具体功能实现
将遮挡物放置HC-SR04前,可以将超声波模块和遮挡物之间的距离展示在4位数码管上;如果两者之间的距离小于5cm,则LED灯(P2^7)亮起。
器件
HC-SR04超声波模块,4位数码管,LED灯,4根杜邦线
超声波测距展示图:
当距离小于5cm时:
此时超声波和遮挡物的距离为4.5cm< 5cm,所以LED(P2^7)点亮。
当距离大于5cm时:
此时超声波和遮挡物的距离为15.6cm,LED灯熄灭
知识介绍
超声波模块(HC-SR04)
以上是该模块测距的工作原理:由Trig引脚发送一个10us的高电平信号,此时模块内部会自动发送8个40khz的脉冲信号,最后声音返回的信号会传送至Echo引脚,利用距离、时间和速度的公式可以得出两者之间的距离
HC-SR04引脚定义图
该项目代码中,Trig口接至P2^1 , Echo接至P2^0,VCC接3.3v,GND接地
超声波测距公式及原理
测试距离 = (高电平时间 * 声速(340m / s)) /2
测试距离最终要除于2的原因是经历了一个来回,相当于走了原本距离的两倍
定时中断系统
外部中断:
STC89C52有4个外部中断;
STC89C52的外部中断有两种触发方式:
下降沿触发和低电平触发
下降沿触发:当按键按下不松手时只触发一次
低电平触发:当按键按下不松手时会持续触发
中断号:
主函数代码(C语言)KEIL5实现
#include
/* 自定义变量类型 */
typedef unsigned char uchar; //0~255
typedef unsigned int uint; //0~65535
sbit Echo = P2^0;
sbit Trig = P2^1;
uchar flag;
uchar date_distance[5];
uchar count;
/* 用于控制数码管的引脚 */
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
uchar LSA_NODE1[] = {0,1,0,1,0,1,0,1,0};
uchar LSB_NODE1[] = {0,1,1,0,0,1,1,0,0};
uchar LSC_NODE1[] = {0,1,1,1,1,0,0,0,0};
//共阴数码管码表 0-F
uchar SMG[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0X00};
//延时10us
void delay_10us(uchar i)
{
while(i--);
}
//延迟1ms
void delay_ms(uint c) //误差 0us
{
uint a,b;
for(;c>0;c--)
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
/* 数码管选择函数 */
void init_smg(uchar i)
{
LSA = LSA_NODE1[i];
LSB = LSB_NODE1[i];
LSC = LSC_NODE1[i];
}
//初始化定时器
void init_timer()
{
TMOD = 0x11; //打开定时器0 1
//初始化定时器 0
TH0 = 0x00;
TL0 = 0x00;
EA = 1;
ET0 = 1;
//TR0 = 1;
//初始化定时器 1
TH1 = 0xF8; //定时2ms
TL1 = 0xCD;
ET1 = 1;
TR1 = 1;
}
//计算距离
void count_distance()
{
//s = 340m/s * time us /2 = 170*time *10^-6 m = 0.17*time mm
uint distance = (TH0*256 + TL0*1)*0.17; //单位mm
if(distance<50)
{
P2_7 = 0;
}
else {
P2_7 = 1;
}
TH0 = 0;
TL0 = 0;
date_distance[1] = distance%10000/1000;
date_distance[2] = distance%1000/100;
date_distance[3] = distance%100/10;
date_distance[4] = distance%10/1;
}
void display()
{
uchar i;
for(i = 1;i<=4;i++)
{
if(i==1)
P0 = SMG[date_distance[i]] |0x80;
else
P0 = SMG[date_distance[i]];
delay_ms(1);
P0 = 0x00;
}
}
void main()
{
init_timer();
while (1)
{
while(!Echo); //等待Trig发出
TR0 = 1; //开始计时
while(Echo); //当Trig发出时,Echo为高电平
TR0 = 0; //终止计时
count_distance();
}
}
//定时器 1 用来数码管显示数据和发射超声波信号
void timer1() interrupt 3
{
TR1 = 0; //终止定时
TH1 = 0xF8; //定时2ms
TL1 = 0xCD;
count ++;
display();
if(count>100) //每200ms启动一次超声波模块
{
count = 0;
//启动超声波模块
Trig = 1;
delay_10us(2);
Trig = 0;
}
TR1 = 1;
}
问题解答
Q:
为什么数码管不是显示完整的静态数?
A:
因为数码管显示扫描的速度过慢,只有当扫描的速度足够块,才能“欺骗”眼睛,也就是将延时的时间修改短一些。
如果想要数码管动态显示,只需要将delay_ms里面的时间修改为500即可。
Q:
为什么数码管不能实时更新显示数据,而是按一下RESET的键才能显示当前距离?
A:
解决的方法如下:将数码管要显示的数据赋值给数组,数组将数据进行短暂的存储,以至于数码管有数字可以显示,如果出现问题中的情况,很大原因是因为直接调用数码管的库函数进行显示
Q:
如何通过定时器得到测量距离?
A:
定时器0的初始值TH0和TL0同时设置为0x00,并且此时的TR0=0,也就是定时器还没开启。当Trig发送信号后,Echo开始接受高电平信号,此时开启TR0=1,当Echo恢复低电平时,TR0=0关闭定时器;此时可以得到TH0和TL0的值,将两者合并即可。
相关文章