这个是我的单片机期末大作业,本来设计了两个方案的,要是这个超声波测距做不出来就做一个多功能日历秒表计时系统,最后那个日历秒表计时系统的代码不小心没有保存,只留下了一个protues原理图,这里主要介绍的是我的超声波测距系统,主要是参考了很多其他资料最终做了一个超声波测距系统(也就是模拟了倒车雷达的功能)
软件上用的是protues8.6和Keil.C51.V9.01+win10
这里后面放一个资源链接吧
protues原理图是我绘制的,省略了晶振电路,但因为软件问题不具备仿真功能,只能描述大致的工作流程和原理电路
实物图如下:
当然还有我的原理说明:
本项目主要采用了HC-SR04超声波模块来进行距离的测定,该模块的使用功能较为简单,且测距精准度可以达到3mm,其基本的工作原理如下:
首先,该模块会有四个引脚,其实物图如下:
它们分别是Gnd(接地引脚)、Echo(回显引脚)、Trig(使能引脚)、Vcc(接高电平引脚)
当该模块的Tring引脚接受到维持了一定时间的高电平使能信号且VCC和GND线连接正确时,超声波模块将开始工作。首先,超声波发生器发射向前方发射一束超声波,当超声波接收器接受到超声波信号时,HC-SR04模块将利用Echo引脚发出一段高电平信号,高电平信号持续的时间就是超声波在空气中传播的时间。所以我在这里利用了中断的方式,首先给Tring引脚一个持续了十几个毫秒的高电平信号,当收到Echo引脚的信号时,开启计时器0并开始计时,知道Echo信号变为低电平,计算计时器所得时间,然后利用声音在空气中传播得速度大约为340m/s,将计时器所得时间除以2,再与声速相乘,得到一个较为精准的测距结果,最后将结果回显到数码管上。
同时我也从原理上简单的证明了误差的存在性,首先是超声波传播路径的计算
然后一个斜边与直角边的误差
但是实际上这个误差会很小,我也在实际中测定了大致的误差
可以看到实际上0.595m的距离显示的是0.58m,而实际上的1.591m的距离显示的是1.58m,误差范围在可接受的范围内,在写大作业报告的时候最好多次测量并拟合一下实际测量和测定结果间的误差,用一个图表的方式体现
源代码,这个是最后一次保存到的源码,内容可能和实物中的略有不符,但是大致功能是一样的
#include <reg51.h>
#include <intrins.h>
//数码管表示的数字 0 1 2 3 4 5 6 7 8 9
// 十进制 64, 568, 80, 354, 552, 353, 51, 564, 50, 352
unsigned char code display[]={0x28,0xee,0x32,0xa2,0xe4,0xa1,0x21,0xea,0x20,0xa0};
unsigned char dispbit[4]={0xff,0xff,0xff,0xff}; //0xff全部熄灭 共阳极数码管
/*
接口说明:
P1口:连接数码管的显示值(P1.0-P1.7)
P3.2 :HC-SR04的使能口:Trig
P3.3 : HC-SR04的数据回显口:Echo
P3.4 : 控制第一个数码管
P3.5 : 控制第二个数码管
P3.6 : 控制第三个数码管
P3.7 : 控制第四个数码管
P2.3 :蜂鸣器
*/
sbit led1 = P3^4;
sbit led2 = P3^5;
sbit led3 = P3^6;
sbit led4 = P3^7;
//测定距离
long distance;
//手动设定的距离
unsigned int set=50;
unsigned char flag_over_dis; //超声波超出量程
//测定的时间
unsigned int time0; // 65535
unsigned char menu; //菜单
//只有两个menu界面,一个用来显示当前的距离,另一个界面用来调整和显示报警距离,默认报警距离为0.5m
sbit sound_send = P3^2; //超声波
sbit sound_recive = P3^3;
sbit beep = P2^3; //蜂鸣器
P0 = P1 = P2 = P3 = 0xff; //初始化单片机IO口,实际使用P0口时可以不用上拉电阻
//延时大约为1ms的延时函数
void delay(unsigned int q)
{
unsigned int i,j;
for(i=0;i<q;i++)
for(j=0;j<120;j++);
}
//按键检测处理程序
unsigned char key_cur; //按键值
//处理按键程序
void key_with()
{
unsigned char key=0; //松手检测
unsigned char i;
unsigned int p=set;
// 0b11111110=254 0b11111101=253 0b111111011=251
if(P2==254 || P2==253 || P2==251) //按键按下
{
// delay(5); //消抖,这样消抖难以确定延时的时间
//第二种消抖方式
while(1){
delay(5);
if(!(P2==254 || P2==253 || P2==251)) //当按钮被按下,
{
key=1;
break;
}
}
if(key == 1)
{ //确认是按键按下
key = 0; //key=0 说明按键已按下
if(P2==251) //按下设置键
{
key_cur=1; //设置键
menu ++;
menu%=2; //menu的值为0或1,%2对2取余
}
if(P2==254)
{
if(menu==1) {
//设置报警
set -- ; //减1
if(set <= 1)
set = 1;
}
}
if(P2==253)
{
if(menu==1) {
//设置报警
set ++ ; //
if(set > 500)
set = 500;
}
}
}
}
//显示数据
for(i=0;i<3;i++)
{
dispbit[i]=display[p%10];
p/=10;
}
dispbit[2]|=0x7f; //显示小数点,共阳极
dispbit[3] = 0x60; //显示一个A
}
void clock()
{
if(distance <= set) //如果实际距离小于设定距离
{
//beep = 0; //蜂鸣器报警
beep=0;
delay(distance); //控制频率
beep=1;
delay(10);
}
else
{
beep = 1; //蜂鸣器两端接高,不报警
}
}
//选择显示函数,利用视觉暂留现象,每个数码管显示一定的很短暂的时间,视觉上看就像是同时显示的一样
void led_choice(unsigned char i)
{
if(i==0)
{
led1 = 0;
led2 = 1;
led3 = 1;
led4 = 1;
}
if(i==1)
{
led1 = 1;
led2 = 0;
led3 = 1;
led4 = 1;
}
if(i==2)
{
led1 = 1;
led2 = 1;
led3 = 0;
led4 = 1;
}
if(i==3)
{
led1 = 1;
led2 = 1;
led3 = 1;
led4 = 0;
}
}
//数据显示函数
void show()
{
static unsigned char i=0;
i++;
if(i >= 4)
i = 0;
led_choice(i);
if(i==2)
{
dispbit[2]|=0x7f;
}
P1 = dispbit[i];
}
//HC-SR04延时函数
void trig_delay()
{
_nop_(); //执行一条_nop_()指令就是1us
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
//测定距离
void send_wave()
{
sound_send = 1; //10us的高电平触发
trig_delay();
sound_send = 0;
TH0 = 0; //给定时器0清零
TL0 = 0;
TR0 = 1; //计时器启动
while(!sound_recive); //空语句,直到收到信号时退出循环
TR0=0; //计时器停止
while(sound_recive) //当sound_recive为1计数并等待
{
time0 = TH0 * 256 + TL0;
if((time0 > 60000)) //时间超出,显示3个888 65535
{
TR0 = 0;
flag_over_dis = 2;
distance = 888;
break ;
}
else
{
TR0=0; //关定时器0定时
distance =time0;
distance *= 0.017; //程序自动向高精度转换
if((distance > 100))
{
distance = 888;
}
}
}
}
//计时器1用来每隔一段时间显示距离,这个时间间隔不能太大
void time1_int() interrupt 3
{
TH1 = 0xf8; //0xf830=63536
//时间间隔 2000ns ,大致为 2 ms
TL1 = 0x30;
show();
}
//计时器、中断的初始化
void INT_init()
{
EA = 1; //开总中断
TMOD = 0X11; //定时器0、定时器1工作方式1
ET0 = 0; //关定时器0中断
TR0 = 1; //允许定时器0定时
ET1 = 1; //开定时器1中断
TR1 = 1; //允许定时器1定时
}
main()
{
unsigned char i=0;
beep=0; //蜂鸣器报警
delay(150);
beep=1; //蜂鸣器停止
INT_init(); //定时器初始化程序
while(1)
{
send_wave();
if(menu == 0)
{
for(i=0;i<3;i++)
{
dispbit[i]=display[distance%10];
distance/=10;
}
dispbit[2]|=0x7f; //生成小数点
dispbit[3]=0xff; //最后一个数码管熄灭
}
key_with();
delay(10);
}
}
零件在各个网购平台上都可以买到,有一整套的零件,不需要单独买,代码的话可以自己写然后烧进芯片中,也有些卖家会提供代码。
以上就是我的单片机大作业,所有内容仅供参考,希望能给大家带来好的思路和启发,抛砖引玉了,我的大作业报告写的不太行,就不展示了,需要的话留言吧,可能之后会补个链接