目录
效果展示:
基于C52单片机的感应开盖垃圾桶
一 超声波模块

超声波模块
型号:HC-SR04
接线参考:模块除了两个电源引脚外,还有TRIG,ECHO引脚,这两个引脚分别接我们开发板
P1.5 和 P1.6 端口
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度,
计算出模块到前方障碍物的距离。
怎么让它发送波
Trig ,给Trig端口至少10us的高电平
怎么知道它开始发了
Echo信号,由低电平跳转到高电平,表示开始发送波
怎么知道接收了返回波
Echo,由高电平跳转回低电平,表示波回来了
怎么算时间
Echo引脚维持高电平的时间!
波发出去的那一下,开始启动定时器
波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间
怎么算距离
距离 = 速度 (340m/s)* 时间/2
代码:
设置定时器为初始状态,4行代码,然后利用进制运算换算出时间,再求出距离
//计算时间
time = (TH0 * 256 + TL0)*1.085;//us
//计算距离
dist = time * 0.017;//cm

#include "reg52.h"
sbit Trig = P1^5;
sbit Echo = P1^6;
sbit led1 = P3^7;
sbit led2 = P3^6;
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void send(){
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void Timer0Init(void) //71毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01;
TL0 = 0; //设置定时初值
TH0 = 0; //设置定时初值
}
void main()
{
double time;
double dist;
Timer0Init();
while(1){
//发送信号
send();
//Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
TR0 = 1;//开始计时
//Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
TR0 = 0;//停止计时
//计算时间
time = (TH0 * 256 + TL0)*1.085;//us
//计算距离
dist = time * 0.017;//cm
//根据距离亮灯
if(dist < 10){
led1 = 0;
led2 = 1;
}else{
led1 = 1;
led2 = 0;
}
TL0 = 0; //设置定时初值
TH0 = 0;
}
}
二 超声波感应自动开盖、 按键开盖
材料:
舵机 超声波模块 蜂鸣器
需求:
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
双计时器:
由于舵机和超声波都需要计时器,所以把T0;T1两个计时器分别使用
将上述距离检测定时器T0改为T1;并且封装函数:
#include "reg52.h"
sbit Trig = P1^5;
sbit Echo = P1^6;
sbit led1 = P3^7;
sbit led2 = P3^6;
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void send(){
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void Timer1Init(void)
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x00; //设置定时初值
TH1 = 0x00; //设置定时初值
}
double dist;
double time;
void getDistance(){
//发送信号
send();
//Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
TR1 = 1;//开始计时
//Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
TR1 = 0;//停止计时
//计算时间
time = (TH1 * 256 + TL1)*1.085;//us
//计算距离
dist = time * 0.017;//cm
}
void main()
{
Timer1Init();
while(1){
getDistance();
//根据距离亮灯
if(dist < 10){
led1 = 0;
led2 = 1;
}else{
led1 = 1;
led2 = 0;
}
TL1 = 0; //设置定时初值
TH1 = 0;
}
}
运行成功。
实现:
将PWM舵机控制的代码与上述代码进行结合
多封装函数,
注意两个定时器配置别冲突了
T0:
TMOD &= 0xF0;
TMOD |= 0x01;
T1:
TMOD &= 0x0F;
TMOD |= 0x10;
#include "reg52.h"
#include <intrins.h>
//舵机引脚
sbit sg90_con = P1^1;
//蜂鸣器
sbit buzzer = P1^2;
//超声波
sbit Trig = P1^5;
sbit Echo = P1^6;
//led
sbit led1 = P3^7;
sbit led2 = P3^6;
//按键
sbit key1 = P2^0;
int angle;
int cnt = 0;
void Timer0Init()//500微秒;T0
{
//1. 配置定时器0工作模式位16位计时
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01;
//2. 给初值,定一个10ms出来
TL0 = 0x33; //设置定时初值
TH0 = 0xFE; //设置定时初值
//3. 开始计时,定时器"数数"
TR0 = 1;
TF0 = 0;
//4. 打开定时器0中断
ET0 = 1;
//5. 打开总中断EA
EA = 1;
}
void Timer1Init(void)//测距使用;T1
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x00; //设置定时初值
TH1 = 0x00; //设置定时初值
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void send(){//发出超声波
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void Delay1500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 11;
j = 130;
k = 111;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//测距功能:
double dist;
double time;
void getDistance(){
//发送信号
send();
//Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
TR1 = 1;//开始计时
//Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
TR1 = 0;//停止计时
//计算时间
time = (TH1 * 256 + TL1)*1.085;//us
//计算距离
dist = time * 0.017;//cm
TL1 = 0; //设置定时初值
TH1 = 0;
}
void Open(){
//Turn the Lihgt
led1 = 0;
led2 = 1;
//open buzzer
buzzer = 0;
//open lid
angle = 3;//90度
cnt = 0;
Delay500ms();
//close buzzer
buzzer = 1;
Delay1500ms();
}
void Close(){
//Turn the Lihgt
led1 = 1;
led2 = 0;
//close lid
angle = 1;//0度
cnt = 0;
}
//================================================
void main()
{
Delay500ms();
Timer1Init();
Timer0Init();
while(1){
getDistance();
//根据距离亮灯
if(dist < 10 || key1 == 0){
Open();
}else{
Close();
}
}
}
//=================================================
void Time0Handler() interrupt 1
{
cnt++; //统计爆表的次数
//重新给初值
TL0 = 0x33; //设置定时初值
TH0 = 0xFE; //设置定时初值
if(cnt < angle){
sg90_con = 1;
}else{
sg90_con = 0;
}
if(cnt == 40){//爆表40次,经过了20ms
cnt = 0; //计算下一次的20ms
sg90_con = 1;
}
}
三 添加震动开盖(外部中断)
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
代码相同,但是震动导致的低电平时间很短,不容易被检测到
所以采用中断



CPU能响应定时器0中断的条件:需要配置IE寄存器的 bit1: ET0 bit7:EA
1. ET0中断允许要置一 ET0 = 1
2. EA总中断要置一 EA = 1

//打开外部中断
EX0 = 1;
//低电平触发
IT0 = 0;
#include "reg52.h"
#include <intrins.h>
//舵机引脚
sbit sg90_con = P1^1;
//蜂鸣器
sbit buzzer = P1^2;
//超声波
sbit Trig = P1^5;
sbit Echo = P1^6;
//led
sbit led1 = P3^7;
sbit led2 = P3^6;
//按键
sbit key1 = P2^0;
//震动传感器,外部中断,这里其实不用定义,插上就行
sbit vibrate = P3^2;
int angle;
int cnt = 0;
char vib_mark = 0;//char省空间
void Timer0Init()//500微秒;T0
{
//1. 配置定时器0工作模式位16位计时
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01;
//2. 给初值,定一个10ms出来
TL0 = 0x33; //设置定时初值
TH0 = 0xFE; //设置定时初值
//3. 开始计时,定时器"数数"
TR0 = 1;
TF0 = 0;
//4. 打开定时器0中断
ET0 = 1;
//5. 打开总中断EA
EA = 1;
}
void Timer1Init(void)//测距使用;T1
{
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0x00; //设置定时初值
TH1 = 0x00; //设置定时初值
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void send(){//发出超声波
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void vibrate_EX0_init(){
//打开外部中断
EX0 = 1;
//低电平触发
IT0 = 0;
}
//测距功能:
double dist;
double time;
void getDistance(){
//发送信号
send();
//Echo信号,由低电平跳转到高电平,表示开始发送波
while(Echo == 0);
TR1 = 1;//开始计时
//Echo,由高电平跳转回低电平,表示波回来了
while(Echo == 1);
TR1 = 0;//停止计时
//计算时间
time = (TH1 * 256 + TL1)*1.085;//us
//计算距离
dist = time * 0.017;//cm
TL1 = 0; //设置定时初值
TH1 = 0;
}
void Open(){
//Turn the Lihgt
led1 = 0;
led2 = 1;
//open buzzer
buzzer = 0;
//open lid
angle = 3;//90度
Delay500ms();
//close buzzer
buzzer = 1;
Delay1000ms();
//if close lid
while(dist < 10){
getDistance();
}
Delay500ms();
vib_mark = 0;
}
void Close(){
//Turn the Lihgt
led1 = 1;
led2 = 0;
//close lid
angle = 1;//0度
}
//================================================
void main()
{
Delay500ms();
Timer1Init();
Timer0Init();
vibrate_EX0_init();
while(1){
getDistance();
//根据距离亮灯
if(dist < 10 || key1 == 0 || vib_mark == 1){
Open();
}else{
Close();
}
}
}
//=================================================
void Time0Handler() interrupt 1
{
cnt++; //统计爆表的次数
//重新给初值
TL0 = 0x33; //设置定时初值
TH0 = 0xFE; //设置定时初值
if(cnt < angle){
sg90_con = 1;
}else{
sg90_con = 0;
}
if(cnt == 40){//爆表40次,经过了20ms
cnt = 0; //计算下一次的20ms
sg90_con = 1;
}
}
void EX0_handler() interrupt 0
{
vib_mark = 1;
}
四 最终效果
震动、按钮或者超声波距离检测,触发蜂鸣器饷以及开盖2秒。
两秒后,如果人还一直在检测范围内,就不关盖。
基于C52单片机的感应开盖垃圾桶
628

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



