垃圾桶有灵性了!还会自动开盖。#51单片机制作感应开关盖垃圾桶【下】
前言
本篇博文介绍的是用51单片机制作感应开关盖垃圾桶【下】,里面包含sg90舵机基本认知,定时中断方式控制LED灯,舵机实战编程,超声波测距传感器认知,从零编程实现超声波测距(当距离小于10厘米,D5亮,D6灭。当距离大于10厘米,D5灭,D6亮。),感应开关盖垃圾桶需求设计,垃圾桶01修改超声波为定过器一控制,垃圾桶02封装超声波测距代码,垃圾桶03实现距离感应开盖,垃圾桶04添加按键开盖功能,垃圾桶05添加震动开盖功能使用外部中断优化,垃圾桶06添加开盖滴滴声_项目完结,垃圾桶的抽抽BUG解决。看到这篇博文的朋友,可以先赞再看吗?
1.预备知识
一、数学周期,频率等相关知识。
二、数学对于时间的计算。
三、数学对于波形的理解能力
四、数字电子中与或运算
五、计算机中的进制转换
六、C变量
七、基本输入输出
八、流程控制
九、函数
如果以上知识不清楚,请自行学习后再来浏览。
2.sg90舵机基本认知
2.1什么是舵机
如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号线。起控制舵机转动角度作用。控制角度的用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等常见的有0-90°、0-180°、0-360°。

2.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.5ms 记录爆表次数变量cnt++
1s = 10ms * 100
20ms = 0.5ms * 40
3.定时中断方式控制LED灯
3.1程序思路
一、在定时器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();
}
}
3.2完整程序代码
#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灯状态翻转
}
}
4.舵机实战编程
4.1程序思路
一、设计定时器初值为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();
}
}
4.2 PWM设计波形图

4.3完整程序代码
#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豪秒,重新给舵机控制线一个高电平
}
}
5.超声波测距传感器认知
5.1手册介绍
5.1.1产品特色
1、典型工作用电压:5V。
2、超小静态工作电流:小于 2mA。
3、感应角度:不大于15度 。
4、探测距离:2cm-400cm
5、高精度:可达 0.3cm。
6、盲区(2cm)超近。
7、完全谦容 GH-311 防盗模块。
8、带金属 USB 外壳,坚固耐用。
5.1.2接口定义
Vcc、 Trig(控制端)、 Echo(接收端)、 Gnd
5.1.3产品使用方法
控制口发一个 10us 以上的高电平,就可以在接收口等待高电平输出.一有输出就可以开定时器计时,当此口变为低电平时就可以读取定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,就可以达到你移动测量的值了。
5.1.4模块工作原理
(1)采用 IO 触发测距,给至少 10us 的高电平信号;
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 输出一高电平,高电平持续的时间就是
(4)超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
5.1.5超声波时序图

5.1.6注意事项
1:此模块不宜带电连接,如果要带电连接,则先让模块的 Gnd 端先连接。否则会影响模块工作。
2:测距时,被测物体的面积不少于 0.5 平方米且要尽量平整。否则会影响测试结果。
5.2课程内容
5.1简介
型号:HC-SR04
接线参考:模块除了两个电源引脚外,还有TRIG,ECHO引脚,这两个引脚分别接我开发板的P1.5和P1.6端口
超声波测距模块是用来测量距离的一种产品,通过发送和接收超声波,利用时间差和声音传播速度,计算出模块到前方障碍物的距离。
5.2怎么让它发送波
Trig ,给Trig端口至少10us的高电平。
5.3怎么知道它开始发了
Echo信号,由低电平跳转到高电平,表示开始发送波。
5.4怎么知道接收了返回波
Echo,由高电平跳转回低电平,表示波回来了。
5.5怎么算时间
Echo引脚维持高电平的时间!
波发出去的那一下,开始启动定时器
波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
5.6怎么算距离
距离 = 速度 (340m/s)* 时间/2
6.从零编程实现超声波测距(当距离小于10厘米,D5亮,D6灭。当距离大于10厘米,D5灭,D6亮。)
6.1程序思路
6.1.1 Trig信号 ,给Trig端口至少10us的高电平
一、软件延时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();
6.1.2 Echo信号,由低电平跳转到高电平,表示开始发送波
一、
while(Echo == 0); //等待发送波
二、波发出去的那一下,开始启动定时器
定时器T0初始化函数
void time0Init() //设置定时器T0为16位模式,从0开始数数,不忙启动定时器
{
TMOD &= 0xF0;
TMOD |= 0x01;
TL0 = 0;
TH0 = 0;
}
定时器T0启动
TR0 = 1; //启动定时器T0
6.1.3 Echo,由高电平跳转回低电平,表示波回来了
一、
while(Echo == 1); //等待波回来
二、波回来的那一下,我们开始停止定时器
TR0 = 0; //关闭定时器
三、计算出中间经过多少时间
time = ((TH0 * 256) + TL0)*1.085; //单位为us。
/*
256的含义:
对于十进制数2向左移一位位20,相当于乘以10
那么对于二进制数2向左移移一位,相当于乘以2。移动8位,乘以2的8次方256
*/
6.1.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;
6.1.5判断距离小于10厘米,D5亮,D6灭。判断距离大于10厘米,D5灭,D6亮。
if(dis < 10)
{
D5 = 0;
D6 = 1;
}
else
{
D5 = 1;
D6 = 0;
}
6.1.6因为需要重复测距,所以得多次给定时器赋初值
重新给初值,重新计时
TL0 = 0;
TH0 = 0;
6.2完整程序代码
#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;
}
}
7.感应开关盖垃圾桶需求设计
7.1 项目概述
7.1.1功能描述
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
7.1.2硬件说明
SG90舵机,超声波模块,震动传感器,蜂鸣器
7.1.3接线说明
舵机控制口 P1.1
超声波Trig接 P1.5
Echo接 P1.6
蜂鸣器接 P2.0 口
震动传感器接 P3.2口(外部中断0)
8.垃圾桶01修改超声波为定过器一控制
8.1开发步骤
8.1.1舵机用定时器0 超声波用定时器1
8.1.2修改超声波定时器T0为T1
TMOD &= 0xF0 修改为 TMOD &= 0x0F
TMOD |= 0x01 修改为 TMOD &= 0x10
所有的TL0修改为TL1
所有的TH0修改为TH1
所有的TR0修改为TR1
time0Init() 修改为 time1Init()
8.1.3修改后的程序代码
#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;
}
}
9.垃圾桶02封装超声波测距代码
9.1建立测距函数
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);
}
8.2建立开盖灯状态函数
void opencCoverLight()
{
D5 = 0;
D6 = 1;
}
8.3建立关盖灯状态函数
void closeCoverLight()
{
D5 = 1;
D6 = 0;
}
8.4修改后的程序代码
#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();
}
}
}
10.垃圾桶03实现距离感应开盖
10.1程序思路:总思路将舵机控制代码和超声波控制给整合到一个程序中
10.1.1将舵机控制的变量和IO口复制到超声波测距程序代码中
sbit sg90_con = P1^1; //sg90舵机PWM控制线接单片机P1.1口,用于模拟PWM波形。
int cnt = 0; //记录爆表次数
int angle; //记录舵机角度变量
10.1.2将300毫秒,2000毫秒软件延时函数复制到超声波测距程序代码中,并建立一个软件延时150毫秒的函数
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);
}
10.1.3将定时器T0初始化函数和定时器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;
}
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豪秒,重新给舵机控制线一个高电平
}
}
10.1.4分别建立SG90舵机初始化函数,垃圾桶开关盖函数。置于超声波测距程序的相应位置
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();
}
10.1.5通过超声波测距,小于10厘米就开盖开灯。大于10厘米就关盖关灯。
while(1)
{
dis = getDistance(); //超声波测距
if(dis < 10)
{
openCoverLight(); //开盖,D5亮
openCoverDustbin();
}
else
{
closeCoverLight(); //关盖,D5灭
closeCoverDustbin();
}
}
10.1.6特别提醒:编译时记得输出HEX文件,不然程序会跑错。
10.2完整程序代码
#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豪秒,重新给舵机控制线一个高电平
}
}
11.垃圾桶04添加按键开盖功能
11.1程序思路
一、根据开发板原理图,将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();
}
}
11.2完整程序代码
#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豪秒,重新给舵机控制线一个高电平
}
}
12.垃圾桶05添加震动开盖功能使用外部中断优化
12.1程序思路
12.1.1直接采用软件扫码震动传感器返回的低电平启动开盖。只需要将震动传感器接入单片机P3.2(根据单片机手册得知P3.2口为外部中断)口,并在主函数死循环中添加P3.2口接收到低电平的判断条件。
一、判断条件
if(dis < 10 || SW1 == 0 || Vibrate == 0)
二、 会出现震动开盖不灵敏的BUG,因为再关盖后会延时150毫秒。并且此时测距的距离大于10厘米。震动触发的低电平容易卡在软件延时的150毫秒内。解决办法就是设立外部中断,建立震动传感器标志变量。当发生震动,标志为0,触发开盖。反之则不。
三、

12.1.2依据单片机手册建立外部中断0的初始化函数
一、

二、

三、
void initEX0_vib() //初始化外部中断0关于震动传感器
{
EX0 = 1;
IT0 = 0;
}
12.1.3依据手册建立外部中断执行函数并建立震动标志变量
一、

二、
void EX0_Handler() interrupt 0
{
markVibrate = 0;
}
三、
int markVibrate = 1; //震动传感器标志变量 一定要默认初始化为1,因为为0时单片机一上电就会开盖。
12.2完整程序代码
#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;
}
13.垃圾桶06添加开盖滴滴声_项目完结
13.1程序思路
一、把蜂鸣器接单片机P2.0口
sbit beep = P2^0; //蜂鸣器接单片机2.0口
二、在舵机开盖函数中添加蜂鸣器启动关闭语句,给予300ms软件延时。
void openCoverDustbin()
{
angle = 3; //舵机开盖
cnt = 0;
beep = 0; //低电平响
Delay300ms();
beep = 1;
Delay2000ms();
}
13.2完整程序代码
#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;
}
14.垃圾桶的抽抽BUG解决
14.1程序思路
一、定义一个角度标志变量
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();
14.2完整程序代码
#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;
}
结束语
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!

8971

被折叠的 条评论
为什么被折叠?



