51单片机—智能垃圾桶(定时器)

一. 定时器

1. 简介

C51中的定时器和计数器是同一个硬件电路支持的,通过寄存器配置不同,就可以将他当做定时器或者计数器使用。

确切的说,定时器和计数器区别是致使他们背后的计数存储器加1的信号不同。当配置为定时器使用时,每经过1个机器周期,计数存储器的值就加1。而当配置为计数器时,每来一个负跳变信号(信号从P3.4 或者P3.5引脚输入),就加1,以此达到计数的目的。

标准C51有2个定时器/计数器:T0和T1。他们的使用方法一致。C52相比C51多了一个T2

1.1 概念解读
  • 定时器和计数器,电路一样
  • 定时或者计数的本质就是让单片机某个部件数数
  • 当定时器用的时候,靠内部震荡电路数数
  • 当计数器用的时候,数外面的信号,读取针脚的数据

在51单片机中,定时器和计数器的主要区别在于它们的工作方式和用途:

  • 定时器(Timer)
    • 工作方式:定时器使用内部时钟源(例如晶振)进行计数。
    • 用途:用于计时,例如生成精确的时间延迟、实现周期性中断等。
    • 例子:设定一个定时器来每隔一秒触发一次中断,用于更新系统时钟。
  • 计数器(Counter)
    • 工作方式:计数器通过外部信号(例如外部引脚上的脉冲信号)进行计数。
    • 用途:用于计数外部事件或脉冲,例如计数输入脉冲的次数。
    • 例子:连接一个传感器到单片机的计数器引脚,计数传感器发出的脉冲信号。
1.2 定时器怎么定时

定时器的本质原理: 每经过一个机器周期,就加1 :寄存器

思考:

  • 什么是晶振

晶振(晶体震荡器),又称数字电路的“心脏”,是各种电子产品里面必不可少的频率元器件。数字电

路的所有工作都离不开时钟,晶振的好坏、晶振电路设计的好坏,会影响到整个系统的稳

  • 什么是时钟周期

时钟周期也称为振荡周期,定义为时钟频率的倒数。时钟周期是计算机中最基本的、最小的时间单

位。在一个时钟周期内,CPU仅完成一个最基本的动作。时钟周期是一个时间的量。更小的时钟周

期就意味着更高的工作频率

  • 什么是机器周期

机器周期也称为CPU周期。在计算机中,为了便于管理,常把一条指令的执行过程划分为若干个阶

段(如取指、译码、执行等),每一阶段完成一个基本操作。完成一个基本操作所需要的时间称为

机器周期。一般情况下,一个机器周期由若干个时钟周期组成

  • 加1经过了多少时间

当晶振频率是11.0592MHz的时候,等于11059.2KHz = 11059200Hz

跳一次等于一个机器周期

一个机器周期等于12个时钟周期

一个时钟周期等于晶振的倒数:1/11059200秒

那么跳一次就是:12/11059200秒 = 12000000/11059200 微秒= 1.085微妙

机器周期 = 12 x 时钟周期

= 12 x (1/时钟频率) 秒 = 12 / 时钟频率 秒 = 12 / 11059200 秒 = 12 000 000 / 11059200 微秒 = 1.085 微秒

1.3 定时器编程

相关寄存器:

  • 在哪里加1,最大计数时间,也就是爆表了能计算多长

在T8H0/1和TL0/1寄存器中加1,默认是从0开始数数,最多能数65536下,累计计时71ms ,71毫秒

  • 如何算出10ms定时器的初值

就不让他从0开始数数,10ms需要数9216下,你让他从65536-9126=56320(16进制表示为

0xDC00)开始数数

这样TL0=0x00;TH0=0xDC

  • 关于TCON

  • 怎么知道爆表

TCON寄存器的bit5(TF0)能表示爆表:当爆表的时候,硬件会修改bit5(TF0)位上面的数据,改成 1(置1),如果不用中断,我们代码清零。

  • 怎么开始计时

TCON寄存器的bit4,TRO通过编程让这个位为1的时候,开始计时,相当于按下了闹钟

  • 定时器使用是有很多种模式的

定时器模式寄存器:TMOD来选择定时器模式,选择工作方式1,TMOD的bit0 bit1配置成0 1 :16 位的定时器功能

  • 四个二进制数表示一位的16进制数

8421法进制的转换,二进制转16进制(方便人类来看,对计算机底层来说,不关心二进制010101010)。

配寄存器推荐用按位操作,清零的时候,对应的需要清零的位与上0,不需要清零的位与上1

置1的时候,需要置1的位置或1,不需要置一的位置或0

AUXR,降低单片机时钟对外界的辐射。

  • 定时器控制led灯每隔一秒灭一次
#include "reg52.h"sbit led1 = P3^6;   // 定义 led1 变量,指向 P3.6 引脚
sbit led2 = P3^7;   // 定义 led2 变量,指向 P3.7 引脚void main()
{// 1.配置定时器0工作模式为16位计数器模式int cnt = 0;  // 定义一个整数变量 'cnt' 用于计数led1 = 1; // 初始化 led1 为高电平(假设高电平点亮)led2 = 0; // 初始化 led2 为低电平(假设低电平熄灭)TMOD = 0x01; // 配置定时器0为模式1(16位定时器模式)// 2.设置定时器初值,使其每10ms产生一次溢出TL0 = 0x00; // 设置定时器0低8位初值为 0x00TH0 = 0xDC; // 设置定时器0高8位初值为 0xDC// 3.启动计时TR0 = 1;  // 启动定时器0TF0 = 0;  // 清除定时器0溢出标志位while(1) {   // 无限循环if(TF0 == 1) { // 如果定时器0溢出  爆表TF0 = 0; // 清除定时器0溢出标志位cnt++; // 增加计数器 'cnt' 的值// 重新设置定时器初值TL0 = 0x00;   TH0 = 0xDC;if(cnt == 100) { // 如果计数器 'cnt' 达到 100(即经过1秒)cnt = 0; // 重置计数器 'cnt'led1 = !led1; // 翻转 led1 的状态led2 = !led2; // 翻转 led2 的状态}}}
}

1.4 定时器中断方式控制 (相当于多线程)

中断寄存器

  • 定时器中断方式控制led
#include "reg52.h"  // 包含51系列单片机寄存器定义文件sbit led = P3^6;   // 定义一个位变量led,连接到P3端口的第6位(LED1)
sbit led1 = P3^7;  // 定义一个位变量led1,连接到P3端口的第7位(LED2)
int cnt = 0;       // 定义一个整数变量cnt,用来统计定时器溢出的次数// 定义定时器0初始化函数
void Time0Init()
{// 1. 配置定时器0工作模式为16位计时模式TMOD = 0x01;    // 设置TMOD寄存器为0x01,定时器0为16位定时器模式// 2. 设置定时器初值,以生成大约10ms的定时TL0 = 0x00;    // 设置定时器0低8位初值为0x00TH0 = 0xDC;    // 设置定时器0高8位初值为0xDC(即0xDC00)// 3. 启动定时器0TR0 = 1;       // 启动定时器0,使其开始计时TF0 = 0;       // 清除定时器0的溢出标志位(初始为0)// 4. 启用定时器0中断ET0 = 1;       // 使能定时器0中断,使单片机能够响应定时器0的中断请求// 5. 启用总中断EA = 1;        // 启用全局中断,使单片机能够响应所有中断请求
}void main()
{led = 1;       // 将LED1点亮(即将P3^6置为高电平)led1 = 0;      // 将LED2熄灭(即将P3^7置为低电平)Time0Init();   // 调用定时器初始化函数,设置定时器0并启动定时器while(1) {// 无限循环,程序在这里等待中断事件发生// 这部分代码可以执行其他任务,但本例中为空}
}// 定时器0中断处理函数  interrupt 1 定时器0的优先级
void Time0Handler() interrupt 1
{cnt++;        // 每次定时器0溢出时,计数器cnt增加1// 重新设置定时器0的初值,保持定时周期不变TL0 = 0x00;  // 重新加载定时器0低8位初值为0x00TH0 = 0xDC;  // 重新加载定时器0高8位初值为0xDC(即0xDC00)if (cnt == 30) { // 如果定时器0溢出30次(约300ms)cnt = 0;     // 重置计数器cnt为0// 翻转LED的状态led = !led;   // 每300ms翻转LED1的状态led1 = !led1; // 每300ms翻转LED2的状态}
}

这段代码是用来在51系列单片机中配置定时器0,使其每隔1秒钟翻转一个LED的状态。下面是对每一部分的详细解释:

1. 头文件和变量定义
#include "reg52.h"sbit led = P3^6;  // 定义一个位变量led,连接到P3端口的第6位(LED1)
sbit led1 = P3^7; // 定义一个位变量led1,连接到P3端口的第7位(LED2)
int cnt = 0;      // 定义一个整数变量cnt,用来统计定时器溢出次数
  • #include "reg52.h":包含51系列单片机的寄存器定义文件。
  • sbit led = P3^6;:将单片机的P3端口的第6位定义为 led,用于控制LED的开关。
  • sbit led1 = P3^7;:将P3端口的第7位定义为 led1,虽然在代码中没有使用。
  • int cnt = 0;:定义一个计数器 cnt,用于跟踪定时器0的溢出次数。
2. Time0Init 函数
void Time0Init()
{//1. 配置定时器0工作模式位16位计时TMOD = 0x01;//2. 给初值,定一个10ms出来TL0=0x00;TH0=0xDC;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}
  • TMOD = 0x01;:将 TMOD 寄存器的值设置为 0x01,将定时器0配置为模式1(16位定时器模式)。低4位 0001 表示定时器0的工作模式。
  • TL0 = 0x00;TH0 = 0xDC;:设置定时器0的初始值。TH0TL0 设置为 0xDC00,这样定时器从 0xDC00 开始计数。
  • TR0 = 1;:启动定时器0。
  • TF0 = 0;:清除定时器0的溢出标志位。
  • ET0 = 1;:允许定时器0的中断。
  • EA = 1;:允许总中断,使单片机能够响应所有中断请求。
3. main 函数
void main()
{led = 1;     // 初始时点亮LEDTime0Init(); // 初始化定时器0while(1){// 无限循环,等待中断发生}
}
  • led = 1;:在程序开始时,将 led 设为1,点亮LED。
  • Time0Init();:调用初始化定时器0的函数。
  • while(1){}:无限循环,程序在这里等待中断事件发生。实际的操作由中断处理函数完成。
4. 定时器0中断处理函数
void Time0Handler() interrupt 1
{cnt++;  // 统计溢出次数// 重新设置定时器初值TL0=0x00;TH0=0xDC;if(cnt == 100) {  // 每100次溢出表示1秒cnt = 0;     // 重置计数器led = !led;  // 翻转LED状态}
}
  • void Time0Handler() interrupt 1:定义了一个中断服务函数,用于处理定时器0的中断。interrupt 1 表示这是定时器0的中断处理函数。
  • cnt++;:每次定时器0溢出时,计数器 cnt 增加1。
  • TL0 = 0x00;TH0 = 0xDC;:重新加载定时器初值,保持定时器周期不变。
  • if(cnt == 100):检查 cnt 是否达到100。每100次溢出表示1秒(因为10毫秒 × 100 = 1000毫秒,即1秒)。
    • cnt = 0;:重置 cnt 以开始新的计时周期。
    • led = !led;:每秒钟翻转LED的状态。
总结
  • 初始化Time0Init 函数设置定时器0的工作模式和初值,并开启定时器中断。
  • 主程序main 函数设置LED初始状态,并无限循环等待中断。
  • 中断处理Time0Handler 函数在每次定时器0溢出时执行,统计溢出次数,并每1秒翻转一次LED的状态。

  • 定时器中断方式控制led,led灯多线程 控制
#include "reg52.h"// 定义LED控制的位变量
sbit led = P3^6;   // LED1 连接到P3端口的第6位
sbit led1 = P3^7;  // LED2 连接到P3端口的第7位int cnt = 0;       // 用于计数定时器溢出次数的变量// 定时器0初始化函数
void Time0Init()
{// 1. 配置定时器0工作模式为16位计时模式TMOD = 0x01;   // 设置定时器0为16位计时器模式(模式1)// 2. 给定初值,设置一个10ms的定时周期TL0 = 0x00;    // 设置定时器0的低8位初值TH0 = 0xDC;    // 设置定时器0的高8位初值// (0xDC00 是 16位定时器初值,用来生成10ms的定时周期)// 3. 开始计时TR0 = 1;       // 启动定时器0TF0 = 1;       // 设置定时器0的溢出标志位(启动时应清零,但此处设为1可能是为确保中断服务函数能被触发)// 4. 打开定时器0中断ET0 = 1;       // 使能定时器0中断// 5. 打开总中断EAEA = 1;        // 使能总中断,允许所有中断请求
}// 延时函数
void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;i = 3;  // 外循环计数j = 26; // 中循环计数k = 223; // 内循环计数do{do{while (--k);  // 内循环延时} while (--j);  // 中循环延时} while (--i);  // 外循环延时
}// 主函数
void main()
{led = 1;    // 初始化时将LED1点亮led1 = 0;   // 初始化时将LED2熄灭Time0Init(); // 调用定时器0初始化函数while(1) {// 无限循环led1 = 0;       // LED2熄灭Delay300ms();   // 延时300msled1 = 1;       // LED2点亮Delay300ms();   // 延时300ms}
}// 定时器0中断服务函数
void Time0Handler() interrupt 1
{cnt++;      // 每次定时器0溢出时,计数器cnt增加1// 重新给定时器0初值,以保持定时周期TL0 = 0x00; // 重新加载定时器0的低8位初值TH0 = 0xDC; // 重新加载定时器0的高8位初值if(cnt == 30) { // 每30次溢出表示约1秒(10ms * 30 = 300ms)cnt = 0;     // 重置计数器cnt,以开始新的计时周期led = !led;  // 翻转LED1的状态}
}

当然,下面是对你提供的代码的详细解释,逐步解释每一部分的功能和目的:

1. 头文件和变量定义
#include "reg52.h"// 定义LED控制的位变量
sbit led = P3^6;   // LED1 连接到P3端口的第6位
sbit led1 = P3^7;  // LED2 连接到P3端口的第7位int cnt = 0;       // 用于计数定时器溢出次数的变量
  • #include "reg52.h":包括一个头文件,这个文件通常包含对51系列单片机寄存器的定义。
  • sbit led = P3^6;sbit led1 = P3^7;:将 ledled1 分别定义为 P3 端口的第6位和第7位,控制对应的LED灯。sbit 是位变量的定义方式,用于操作单片机的特定位。
  • int cnt = 0;:定义一个全局变量 cnt,用来计数定时器溢出次数。
2. 定时器0初始化函数
void Time0Init()
{// 1. 配置定时器0工作模式为16位计时模式TMOD = 0x01;   // 设置定时器0为16位定时器模式(模式1)// 2. 给定初值,设置一个10ms的定时周期TL0 = 0x00;    // 设置定时器0的低8位初值TH0 = 0xDC;    // 设置定时器0的高8位初值// (0xDC00 是 16位定时器初值,用来生成10ms的定时周期)// 3. 开始计时TR0 = 1;       // 启动定时器0TF0 = 1;       // 设置定时器0的溢出标志位(启动时应清零,但此处设为1可能是为确保中断服务函数能被触发)// 4. 打开定时器0中断ET0 = 1;       // 使能定时器0中断// 5. 打开总中断EAEA = 1;        // 使能总中断,允许所有中断请求
}
  • 配置定时器模式
    • TMOD = 0x01;:设置定时器0为模式1(16位定时器模式)。TMOD 寄存器的低4位设置定时器0的模式,0x01 表示模式1,即16位计时器。
  • 设置定时初值
    • TL0 = 0x00;TH0 = 0xDC;:设置定时器0的低8位(TL0)和高8位(TH0)的初值。这里的初值 0xDC00(16位)用来生成一个10ms的定时周期。具体的10ms周期计算基于单片机的时钟频率(11.0592 MHz)。
  • 启动定时器和中断
    • TR0 = 1;:启动定时器0,开始计时。
    • TF0 = 1;:设置溢出标志位。这通常在定时器启动时应清除,但此处设为1可能是为了确保中断服务函数能被触发。
    • ET0 = 1;:使能定时器0的中断,允许定时器溢出时触发中断。
    • EA = 1;:使能所有中断,允许中断请求的处理。
3. 延时函数
void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;i = 3;  // 外循环计数j = 26; // 中循环计数k = 223; // 内循环计数do{do{while (--k);  // 内循环延时} while (--j);  // 中循环延时} while (--i);  // 外循环延时
}
  • 延时函数
    • Delay300ms() 用来实现一个大约300ms的延时。
    • 使用嵌套的 do-while 循环来耗费时间。外层循环 i 控制循环次数,中层循环 j 和内层循环 k 控制每次循环的延时。具体的延时时间取决于单片机的时钟频率(11.0592 MHz)。
4. 主函数
void main()
{led = 1;    // 初始化时将LED1点亮led1 = 0;   // 初始化时将LED2熄灭Time0Init(); // 调用定时器0初始化函数while(1) {// 无限循环led1 = 0;       // LED2熄灭Delay300ms();   // 延时300msled1 = 1;       // LED2点亮Delay300ms();   // 延时300ms}
}
  • 主函数
    • 初始化时将LED1点亮 (led = 1;),LED2熄灭 (led1 = 0;)。
    • 调用 Time0Init() 初始化定时器0。
    • 进入无限循环,在其中交替点亮和熄灭LED2,每次切换后调用 Delay300ms() 实现300ms的延时。
5. 定时器0中断服务函数
void Time0Handler() interrupt 1
{cnt++;      // 每次定时器0溢出时,计数器cnt增加1// 重新给定时器0初值,以保持定时周期TL0 = 0x00; // 重新加载定时器0的低8位初值TH0 = 0xDC; // 重新加载定时器0的高8位初值if(cnt == 30) { // 每30次溢出表示约1秒(10ms * 30 = 300ms)cnt = 0;     // 重置计数器cnt,以开始新的计时周期led = !led;  // 翻转LED1的状态}
}
  • 定时器0中断服务函数
    • void Time0Handler() interrupt 1:这是定时器0的中断服务函数。interrupt 1 表示它处理定时器0的中断请求。
    • cnt++:每次定时器0溢出时,计数器 cnt 增加1。
    • 重新设置定时器0的初值 (TL0TH0),以保持定时器的计时周期。
    • cnt 达到30时(每30次10ms溢出约300ms),重置 cnt 并翻转LED1的状态。

二、PWM开发SG90

2.1 简介

PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进 行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的 时间占据整个信号周期的百分比,例如方波的占空比就是50%.

  • 脉冲宽度调制
  • 通过占空比编码模拟信号
  • 占空比 一个周期内,高电平占据时长的百分比

4毫秒为一个(波形)周期,其中3ms为低电平,1ms为高电平

什么是占空比 :一个周期内,高电平占据时长的百分比,为25%。

2.2 如何实现PWM信号输出

1. 通过芯片内部模块输出,一般观察手册或者芯片IO口都会标明这个是否是PWM口

如下图增强51,STC15w的

2. 如果没有集成PWM功能,可以通过IO口软件模拟,相对硬件PWM来说精准度略差 ,怎么模拟;

搞个50HZ频率的pwm;

2.3 控制舵机
1. 什么是舵机

如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制

用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等

常见的有0-90°、0-180°、0-360°

2. 怎么控制舵机

向黄色信号线“灌入”PWM信号。

PWM波的频率不能太高,大约50HZ,即周期=1/频率=1/50=0.02s,20ms左右

数据:

0.5ms-------------0度; 2.5% 对应函数中占空比为250

1.0ms------------45度; 5.0% 对应函数中占空比为500

1.5ms------------90度; 7.5% 对应函数中占空比为750

2.0ms-----------135度; 10.0% 对应函数中占空比为1000

2.5ms-----------180度; 12.5% 对应函数中占空比为1250

定时器需要定时20ms, 关心的单位0.5ms, 40个的0.5ms,初值0.5m cnt++

1s = 10ms * 100

20ms = 0.5ms * 40 \

  • 编程实现

#include "reg52.h"sbit sg90_con = P1^1;  // 定义一个名为 sg90_con 的引脚,与 P1 端口的第 1 位连接int jiaodu ;  // 定义一个整数变量 jiaodu,用于表示角度
int cnt = 0;  // 定义一个计数器变量 cnt,用于统计定时器溢出次数// 延时 2000 毫秒函数
void Delay2000ms()		//@11.0592MHz
{unsigned char i, j, k;i = 15;j = 2;k = 235;do{do{while (--k);  // 内层循环,k 减到 0} while (--j);  // 中层循环,j 减到 0} while (--i);  // 外层循环,i 减到 0
}// 定时器0初始化函数
void Time0Init()
{//1. 配置定时器0工作模式为16位计时TMOD = 0x01;//2. 设置初值,定时10msTL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}// 延时 300 毫秒函数
void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;i = 3;j = 26;k = 223;do{do{while (--k);  // 内层循环,k 减到 0} while (--j);  // 中层循环,j 减到 0} while (--i);  // 外层循环,i 减到 0
}void main()
{Delay300ms();  // 让硬件稳定一下Time0Init();  // 初始化定时器jiaodu = 1;   // 初始角度是 0 度,高电平时间为 0.5mscnt = 0;sg90_con = 1;  // 一开始从高电平开始// 每隔两秒切换一次角度while(1){jiaodu = 3;  // 90度,高电平时间为 1.5mscnt = 0;Delay2000ms();jiaodu = 1;  // 0度,高电平时间为 0.5mscnt = 0;Delay2000ms();}
}// 定时器0中断处理函数
void Time0Handler() interrupt 1
{cnt++;  // 统计溢出次数// 重新设置定时器初值TL0=0x33;TH0=0xFE;// 控制PWM波if(cnt < jiaodu){	sg90_con = 1;  // 设置高电平}else{sg90_con = 0;  // 设置低电平} if(cnt == 40){  // 溢出40次,经过20mscnt = 0;  // 重新开始计数sg90_con = 1;  // 开始新的PWM周期,从高电平开始}
}
详细解释
  1. 头文件和变量定义
    • #include "reg52.h":包含51单片机的头文件。
    • sbit sg90_con = P1^1;:定义舵机控制引脚,连接到P1.1。
    • int jiaodu;int cnt = 0;:用于控制舵机角度和计数器的变量。
  1. 延时函数
    • Delay2000ms()Delay300ms():这两个函数通过嵌套的空循环实现延时,用于产生约2000毫秒和300毫秒的延时。
  1. 定时器初始化函数
    • Time0Init():配置定时器0为16位计时模式,设置初始值,启动定时器,并开启定时器中断和全局中断。
  1. 主函数
    • main():主函数初始化定时器,并在一个无限循环中每隔2秒切换舵机的角度。jiaodu 设置为1表示0度,设置为3表示90度。
  1. 定时器中断处理函数
    • Time0Handler():定时器0溢出时调用此函数。每次溢出时计数器 cnt 增加,设置新的初始值,并根据 cntjiaodu 控制舵机信号引脚 sg90_con 的高低电平,从而产生PWM波。
工作原理
  • PWM信号生成
    • 中断处理函数通过计数器 cnt 控制 sg90_con 的高低电平时间,从而生成PWM信号。每个PWM周期为20ms,其中高电平时间由 jiaodu 控制。
  • 舵机控制
    • 主函数通过设置 jiaodu 控制舵机角度,每隔2秒改变一次角度。通过 Delay2000ms() 函数实现延时。
  • 中断处理
    • 每次定时器0溢出时,进入中断处理函数。计数器 cnt 增加,并根据 cnt 的值控制PWM波的高低电平。当 cnt 达到40次溢出时(相当于20ms),重置 cnt 并开始新的PWM周期。

主函数和中断一起执行 ,如果cnt 大于角度的时候,是低电压,中断函数cnt继续加加,直到加到等于40的时候,这个周期结束,进入下一个周期,

三、 超声波测距

3.1 简介

型号:HC-SR04

接线参考:模块除了两个电源引脚外,还有TRIG,ECHO引脚,这两个引脚分别接我们开发板的P1.5和

P1.6端口

超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离。

  • 怎么让它发送波

Trig ,给Trig端口至少10us的高电平

  • 怎么知道它开始发了

Echo信号,由低电平跳转到高电平,表示开始发送波

  • 怎么知道接收了返回波

Echo,由高电平跳转回低电平,表示波回来了

  • 怎么算时间

Echo引脚维持高电平的时间!

波发出去的那一下,开始启动定时器

波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间

  • 怎么算距离

距离 = 速度 (340m/s)* 时间/2

3.2 超声波的时序图

3.3 超声波测距代码实现
#include "reg52.h"//距离小于10cm ,D5 亮,6灭,反之想反sbit D5 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口sbit Trig = P1^5;   // 发送声波
sbit Echo = P1^6;   // 接收声波void Delay10us()		//@11.0592MHz  //声波的持续时间   10微妙  
{unsigned char i;i = 2;while (--i);
}
/*
十进制2左移1位,变成20。相当于乘以10
二禁止1左移1位,变成10(2)。相当于乘以2,左移8位,乘以2的8次方=256;*/
void startHC()   //Trig  输出10ms的高电平 启动发波
{Trig = 0;    //发声波 低电压 Trig = 1;    //发声波 高电压 维持10秒Delay10us();Trig = 0;  //发声波 低电压 }//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器void Time0Init()   //不用关心初值  定时器
{TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x01;		//设置定时器模式TH0 = 0;    //16进制计时TL0 = 0;// 设置定时器-0工作模块1.初值为0,不着急启动定时器、}
double get_distance()
{double time;//定时器数据清零,以便下一次测距TH1 = 0;TL1 = 0;startHC(); //调用超声波函数,启动发波;while(Echo == 0);   // 当接收端由低电压转换至高电压时,循环结束 表示声波发出//	启动定时器TR0 = 1;   // 开始计时//		3、Echo,由高电平跳转回低电平,表示波回来了 //	 停止计时while(Echo == 1);  // 当接收端由高电压转换至低电压时,循环结束,表示声波返回TR0 = 0;  // 停止计时//4. 计算出中间经过多少时间 (公式)time = (TH0 * 256 + TL0)*1.085;//us为单位//5. 距离 = 速度 (340m/s)* 时间/2dis = time * 0.017;double dis;  //返回一个数值
}
void openStatusLight()   // 开启状态灯
{D5 = 0;D6 = 1;
}
void closeStatusLight()  // 关闭状态灯
{D5 = 1;D6 = 0;
}
void main()
{double dis;   // 距离Time0Init();   //初始化定时器while(1){dis = get_distance();  // 计算距离// 判断距离是否小于10cmif(dis < 10){   // 如果小于10cm  openStatusLight();  // 调用开启函数}else{     // 否则。其他情况closeStatusLight();     // 调用关闭函数}}
}

四、本节项目感应开关盖垃圾桶

4.1 项目概述
  • 功能描述
      • 检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
      • 发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
      • 按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
  • 硬件说明
      • SG90舵机,超声波模块,震动传感器,蜂鸣器
  • 接线说明

舵机控制口 P1.1;超声波Trig接 P1.5 ,Echo接 P1.6 ;蜂鸣器接 P2.0 口; 震动传感器接 P3.2`口(外部 中断0)

4.2 编程实现
  • 开发步骤:

1. 舵机和超声波代码整合

    • 舵机用定时器0
    • 超声波用定时器1
    • 实现物体靠近后,自动开盖,2秒后关盖

2. 查询的方式添加按键控制

3. 查询的方式添加震动控制

4. 使用外部中断0配合震动控制

代码:

#include "reg52.h"sbit sg90_con = P1^1;
sbit D5 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口sbit Trig = P1^5;
sbit Echo = P1^6;int jiaodu ;  // 舵机的角度
int cnt = 0;  //爆表的累计次数void Delay2000ms()		//@11.0592MHz  // 延迟2秒
{unsigned char i, j, k;i = 15;j = 2;k = 235;do{do{while (--k);} while (--j);} while (--i);
}void Delay10us()		//@11.0592MHz 
{unsigned char i;i = 2;while (--i);
}void startHC()   //Trig  输出10ms的高电平 启动发波
{Trig = 0;Trig = 1;Delay10us();Trig = 0;}
void Time0Init1()  // 初始化定时器0,用于舵机控制
{//1. 配置定时器0工作模式位16位计时TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x01;//2. 给初值,定一个10ms出来TL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}void Time0Init2()   // 初始化定时器1,用于超声波控制
{TMOD &= 0x0F;		//设置定时器模式TMOD |= 0x10;		//设置定时器模式TH1 = 0;TL1 = 0;// 设置定时器-0工作模块1.初值为0,不着急启动定时器、}
void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;i = 3;j = 26;k = 223;do{do{while (--k);} while (--j);} while (--i);
}void initSG90_0()
{jiaodu = 1;      //初始角度是0度,0.5ms,溢出1就是0.5,高电平cnt = 0;sg90_con = 1;		//一开始从高电平开始
}
double  get_distance()
{double time;double dis;//定时器数据清零,以便下一次测距TH1 = 0;TL1 = 0;//1. Trig ,给Trig端口至少10us的高电平startHC();// 2、Echo信号,由低电平跳转到高电平,表示开始发送波//		波发出去的那一下,开始启动定时器while(Echo == 0);//	启动定时器TR1 = 1;//		3、Echo,由高电平跳转回低电平,表示波回来了 //	 停止计时while(Echo == 1);TR1 = 0;//4. 计算出中间经过多少时间time = (TH1 * 256 + TL1)*1.085;//us为单位//5. 距离 = 速度 (340m/s)* 时间/2dis = time * 0.017;return dis;
}
void openStatusLight() {D5 = 0;  // 点亮D5D6 = 1;  // 熄灭D6
}void closeStatusLight() {D5 = 1;  // 熄灭D5D6 = 0;  // 点亮D6
}void openlajitong() {jiaodu = 3;  // 90度,1.5ms高电平cnt = 0;Delay2000ms();
}void closelajitong() {jiaodu = 1;  // 0度,0.5ms高电平cnt = 0;Delay2000ms();
}
void main()
{double dis;Delay300ms(); 	//  让硬件稳定一下Time0Init1();  	//  初始化定时器1Time0Init2();	//  初始化定时器2initSG90_0();   //  初始化舵机的角度// 每隔两秒切换一次角度while(1){dis = get_distance();   // 计算距离if(dis < 10){        // 判断距离  //  如果距离小于10 调用开启函数openStatusLight();    //openlajitong();}else{                 //  如果距离大于10 调用关闭函数closeStatusLight();closelajitong();}}
}
void Time0Handler() interrupt 1  // 定时器中断
{cnt++;  //统计爆表的次数,cnt = 1的时候,报表了1//重新给初值TL0=0x33;TH0=0xFE;// 控制PWM波if(cnt < jiaodu){	sg90_con = 1 ;}else{sg90_con = 0 ;} if(cnt == 40){//爆表40次,经过了20mscnt = 0;  //当100次表示1s,重新让cnt从0开始,计算下一次的1ssg90_con = 1 ;}}
  • 测距开关盖添加按键开盖功能
    • 51单片机KY1 按键
    • 遥控发送接收433M
      • https://wenku.baidu.com/view/8fe8f444bed5b9f3f80f1c33.html
      • 默认低电平,按键之后是高电平。
      • 遥控控制开关
#include "reg52.h"// 定义各个IO口
sbit D5       = P3^7;      // LED D5连接到P3.7口
sbit D6       = P3^6;      // LED D6连接到P3.6口
sbit SW1      = P2^1;      // 开关 SW1连接到P2.1口
sbit Trig     = P1^5;      // 超声波传感器Trig引脚连接到P1.5口
sbit Echo     = P1^6;      // 超声波传感器Echo引脚连接到P1.6口
sbit sg90_con = P1^1;      // SG90舵机控制引脚连接到P1.1口
sbit D0_ON    = P1^2;      // LED D0_ON连接到P1.2口
sbit D1_OFF   = P1^3;      // LED D1_OFF连接到P1.3口int jiaodu ;  // 舵机的角度
int cnt = 0;  //爆表的累计次数void Delay2000ms()		//@11.0592MHz  // 延迟2秒
{unsigned char i, j, k;i = 15;j = 2;k = 235;do{do{while (--k);} while (--j);} while (--i);
}
void Delay10us()		//@11.0592MHz 
{unsigned char i;i = 2;while (--i);
}
void startHC()   //Trig  输出10ms的高电平 启动发波
{Trig = 0;Trig = 1;Delay10us();Trig = 0;}
void Time0Init1()  // 初始化定时器0,用于舵机控制
{//1. 配置定时器0工作模式位16位计时TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x01;//2. 给初值,定一个10ms出来TL0=0x33;TH0=0xFE;//3. 开始计时TR0 = 1;TF0 = 0;//4. 打开定时器0中断ET0 = 1;//5. 打开总中断EAEA = 1;
}
void Time0Init2()   // 初始化定时器1,用于超声波控制
{TMOD &= 0x0F;		//设置定时器模式TMOD |= 0x10;		//设置定时器模式TH1 = 0;TL1 = 0;// 设置定时器-0工作模块1.初值为0,不着急启动定时器、}
void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;i = 3;j = 26;k = 223;do{do{while (--k);} while (--j);} while (--i);
}
void initSG90_0()
{jiaodu = 1;      //初始角度是0度,0.5ms,溢出1就是0.5,高电平cnt = 0;sg90_con = 1;		//一开始从高电平开始
}
double  get_distance()
{double time;double dis;//定时器数据清零,以便下一次测距TH1 = 0;TL1 = 0;//1. Trig ,给Trig端口至少10us的高电平startHC();// 2、Echo信号,由低电平跳转到高电平,表示开始发送波//		波发出去的那一下,开始启动定时器while(Echo == 0);//	启动定时器TR1 = 1;//		3、Echo,由高电平跳转回低电平,表示波回来了 //	 停止计时while(Echo == 1);TR1 = 0;//4. 计算出中间经过多少时间time = (TH1 * 256 + TL1)*1.085;//us为单位//5. 距离 = 速度 (340m/s)* 时间/2dis = time * 0.017;return dis;
}
void openStatusLight() {D5 = 0;  // 点亮D5D6 = 1;  // 熄灭D6
}
void closeStatusLight() {D5 = 1;  // 熄灭D5D6 = 0;  // 点亮D6
}
void openlajitong() {jiaodu = 3;  // 90度,1.5ms高电平cnt = 0;Delay2000ms();
}
void closelajitong() {jiaodu = 1;  // 0度,0.5ms高电平cnt = 0;Delay2000ms();
}
void main()
{double dis;Delay300ms(); 	//  让硬件稳定一下Time0Init1();  	//  初始化定时器1Time0Init2();	//  初始化定时器2initSG90_0();   //  初始化舵机的角度// 每隔两秒切换一次角度while(1){dis = get_distance();   // 计算距离if(dis < 10 || SW1 == 0 || D0_ON == 1){openStatusLight();openDusbin();}else if (D1_OFF == 1){//关盖,灯状态,D5灭closeStatusLight();closeDusbin();}else{closeStatusLight();closeDusbin();}}
}
void Time0Handler() interrupt 1  // 定时器中断
{cnt++;  //统计爆表的次数,cnt = 1的时候,报表了1//重新给初值TL0=0x33;TH0=0xFE;// 控制PWM波if(cnt < jiaodu){	sg90_con = 1 ;}else{sg90_con = 0 ;} if(cnt == 40){//爆表40次,经过了20mscnt = 0;  //当100次表示1s,重新让cnt从0开始,计算下一次的1ssg90_con = 1 ;}	
}
  • 测距开关盖添加振动传感器开盖功能
#include "reg52.h"// 定义各个IO口
sbit D5       = P3^7;      // LED D5连接到P3.7口
sbit D6       = P3^6;      // LED D6连接到P3.6口
sbit SW1      = P2^1;      // 开关 SW1连接到P2.1口
sbit Trig     = P1^5;      // 超声波传感器Trig引脚连接到P1.5口
sbit Echo     = P1^6;      // 超声波传感器Echo引脚连接到P1.6口
sbit sg90_con = P1^1;      // SG90舵机控制引脚连接到P1.1口
sbit D0_ON    = P1^2;      // LED D0_ON连接到P1.2口
sbit D1_OFF   = P1^3;      // LED D1_OFF连接到P1.3口
sbit vibrate  = P3^2;      // 振动传感器连接到P3.2口
sbit beep     = P2^0;char jiaodu;  // 舵机的角度变量
char jd_bak;
char cnt = 0;// 定时器溢出次数累计变量
char mark_vibrate = 0;// 延迟2秒
void Delay2000ms()		//@11.0592MHz
{unsigned char i, j, k;i = 15;j = 2;k = 235;do {do {while (--k);} while (--j);} while (--i);
}// 延迟10微秒
void Delay10us()		//@11.0592MHz 
{unsigned char i;i = 2;while (--i);
}// Trig输出10微秒的高电平以启动超声波传感器
void startHC()
{Trig = 0;Trig = 1;Delay10us();Trig = 0;
}// 初始化定时器0,用于舵机控制
void Time0Init1()
{TMOD &= 0xF0;		// 设置定时器模式TMOD |= 0x01;		// 配置定时器0工作模式为16位计数TL0 = 0x33;			// 定时器初值TH0 = 0xFE;			// 定时器初值TR0 = 1;			// 开始计时TF0 = 0;			// 清除定时器溢出标志ET0 = 1;			// 打开定时器0中断EA = 1;				// 打开总中断
}// 初始化定时器1,用于超声波控制
void Time0Init2()
{TMOD &= 0x0F;		// 设置定时器模式TMOD |= 0x10;		// 配置定时器1工作模式为16位计数TH1 = 0;			// 定时器1初值TL1 = 0;			// 定时器1初值
}// 延迟300毫秒
void Delay300ms()		//@11.0592MHz
{unsigned char i, j, k;i = 3;j = 26;k = 223;do {do {while (--k);} while (--j);} while (--i);
}// 初始化舵机角度为0度(0.5ms高电平)
void initSG90_0()
{jiaodu = 1;      // 初始角度是0度cnt = 0;sg90_con = 1;	 // 一开始从高电平开始
}// 获取距离
double get_distance()
{double time;double dis;TH1 = 0;  // 定时器1数据清零TL1 = 0;startHC();  // 启动超声波传感器while(Echo == 0);  // 等待Echo信号变高TR1 = 1;  // 启动定时器1while(Echo == 1);  // 等待Echo信号变低TR1 = 0;  // 停止定时器1time = (TH1 * 256 + TL1) * 1.085;  // 计算时间,单位为微秒dis = time * 0.017;  // 计算距离,单位为厘米return dis;
}// 打开状态灯
void openStatusLight() {D5 = 0;  // 点亮D5D6 = 1;  // 熄灭D6
}// 关闭状态灯
void closeStatusLight() {D5 = 1;  // 熄灭D5D6 = 0;  // 点亮D6
}// 打开垃圾桶
void openlajitong() {char n;jiaodu = 3; //90度 1.5ms高电平//舵机开盖if(jd_bak != jiaodu){cnt = 0;beep = 0;for(n=0;n<2;n++)Delay150ms();beep = 1;Delay2000ms();}jd_bak = jiaodu;}// 关闭垃圾桶
void closelajitong() {char n;//关盖for(n=0;n<2;n++)Delay150ms();jd = 1; //0度jd_bak = jd;cnt = 0;Delay150ms();
}
void EX0_Init()
{//打开外部中断EX0 = 1;//低电平触发IT0 = 0;
}
// 主函数
void main()
{double dis;Delay300ms(); 	// 让硬件稳定一下Time0Init1();  	// 初始化定时器0Time0Init2();	// 初始化定时器1EX0_Init();initSG90_0();   // 初始化舵机角度while(1) {dis = get_distance();  // 获取距离if(dis < 10 || SW1 == 0 || D0_ON == 1 ||  mark_vibrate == 1 ) {  // 距离小于10cm或SW1按下或D0_ON为高电平openStatusLight();openlajitong();} else if (D1_OFF == 1) {  // D1_OFF为高电平closeStatusLight();closelajitong();} else {  // 其他情况closeStatusLight();closelajitong();}}
}// 定时器中断处理函数
void Time0Handler() interrupt 1
{cnt++;  // 累计定时器溢出次数TL0 = 0x33;  // 重新设置定时器初值TH0 = 0xFE;if(cnt < jiaodu) {sg90_con = 1;  // 输出高电平} else {sg90_con = 0;  // 输出低电平}if(cnt == 40) {  // 溢出40次,经过20mscnt = 0;  // 重置计数sg90_con = 1;}}void Ex0_Handler() interrupt 0   //			振动传感器输出低电平 中断
{mark_vibrate = 1;          
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/395181.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构的基本概念

数据结构的基本概念 数据是什么&#xff1f; 数据 &#xff1a; 数据是信息的载体&#xff0c;是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别&#xff08;二进制0|1&#xff09;和处理的符号的集合。数据是计算机程序加工的原料。 早期计算机处理的…

【代码随想录】有序数组的平方

本博文为《代码随想录》的学习笔记&#xff0c;原文链接&#xff1a;代码随想录 题目 977. 有序数组的平方 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&…

【物联网设备端开发】使用QEMU模拟ESP硬件运行ESP-IDF

目录 一&#xff0c;开发环境搭建 1.1 安装ESP-IDF 1.2 安装vscode插件 1.3 在ESP-IDF插件配置ESP-IDF开发配置 1.4 下载IOTDeviceSDK 设备端开发代码 1.5 通过ESP-IDF插件编译好镜像 1.6 构建QEMU docker镜像 1.7 使用QEMU容器运行镜像 二&#xff0c;搭建QEMU环境步…

PTrade常见问题系列22

反馈定义的上午7点执行run_daily函数&#xff0c;但是每周一上午都没法正常执行&#xff1f; 1、run_daily函数加载在initialize函数中&#xff0c;执行后才会创建定时任务&#xff1b; 2、由于周末会有例行重启操作&#xff0c;在重启以后拉起交易时相当于非交易日启动的交易…

C到C++——C++基础

C是一种通用的、静态类型的、跨平台的编程语言。它是在1979年由Bjarne Stroustrup创建的&#xff0c;最初是作为C语言的扩展来支持面向对象编程。 C在保留C语言的特性的同时&#xff0c;添加了许多其他的功能&#xff0c;包括类、对象、继承、多态、模板等。这使得C成为了一种…

大数据面试SQL(五):查询最近一笔有效订单

文章目录 查询最近一笔有效订单 一、题目 二、分析 三、SQL实战 四、样例数据参考 查询最近一笔有效订单 一、题目 现有订单表t5_order&#xff0c;包含订单ID&#xff0c;订单时间&#xff0c;下单用户&#xff0c;当前订单是否有效。 请查询出每笔订单的上一笔有效订…

Vue - 关于vue-kinesis 移动动画组件

Vue - 关于vue-kinesis 移动动画组件 vue-kinesis可以根据鼠标移动或滚动条来控制元素动画的动画效果&#xff1b;除此之外&#xff0c;vue-kinesis 还可以设置音频文件&#xff0c;根据音频频率来控制动画的跳动效果。 一、安装vue-kinesis Vue2版本&#xff1a; 1.安装 …

2024.8.08(python)

一、搭建python环境 1、检查是否安装python [rootpython ~]# yum list installed | grep python [rootpython ~]# yum list | grep python3 2、安装python3 [rootpython ~]# yum -y install python3 安装3.12可以使用源码安装 3、查看版本信息 [rootpython ~]# python3 --vers…

数字信号处理2: 离散信号与系统的频谱分析

文章目录 前言一、实验目的二、实验设备三、实验内容四、实验原理五、实验步骤1.序列的离散傅里叶变换及分析2.利用共轭对称性&#xff0c;设计高效算法计算2个N点实序列的DFT。3.线性卷积及循环卷积的实现及二者关系分析4.比较DFT和FFT的运算时间5.利用FFT求信号频谱及分析采样…

游戏行业最新报告 | 2024年1—6月:中国游戏市场收入上升至1472.67亿元

2024年1—6月收入&#xff1a;达1472.67亿元&#xff0c;同比增长2.08% 伽马数据提供的数据显示&#xff1a;2024年1—6月&#xff0c;国内游戏市场实际销售收入1472.67亿元&#xff0c;同比增长2.08%&#xff0c;增长趋势较为平稳。 中国市场实际销售收入及增长率 游戏用户达…

(24)(24.2) Minim OSD快速安装指南(一)

文章目录 前言 1 概述 2 基本接线图 3 关键冷却条件的可选设置 4 固件可用于MinimOSD 5 MWOSD 前言 MinimOSD “屏幕显示”是一个小型电路板&#xff0c;它从你的自动驾驶仪中提取遥测数据&#xff0c;并将其覆盖在你的第一人称视图监视器上(First Person View)。Minim …

极限挑战:40亿个非负整数中找到没有出现的数(bit数组)

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好!我是小米,一个积极活泼、热爱分享技术的29岁程序员。今天,我们一起来探讨一个有趣且实用的算法问题:如何在40亿个非负整数中找到没有出现的数…

Powershell 禁用系统更新

创建一个关闭系统更新脚本 脚本系统兼容10,11,2012,206,2019,2022,2025powershell-install-stop-System-update.ps1 <# Powershell Install stop System update +++++++++++++++++++++++++++++++++++++++++++++++++++++ + _____ _____ _ …

供应商较多的汽车制造业如何选择供应商协同平台?

汽车制造业的供应商种类繁多&#xff0c;根据供应链的不同环节和产品特性&#xff0c;可以大致分为以下几类。 按供应链等级分包括&#xff1a; 一级供应商通常具有较高的技术水平和生产能力&#xff0c;能够满足汽车厂商对零部件的高品质、高性能和高可靠性的要求。 二级供应…

ImportError: DLL load failed while importing _rust: 找不到指定的程序的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【Android Studio】Webview 内核升级得三种方法

【Android Studio】Webview 内核升级得三种方法 前言X5 腾讯组件crosswalk开源项目webview升级加载的内核&#xff08;完美解决&#xff09;总结 前言 在APP 中进行网页加载&#xff0c;一般采用原生自带的Webview 组件&#xff0c;但在需要加载高版本网页的时候&#xff0c;有…

【CSS入门】第三课 - padding内填充

上一节&#xff0c;我们说了margin外边距&#xff0c;还举了个例子&#xff0c;比如两个人紧挨着站着&#xff0c;如果两个人冬天穿了棉袄&#xff0c;很厚很厚的棉袄&#xff0c;那么他俩占据的空间就会增加&#xff0c;他俩之间的真实距离也会增加。 这一节&#xff0c;我们…

《暗黑破坏神 IV》是什么类型的游戏,苹果电脑能玩暗黑破坏神吗 crossover玩暗黑4

《暗黑破坏神 IV》&#xff08;Diablo IV&#xff09;是由暴雪娱乐开发的一款动作角色扮演游戏&#xff08;Action RPG&#xff09;&#xff0c;是广受欢迎的《暗黑破坏神》系列的最新作品。暗黑破坏神4拥有出色的游戏画面、音效和丰富的游戏玩法&#xff0c;非常值得玩家们去尝…

SpringBoot3热部署

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional> </dependency> 默认就是,无需配置 可以了…

ADB Installer 0 file(s)copied

在为泡面神器刷安卓&#xff0c;做准备工作装ADB时报错了&#xff0c;以下是报错提示 再用cmd命令adb version验证下&#xff0c;提示adb不是有效命令&#xff0c;百分百安装失败了&#xff0c;往上各种搜索查询均没有对症的&#xff0c;其中也尝试了安装更新版本的&#xff0c…