垃圾桶有灵性了!还会自动开盖。#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;
}
结束语
很高兴您能看到这里,点个赞再走呗。谢谢您啦!!!