本篇博文介绍的是用51单片机制作感应开关盖垃圾桶【下】,里面包含sg90舵机基本认知,定时中断方式控制LED灯,舵机实战编程,超声波测距传感器认知,从零编程实现超声波测距(当距离小于10厘米,D5亮,D6灭。当距离大于10厘米,D5灭,D6亮。),感应开关盖垃圾桶需求设计,垃圾桶01
修改超声波为定过器一控制,垃圾桶02
封装超声波测距代码,垃圾桶03
实现距离感应开盖,垃圾桶04
添加按键开盖功能,垃圾桶05
添加震动开盖功能使用外部中断优化,垃圾桶06
添加开盖滴滴声_项目完结,垃圾桶的抽抽BUG解决。看到这篇博文的朋友,可以先赞再看吗?
一、数学周期,频率等相关知识。
二、数学对于时间的计算。
三、数学对于波形的理解能力
四、数字电子中与或运算
五、计算机中的进制转换
六、C变量
七、基本输入输出
八、流程控制
九、函数
如果以上知识不清楚,请自行学习后再来浏览。
如下图所示,最便宜的舵机sg90
,常用三根或者四根接线
,黄色
为PWM信号线。起控制舵机转动角度作用。控制角度的用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等常见的有0-90°
、0-180°
、0-360°
。
一、向黄色信号线“灌入”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.5ms
记录爆表次数变量cnt++
1s
= 10ms * 100
20ms
= 0.5ms * 40
一、在定时器T0初始化函数中分别打开定时器T0中断ET0
和总中断EA。
void initTime0()
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时10毫秒
TL0 = 0x00;
TH0 = 0xDC;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
二、利用定时器T0溢出标志TF0
的中断,建立中断函数,设置中断号
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
三、在中断函数中设置记录爆表次数变量cnt
自增,重新给定时器赋初值,定时10毫秒
,以及判断是否加到100
,定时1
秒,进行led
的状态翻转
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时10毫秒
TL0 = 0x00;
TH0 = 0xDC;
//判断cnt是否加到100,定时是否1秒
if(cnt == 100)
{
cnt = 0; //定时到1秒,cnt从0开始加
led = !led; //定时到1秒,led灯状态翻转
}
}
四、在主函数中的while
死循环中对另一颗灯进行软件延时闪烁
void main()
{
led = 1; //给led一个高电平,灯灭。
initTime0();
//4.爆表了,不操作灯,累计1秒才操作。
//爆表了,变量加一,加了100次等于计时1秒
while(1)
{
led2 = 1;
Delay300ms();
led2 = 0;
Delay300ms();
}
}
#include "reg52.h"
/*
时间: 2023年10月3日13:31:57
程序功能:定时中断方式控制LED灯
*/
sbit led = P3^7;
sbit led2 = P3^6;
int cnt = 0; //记录爆表次数
void initTime0()
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时10毫秒
TL0 = 0x00;
TH0 = 0xDC;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 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; //给led一个高电平,灯灭。
initTime0();
//4.爆表了,不操作灯,累计1秒才操作。
//爆表了,变量加一,加了100次等于计时1秒
while(1)
{
led2 = 1;
Delay300ms();
led2 = 0;
Delay300ms();
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时10毫秒
TL0 = 0x00;
TH0 = 0xDC;
//判断cnt是否加到100,定时是否1秒
if(cnt == 100)
{
cnt = 0; //定时到1秒,cnt从0开始加
led = !led; //定时到1秒,led灯状态翻转
}
}
一、设计定时器初值为0.5
毫秒,也就是从数数开始到溢出经过0.5毫秒
。
计算过程
已知一个机器周期等于1.085
微妙
定时0.5
毫秒 = 500微妙
。
机器周期 = 500/1.085
= 461
;
已知16
位定时器为65536
个机器周期
设置初值= 65536-461
=65075
= 0xFE33(
16进制)
高位TH0
= 0xFE
;
低位TL0
= 0x33
;
二、分别定义角度,记录爆表的全局变量。设置sg90
舵机的控制线端口为P3.2口
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
sbit sg90_con = P3^2; //sg90舵机PWM控制线接单片机P3.2口,用于模拟PWM波形。
三、修改定时器T0
的初始化函数,将定时器初值修改为计算的值。
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
四、在中断函数中设置记录爆表次数变量cnt
自增。重新给定时器赋初值,定时0.5
毫秒。判读记录爆表变量cnt
的值是否小于角度变量的值,小于继续给sg90
舵机控制线接高电平,大于等于则给低电平;使之呈现PWM波形
。判断cnt
是否加到40
,定时是否20
毫秒PWM
波形周期。
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 20)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
五、在主函数中单片机上电,给sg90
舵机控制线一个高电平。给角度控制变量初始化为0
度,因为0.5
毫秒的高电平PWM
波为0
度,angle = 1;
时定时器刚好定时0.5
毫秒每隔2
秒软件延时切换舵机角度,1为0度
,3为90度
,因为舵机为齿轮结构,角度会有偏差。
void main()
{
Delay300ms(); //因为用软件模拟的PWM有误差,所以让硬件等待300毫秒稳定一下。
initTime0();
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
while(1) //每隔2秒软件延时切换舵机角度,1为0度,3为90度,因为舵机为齿轮结构,角度会有偏差
{
angle = 3;
cnt = 0;
Delay2000ms();
angle = 1;
cnt = 0;
Delay2000ms();
}
}
#include "reg52.h"
/*
时间: 2023年10月3日14:52:24
程序功能:舵机实战编程
*/
sbit sg90_con = P3^2; //sg90舵机PWM控制线接单片机P3.2口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
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 Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
Delay300ms(); //因为用软件模拟的PWM有误差,所以让硬件等待300毫秒稳定一下。
initTime0();
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
while(1) //每隔2秒软件延时切换舵机角度,1为0度,3为90度,因为舵机为齿轮结构,角度会有偏差
{
angle = 3;
cnt = 0;
Delay2000ms();
cnt = 0;
angle = 1;
Delay2000ms();
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 20)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
1、典型工作用电压:5V
。
2、超小静态工作电流:小于 2mA
。
3、感应角度:不大于15
度 。
4、探测距离:2cm-400cm
5、高精度:可达 0.3cm
。
6、盲区(2cm
)超近。
7、完全谦容 GH-311
防盗模块。
8、带金属 USB
外壳,坚固耐用。
Vcc
、 Trig
(控制端)、 Echo
(接收端)、 Gnd
控制口发一个 10us
以上的高电平,就可以在接收口等待高电平
输出.一有输出就可以开定时器计时
,当此口变为低电平时
就可以读取定时器
的值,此时就为此次测距的时间
,方可算出距离
.如此不断的周期测,就可以达到你移动测量的值了。
(1)采用 IO
触发测距,给至少 10us
的高电平信号;
(2)模块自动发送 8
个 40khz
的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO
输出一高电平,高电平持续的时间就是
(4)超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
1:此模块不宜带电连接,如果要带电连接,则先让模块的 Gnd
端先连接。否则会影响模块工作。
2:测距时,被测物体的面积不少于 0.5
平方米且要尽量平整。否则会影响测试结果。
型号:HC-SR04
接线参考:模块除了两个电源引脚外,还有TRIG
,ECHO
引脚,这两个引脚分别接我开发板的P1.5
和P1.6
端口
超声波测距模块是用来测量距离
的一种产品,通过发送
和接收
超声波,利用时间差和声音传播速度,计算出模块到前方障碍物的距离。
Trig
,给Trig
端口至少10us
的高电平。
Echo
信号,由低电平
跳转到高电平
,表示开始发送
波。
Echo
,由高电平
跳转回低电平
,表示波回来
了。
Echo
引脚维持高电平的时间!
波发出
去的那一下,开始
启动定时器
波回来
的那一下,我们开始
停止定时器,计算出中间经过
多少时间
距离
= 速度 (340m/s)* 时间/2
一、软件延时10us
函数
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
二、触发信息函数
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
三、主函数调用触发函数 startHC();
一、
while(Echo == 0); //等待发送波
二、波发出去的那一下,开始启动定时器
定时器T0初始化函数
void time0Init() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0xF0;
TMOD |= 0x01;
TL0 = 0;
TH0 = 0;
}
定时器T0启动
TR0 = 1; //启动定时器T0
一、
while(Echo == 1); //等待波回来
二、波回来的那一下,我们开始停止定时器
TR0 = 0; //关闭定时器
三、计算出中间经过多少时间
time = ((TH0 * 256) + TL0)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
dis = 340m/s
= 34000cm/s
= 34cm/ms
= 0.034cm/us
dis = 0.034 * time/2;
<==> 0.017*time;
dis = 0.017*time;
if(dis < 10)
{
D5 = 0;
D6 = 1;
}
else
{
D5 = 1;
D6 = 0;
}
重新给初值,重新计时
TL0 = 0;
TH0 = 0;
#include "reg52.h"
/*
时间: 2023年10月3日19:22:25
程序功能:从零编程实现超声波测距,
当距离小于10厘米,D5亮,D6灭。
当距离大于10厘米,D5灭,D6亮。
*/
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void time0Init() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0xF0;
TMOD |= 0x01;
TL0 = 0;
TH0 = 0;
}
void main()
{
double time;
double dis;
time0Init();
while(1)
{
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0); //等待发送波
// 波发出去的那一下,开始启动定时器
TR0 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1); //等待波回来
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR0 = 0; //关闭定时器
time = ((TH0 * 256) + TL0)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
dis = 0.017*time;
//判断距离小于10厘米,D5亮,D6灭。
//判断距离大于10厘米,D5灭,D6亮。
if(dis < 10)
{
D5 = 0;
D6 = 1;
}
else
{
D5 = 1;
D6 = 0;
}
//重新给初值,重新计时
TL0 = 0;
TH0 = 0;
}
}
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
SG90舵机
,超声波模块
,震动传感器
,蜂鸣器
舵机控制口 P1.1
超声波Trig接 P1.5
Echo接 P1.6
蜂鸣器接 P2.0 口
震动传感器接 P3.2口(外部中断0)
01
修改超声波为定过器一控制0
超声波用定时器1
T0
为T1
TMOD &= 0xF0
修改为 TMOD &= 0x0F
TMOD |= 0x01
修改为 TMOD &= 0x10
所有的TL0
修改为TL1
所有的TH0
修改为TH1
所有的TR0
修改为TR1
time0Init()
修改为 time1Init()
#include "reg52.h"
/*
时间: 2023年10月3日19:22:25
程序功能:从零编程实现超声波测距,
当距离小于10厘米,D5亮,D6灭。
当距离大于10厘米,D5灭,D6亮。
*/
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void time1Init() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
void main()
{
double time;
double dis;
time1Init();
while(1)
{
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
dis = 0.017*time;
if(dis < 10)
{
D5 = 0;
D6 = 1;
}
else
{
D5 = 1;
D6 = 0;
}
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
}
}
02
封装超声波测距代码double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017*time);
}
void opencCoverLight()
{
D5 = 0;
D6 = 1;
}
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
#include "reg52.h"
/*
时间: 2023年10月3日19:22:25
程序功能:从零编程实现超声波测距,
当距离小于10厘米,D5亮,D6灭。
当距离大于10厘米,D5灭,D6亮。
*/
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void time1Init() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017*time);
}
void opencCoverLight()
{
D5 = 0;
D6 = 1;
}
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
void main()
{
double dis;
time1Init();
while(1)
{
dis = getDistance();
if(dis < 10)
{
opencCoverLight();
}
else
{
closeCoverLight();
}
}
}
03
实现距离感应开盖sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
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 Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
void initSG90_0() //SG90舵机初始化函数。
{
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
cnt = 0; //初始化爆表变量
}
void openCoverDustbin() //垃圾桶开盖函数
{
angle = 3; //舵机开盖
cnt = 0;
Delay2000ms();
}
void closeCoverDustbin()//垃圾桶关盖函数
{
angle = 1; //舵机关盖
cnt = 0;
Delay150ms();
}
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10)
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
#include "reg52.h"
/*
时间: 2023年10月4日14:00:24
程序功能:垃圾桶03实现距离感应开盖
注意:一定要在魔术手中Output内勾选输出Hex文件,不然代码无效,执行其他代码。
*/
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
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 Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void initTime1() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
void initSG90_0() //SG90舵机初始化函数。
{
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
cnt = 0; //初始化爆表变量
}
double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017 * time);
}
void openCoverLight() //开盖灯的状态
{
D5 = 0;
D6 = 1;
}
void closeCoverLight() //关盖垃圾桶的状态
{
D5 = 1;
D6 = 0;
}
void openCoverDustbin() //垃圾桶开盖函数
{
angle = 3; //舵机开盖
cnt = 0;
Delay2000ms();
}
void closeCoverDustbin()//垃圾桶关盖函数
{
angle = 1; //舵机关盖
cnt = 0;
Delay150ms();
}
void main()
{
double dis;
Delay300ms();
initTime0();
initTime1();
initSG90_0();
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10)
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
一、根据开发板原理图,将SW1
定义接到单片机P2.1
口
sbit SW1 = P2^1; //按键1根据原理图接单片机2.1口
二、在主函数while死循环中添加或上按键被按下的条件
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10 || SW1 == 0)
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
#include "reg52.h"
/*
时间: 2023年10月4日15:12:22
程序功能:垃圾桶04添加按键开盖功能
*/
sbit SW1 = P2^1; //按键1根据原理图接单片机2.1口
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
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 Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void initTime1() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
void initSG90_0()
{
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
cnt = 0; //初始化爆表变量
}
double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017 * time);
}
void openCoverLight()
{
D5 = 0;
D6 = 1;
}
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
void openCoverDustbin()
{
angle = 3; //舵机开盖
cnt = 0;
Delay2000ms();
}
void closeCoverDustbin()
{
angle = 1; //舵机关盖
cnt = 0;
Delay150ms();
}
void main()
{
double dis;
Delay300ms();
initTime0();
initTime1();
initSG90_0();
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10 || SW1 == 0) //距离小于10或SW1被按下,舵机开盖。
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
05
添加震动开盖功能使用外部中断优化根据单片机手册得知P3.2口为外部中断
)口,并在主函数死循环中添加P3.2口接收到低电平的判断条件。一、判断条件
if(dis < 10 || SW1 == 0 || Vibrate == 0)
二、 会出现震动开盖不灵敏的BUG,因为再关盖后会延时150毫秒。并且此时测距的距离大于10厘米。震动触发的低电平容易卡在软件延时的150毫秒内。解决办法就是设立外部中断,建立震动传感器标志变量。当发生震动,标志为0,触发开盖。反之则不。
三、
void initEX0_vib() //初始化外部中断0关于震动传感器
{
EX0 = 1;
IT0 = 0;
}
void EX0_Handler() interrupt 0
{
markVibrate = 0;
}
三、
int markVibrate = 1; //震动传感器标志变量 一定要默认初始化为1,因为为0时单片机一上电就会开盖。
#include "reg52.h"
/*
时间: 2023年10月4日15:48:22
程序功能:垃圾桶05添加震动开盖功能使用外部中断优化
*/
sbit SW1 = P2^1; //按键1根据原理图接单片机2.1口
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
sbit vibrate = P3^2; //根据原理图接把震动传感器接外部中断0 P3.2口
sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
int markVibrate = 1; //震动传感器标志变量
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
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 Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void initTime1() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
void initEX0_vib() //初始化外部中断0关于震动传感器
{
EX0 = 1;
IT0 = 0;
}
void initSG90_0()
{
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
cnt = 0; //初始化爆表变量
}
double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017 * time);
}
void openCoverLight()
{
D5 = 0;
D6 = 1;
}
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
void openCoverDustbin()
{
angle = 3; //舵机开盖
cnt = 0;
Delay2000ms();
}
void closeCoverDustbin()
{
angle = 1; //舵机关盖
cnt = 0;
Delay150ms();
}
void main()
{
double dis;
Delay300ms();
initSG90_0();
initTime0();
initTime1();
initEX0_vib();
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10 || SW1 == 0 || markVibrate == 0) //距离小于10或SW1被按下,舵机开盖。
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
markVibrate = 1;
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
void EX0_Handler() interrupt 0
{
markVibrate = 0;
}
一、把蜂鸣器接单片机P2.0
口
sbit beep = P2^0; //蜂鸣器接单片机2.0口
二、在舵机开盖函数中添加蜂鸣器启动关闭语句,给予300ms
软件延时。
void openCoverDustbin()
{
angle = 3; //舵机开盖
cnt = 0;
beep = 0; //低电平响
Delay300ms();
beep = 1;
Delay2000ms();
}
#include "reg52.h"
/*
时间: 2023年10月4日17:24:06
程序功能:垃圾桶06添加开盖滴滴声_项目完结
*/
sbit SW1 = P2^1; //按键1根据原理图接单片机2.1口
sbit beep = P2^0; //蜂鸣器接单片机2.0口
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
sbit vibrate = P3^2; //根据原理图接把震动传感器接外部中断0 P3.2口
sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
int markVibrate = 1; //震动传感器标志变量
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
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 Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void initTime1() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
void initEX0_vib() //初始化外部中断0关于震动传感器
{
EX0 = 1;
IT0 = 0;
}
void initSG90_0()
{
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
cnt = 0; //初始化爆表变量
}
double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017 * time);
}
void openCoverLight()
{
D5 = 0;
D6 = 1;
}
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
void openCoverDustbin()
{
angle = 3; //舵机开盖
cnt = 0;
beep = 0; //低电平响
Delay300ms();
beep = 1;
Delay2000ms();
}
void closeCoverDustbin()
{
angle = 1; //舵机关盖
cnt = 0;
Delay150ms();
}
void main()
{
double dis;
Delay300ms();
initSG90_0();
initTime0();
initTime1();
initEX0_vib();
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10 || SW1 == 0 || markVibrate == 0) //距离小于10或SW1被按下,舵机开盖。
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
markVibrate = 1;
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
void EX0_Handler() interrupt 0
{
markVibrate = 0;
}
一、定义一个角度标志变量
int angleBak = 0; //角度标志变量
二、在舵机开盖关盖函数中分别让角度变量angle
等于角度标志变量angleBak
angleBak = angle;
三、在舵机开盖函数中添加if判断angleBak != angle;
再执行后面语句。
if(angleBak != angle)
{
cnt = 0;
beep = 0;
Delay300ms();
beep = 1;
Delay2000ms();
}
四、最后解决挡住超声波测距撤出后盖子快速盖上情况可以利用在angleBak = angle;
后添加软件延时150ms
解决
angleBak = angle;
Delay150ms();
#include "reg52.h"
/*
时间: 2023年10月4日17:24:06
程序功能:垃圾桶06添加开盖滴滴声_项目完结
*/
sbit SW1 = P2^1; //按键1根据原理图接单片机2.1口
sbit beep = P2^0; //蜂鸣器接单片机2.0口
sbit Trig = P1^5; //超声波测距的控制Trig接单片机1.5口
sbit Echo = P1^6; //超声波测距的控制Echo接单片机1.6口
sbit D5 = P3^7; //根据原理图D5 led灯接单片机3.7口
sbit D6 = P3^6; //根据原理图D6 led灯接单片机3.6口
sbit vibrate = P3^2; //根据原理图接把震动传感器接外部中断0 P3.2口
sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
int markVibrate = 1; //震动传感器标志变量
int angleBak = 0; //角度标志变量
void Delay10us() //@11.0592MHz 软件延时10us
{
unsigned char i;
i = 2;
while (--i);
}
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 Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 软件延时300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void startHC() //给超声波模块控制为Trig一个10us的触发信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void initTime1() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
void initTime0() //初始化定时器T0
{
//1.设置定时器为T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.设置初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.启动定时器,开始计时
TR0 = 1; //TR0为启动定时器标志,值为1启动定时器
TF0 = 0;
//4.打开定时器0的中断 赋1打开
ET0 = 1;
//5.打开总中断EA 赋1打开
EA = 1;
}
void initEX0_vib() //初始化外部中断0关于震动传感器
{
EX0 = 1;
IT0 = 0;
}
void initSG90_0()
{
sg90_con = 1; //单片机上电,给sg90舵机控制线一个高电平。
angle = 1; //给角度控制变量初始化为0度,因为0.5毫秒的高电平PWM波为0度,angle = 1;时定时器刚好定时0.5毫秒
cnt = 0; //初始化爆表变量
}
double getDistance()
{
double time;
//重新给初值,重新计时
TL1 = 0;
TH1 = 0;
//1.Trig ,给Trig端口至少10us的高电平
startHC();
//2.Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
// 波发出去的那一下,开始启动定时器
TR1 = 1; //启动定时器T0
//3.Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
// 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
TR1 = 0; //关闭定时器
time = ((TH1 * 256) + TL1)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
//4.距离 = 速度 (340m/s)* 时间/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017 * time);
}
void openCoverLight()
{
D5 = 0;
D6 = 1;
}
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
void openCoverDustbin()
{
angle = 3; //舵机开盖
if(angleBak != angle)
{
cnt = 0;
beep = 0;
Delay300ms();
beep = 1;
Delay2000ms();
}
angleBak = angle;
Delay150ms();
}
void closeCoverDustbin()
{
angle = 1; //舵机关盖
cnt = 0;
Delay150ms();
}
void main()
{
double dis;
Delay300ms();
initSG90_0();
initTime0();
initTime1();
initEX0_vib();
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10 || SW1 == 0 || markVibrate == 0) //距离小于10或SW1被按下,舵机开盖。
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
markVibrate = 1;
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
}
void Time0Handler() interrupt 1 //定时器T0中断函数,中断号为interrupt 1
{
cnt++;
//重新给定时器赋初值,定时0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判读记录爆表变量cnt的值是否小于角度变量的值,小于继续给sg90舵机控制线高电平,大于等于则给低电平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判断cnt是否加到40,定时是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定时到20豪秒,cnt从0开始加
sg90_con = 1;//定时到20豪秒,重新给舵机控制线一个高电平
}
}
void EX0_Handler() interrupt 0
{
markVibrate = 0;
}
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!