目录
一、超声波测距传感器认知
二、从零编程实现超声波测距
三、项目——感应开关盖垃圾桶
1、开发步骤
2、感应开关盖垃圾桶代码测试
一、超声波测距传感器认知
超声波测距模块是用来测量距离的一种产品,通过发送和接收超声波,利用时间差和声音传播速度,计算出模块到前方障碍物的距离
接线参考:模块除了两个电源引脚外,还有TRIG、ECHO引脚,这两个引脚分别接我们开发板的P1.5和P1.6端口
TRIG引脚: 发送波的引脚
ECHO引脚:接收波的引脚
怎么让它发送波
Trig,给Trig端口至少10μs的高电平
怎么知道开始发波
Echo,由低电平跳转到高电平,表示开始发送波
怎么让它接收了返回波
Echo,由高电平转回低电平,表示波回来了
怎么算时间
波发出去的那一下,开始启动定时器
波回来的那一下,我们停止定时器,计算出中间经过多少时间
怎么算距离
距离 = (速度(340m/s)* 高电平时间)/ 2
超声波的时序图
二、从零编程实现超声波测距
#include "reg52.h"//距离小于10cm,D5亮,D6灭,反之相反现象
sbit D5 = P3^7;
sbit D6 = P3^6;
sbit Trig = P1^5;
sbit Echo = P1^6;void Delay10us() //@11.0592MHz
{unsigned char i;i = 2;while (--i);
}
void Time0Init(){TMOD &= 0xF0; //设置定时器模式TMOD |= 0x01; //设置定时器模式TL0 = 0; //设置定时初值TH0 = 0; //设置定时初值//设置定时器0工作模式1,初始值设定0开始数数
}
void startHC(){ Trig = 0;Trig = 1;Delay10us();Trig = 0;
}void main()
{double time;double dis;Time0Init();while(1){//1、给Trig端口至少10μs的高电平startHC();//2、由低电平跳转到高电平,表示开始发送波while(Echo == 0);//3、波发出去时,开启定时器TR0 = 1;//4、由高电平跳转到低电平,表示接收波while(Echo == 1);//5、波回来那一下,我们停止定时器TR0 = 0;//6、计算出中间经过多长时间time = (TH0 * 256 + TL0) * 1.085; //μs为单位//7、距离 = 速度(340m/s)* 时间 /2//dis= 340m/s = 34000cm/s = 34cm/ms = 0.034cm/μsdis = time * (0.034/2);if(dis < 10){D5 = 0;D6 = 1;}else{D5 = 1;D6 = 0;}//定时器数据清零,以便下次测距TL0 = 0; //设置定时初值TH0 = 0; //设置定时初值}
}
三、项目——感应开关盖垃圾桶
1、开发步骤
1、舵机和超声波代码整合
舵机用定时器0
超声波用定时器1
实现物体靠近后,自动开盖,2秒后关盖
2、查询的方式添加按键控制
3、查询的方式添加震动控制
4、使用外部中断0配合震动控制
2、感应开关盖垃圾桶代码测试
#include "reg52.h"//距离小于10cm,D5亮,D6灭,反之相反现象
sbit D5 = P3^7;
sbit D6 = P3^6;
sbit Trig = P1^5;
sbit Echo = P1^6;
sbit sg90_con = P1^1;
sbit SW1 = P2^1;
sbit vibrate = P3^2; //添加震动传感器引脚
sbit beep = P2^0; //蜂鸣器引脚char jd;
char jd_bak; //记录上一个角度标记
char cnt = 0;
char mark_vibrate = 0; //添加一个标记void Delay2000ms() //@11.0592MHz
{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 Delay10us() //@11.0592MHz
{unsigned char i;i = 2;while (--i);
}void Time0Init(){//1、配置定时器0工作模式位16位计时TMOD &= 0xF0; //设置定时器模式TMOD |= 0x01; //设置定时器模式//2、给定时器一个初值,每个周期都等于0.5msTL0 = 0x33;TH0 = 0xFE;//3、定时器开始计时TR0 = 1;TF0 = 0;//4、打开中断定时器ET0 = 1;//5、设置总中断定时器EA = 1;
}void Time1Init(){TMOD &= 0x0F; //设置定时器模式TMOD |= 0x10; //设置定时器模式TL1 = 0; //设置定时初值TH1 = 0; //设置定时初值//设置定时器0工作模式1,初始值设定0开始数数
}void startHC(){Trig = 0;Trig = 1;Delay10us();Trig = 0;
}double get_distance(){double time;//定时器数据清零,以便下次测距TL1 = 0; //设置定时初值TH1 = 0; //设置定时初值//1、给Trig端口至少10μs的高电平startHC();//2、由低电平跳转到高电平,表示开始发送波while(Echo == 0);//3、波发出去时,开启定时器TR1 = 1;//4、由高电平跳转到低电平,表示接收波while(Echo == 1);//5、波回来那一下,我们停止定时器TR1 = 0;//6、计算出中间经过多长时间time = (TH1 * 256 + TL1) * 1.085; //μs为单位//7、距离 = 速度(340m/s)* 时间 /2//dis= 340m/s = 34000cm/s = 34cm/ms = 0.034cm/μsreturn (time * (0.034/2));
}void openStatusLight(){D5 = 0;D6 = 1;
}void closeStatusLight(){D5 = 1;D6 = 0;
}void initSG90_0(){jd = 1; //初始角度是0度,什么时候0度,刚好是0.5ms的高电平,也是定时器溢出1次cnt = 0;sg90_con = 1; //刚开始给PWM信号一个高电平
}void openDusbin(){ //舵机开盖char n;jd = 3; //90度,1.5ms的高电平if(jd_bak != jd){cnt = 0; //每切换一次角度,都要重置cnt的值beep = 0;for(n=0;n<2;n++);Delay150ms();beep = 1;Delay2000ms();}jd_bak = jd;}void closeDusbin(){ //舵机关盖jd = 1; //0度,1.5ms的高电平cnt = 0; //每切换一次角度,都要重置cnt的值jd_bak = jd;Delay150ms();
}void EX0_Init(){ //打开外部中断函数//打开外部中断EX0 = 1;//低电平触发IT0 = 0;
}void main()
{double dis;Time0Init();Time1Init();EX0_Init();//舵机的初始位置initSG90_0();while(1){//超声波测距dis = get_distance();if(dis < 10 || SW1 == 0 || mark_vibrate == 1){ //如果小于10cm,或者SW1按键被按下,或者vibrate震动//开盖,灯状态,D5亮openStatusLight();//舵机开盖openDusbin();mark_vibrate = 0;}else{//关盖,灯状态,D5灭closeStatusLight();//舵机关盖closeDusbin(); }}
}void Time0Handler() interrupt 1 //定时器0的硬件中断号为 interrupt 1
{cnt ++; //统计爆表的次数//给定时器重新定义初值,每个周期都等于0.5msTL0 = 0x33; TH0 = 0xFE;//控制PWM波形if(cnt < jd){sg90_con = 1;}else{sg90_con = 0;}if(cnt == 40){ //要爆表40次,经过了20mscnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1ssg90_con = 1;}
}void Ex0_Handler() interrupt 0 //外部中断号为 interrupt 0
{mark_vibrate = 1;
}
垃圾桶实体演示