当前位置:文档之家› 基于单片机超声波测距系统设计实验报告-重

基于单片机超声波测距系统设计实验报告-重

指导教师评定成绩:审定成绩:自动化学院计算机控制技术课程设计报告设计题目:基于单片机的超声波测距系统设计单位(二级学院):学生姓名:专业:班级:学号:指导教师:负责项目:设计时间:二〇一四年五月自动化学院制目录一、设计题目 0基于51单片机的超声波测距系统设计 0设计要求 0摘要 (1)二、设计报告正文 (2)2.1 超声波测距原理 (2)2.2系统总体方案设计 (3)2.3主要元件选型及其结构 (4)2.4硬件实现及单元电路设计 (9)2.5系统的软件设计 (12)三、设计总结 (17)四、参考文献 (17)五、附录 (18)附录一:总体电路图 (18)附录二:系统源代码 (18)一、设计题目基于51单片机的超声波测距系统设计设计要求1、以51系列单片机为核心,控制超声波测距系统;2、测量范围为:2cm~4m,测量精度:1cm;3、通过键盘电路设置报警距离,测出的距离通过显示电路显示出来;4、当所测距离小于报警距离时,声光报警装置报警加以提示;5、设计出相应的电子电路和控制软件流程及源代码,并制作实物。

摘要超声波具有传播距离远、能量耗散少、指向性强等特点,在实际应用中常利用这些特点进行距离测量。

超声波测距具有非接触式、测量快速、计算简单、应用性强的特点,在汽车倒车雷达系统、液位测量等方面应用广泛。

本次课设利用超声波传播中距离与时间的关系为基本原理,以STC89C52单片机为核心进行控制及数据处理,通过外围电源、显示、键盘、声光报警等电路实现系统供电、测距显示、报警值设置及报警提示的功能。

软件部分采用了模块化的设计,由系统主程序及各功能部分的子程序组成。

超声波回波信号输入单片机,经单片机综合分析处理后实现其预定功能。

关键词:STC89C52单片机; HC-SR04;超声波测距二、设计报告正文2.1 超声波测距原理常用的超声测距的方法是回声探测法,超声波发射器向某一方向发射超声波,在发射时刻的同时计数器开始计时,超声波在空气中传播,途中碰到障碍物面阻挡就立即反射回来,超声波接收器收到反射回的超声波就立即停止计时。

设超声波在空气中的传播速度为340m/s (不计介质温度变化对速度的影响),根据计时器记录的时间t ,就可以计算出发射点距障碍物面的距离s ,即:s=340t/2。

如图2-1所示:超声波发射障碍物超声波接收图2-1 超声波的测距原理θcos S H = (2-1))(H L arctg =θ (2-2)式中: L —两探头中心之间距离的一半;又知道超声波传播的距离为:vt S =2 (2-3)式中: v —超声波在介质中的传播速度;t —超声波从发射到接收所需要的时间;将式2-1、2-2、2-3联立得:]cos[21H L arctg vt H = (2-4)其中,超声波的传播速度v 在一定的温度下是一个常数(例如在温度T=30度时,V=349m/s);当需要测量的距离H 远远大于L 时,上式变为: vt H 21= (2-5) 所以,只要需要测量出超声波传播的时间t,就可以得出测量的距离H.2.2系统总体方案设计本超声波测距系统由系统硬件电路及软件程序实现两部分构成。

其中由STC89C52单片机最小系统、HC-SR04超声波模块、电源接口电路、4位共阳极数码管显示电路、三极管驱动电路、蜂鸣器声光报警电路及键盘电路构成硬件系统。

以STC89C52单片机为核心,通过触发信号控制HC-SR04超声波测距模块发射超声波并接收回波,测算出前方障碍的距离,输入单片机进行运算,与预设报警距离比较后判断是否启动蜂鸣器声光报警装置。

根据系统功能要求及模块划分可绘制出系统硬件框图,如图2-2所示:图2-2 系统硬件框图2.3主要元件选型及其结构2.3.1 STC89C52芯片STC89C52是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash存储器。

工作电压:5.5V~3.3V。

STC89C52使用经典的MCS-51内核,但做了很多的改进使得芯片具有传统51单片机不具备的功能。

在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。

具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。

另外 STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。

空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。

掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。

最高运作频率35MHz,6T/12T可选。

其引脚图如图2-3所示:a引脚图b实物图图2-3 STC89C52引脚图2.3.2 HC-SR04超声波模块HC-SR04超声波模块具有性能稳定、测度距离精确、模块高精度、盲区小等特点,使用简单易操作,常用于距离测量。

其原理图及实物图如图2-4、图2-5所示:图2-4 HC-SR04超声波模块原理图图2-5 HC-SR04超声波模块实物图(1)接线方式:VCC(接电源)、Trig(控制端)、Echo(接收端)、GND(接地)(2)基本工作原理:a.采用I/O口TRIG触发测距,给至少10us的高电平信号;b.模块自动发送8个40kHz的方波,自动检测是否有信号返回;c.有信号返回,通过I/O口ECHO输出一个高电平,同时开始计时直到此口变为低电平,高电平持续的时间就是超声波从发射到返回的时间。

测试距离=(高电平时间*声速(340M/S))/2。

(3)电气参数表1 HC-SR04电气参数表(4)超声波时序图图2-6 超声波时序图(5)操作:初始化时将trig和echo端口都置低,首先向给trig发送至少10 us 的高电平脉冲(模块自动向外发送8个40kHz的方波),然后等待,捕捉echo 端输出上升沿,捕捉到上升沿的同时,打开定时器开始计时,再次等待捕捉echo 的下降沿,当捕捉到下降沿,读出计时器的时间,这就是超声波在空气中运行的时间,按照测试距离=(高电平时间*声速(340M/S))/2就可以算出超声波到障碍物的距离。

2.3.3 4位共阳数码管(1)共阳数码管的实物图、原理图如图2-7、图2-8所示:图2-7 4位共阳数码管实物图图2-8 4位共阳数码管原理图(2)工作原理:共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管。

共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮。

当某一字段的阴极为高电平时,相应字段就不亮。

(3)动态显示驱动:数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔划"a,b,c,d,e,f,g,dp"的同名端连在一起,另外为每个数码管的公共极COM增加位选通控制电路,位选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位就显示出字形,没有选通的数码管就不会亮。

通过分时轮流控制各个数码管的的COM端,就使各个数码管轮流受控显示,这就是动态驱动。

在轮流显示过程中,每位数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感。

2.4 硬件实现及单元电路设计(1)单片机最小系统单片机系统由电源、晶振电路、复位电路组成。

如图2-9所示:图2-9 单片机最小系统(2)电源接口电路设计电源部分的设计采用3节5号干电池4.5V供电,如图2-10所示:图2-10 电源接口电路(3)超声波模块接口HC-SR04超声波模块接口如图2-11所示:图2-11 HC-SR04超声波模块接口(4) 4位共阳极数码管显示电路及三极管驱动电路显示电路如图2-12所示:图2-12 4位共阳数码管显示电路当I/O口输出低电平时,相应段被选通,反之则不然。

三极管驱动电路如图2-13所示:图2-13 三极管驱动电路当I/O口输出低电平时,相应位被选通,反之则不然。

(5)声光报警电路的设计声光报警电路如图2-14所示:图2-14 声光报警电路声光报警电路由一个蜂鸣器、一个三极管、一个发光二极管、两个电阻构成。

其中电阻起限流的作用,当I/O口输出低电平时,三极管饱和导通,蜂鸣器报警、LED亮,反之则不报警。

(6)键盘电路的设计键盘电路如图2-15所示:图2-15 键盘电路2.5系统的软件设计(1)各主要模块①超声波测距模块。

给超声波Trig口至少10us的高电平,启动测量,定时器T0计时,通过计算测得距离。

②显示模块。

包括数码管位选函数、段选函数及距离处理显示模块。

将超声波测距测量值、报警设定值显示在4位数码管上。

③键盘模块。

由键盘检测函数及键盘处理函数组成。

有设定键、加键、减键、复位键、开关键。

主要设置报警值。

④声光报警模块。

将测量值与设定报警值比较,若小于设定值,报警。

⑤特殊存储器eepom模块。

包括单片机eepom存储器读、写操作以及初始化。

其内存储设定报警值,掉电数据不丢失。

⑥定时器模块。

TO定时器用于超声波测距的计时。

T1定时器用于主程序扫描时间的控制。

(2)主程序源代码void main(){send_wave(); //测距离函数smg_display(); //处理距离显示函数time_init(); //定时器初始化init_eepom(); //初始化eepom(读取set_d)while(1){if(flag_300ms == 1) //300ms执行一次{flag_300ms = 0;clock_h_l(); //报警函数send_wave(); //测距离函数if(menu_1 == 0) //没有键按下时才给缓冲数组赋新值smg_display(); //处理距离显示函数if(zd_break_en == 1) //自动退出设置界面程序{zd_break_value ++; //每300ms加一次if(zd_break_value > 100) //30秒后自动退出设置界面{menu_1 = 0;smg_i = 3;zd_break_en = 0;zd_break_value = 0;}}}key(); //按键检测函数if(key_can < 4){key_with(); //按键处理函数,修改报警设定值}}}(3)主程序工作流程图图2-16 主程序流程图(4)超声波探测程序流程图图2-17 超声波探测程序流程图三、设计总结四、参考文献[1] C程序设计(第三版). 谭浩强 . 清华大学出版社 .[2] 新概念51单片机c语言教程 . 郭天祥 . 电子工业出版社[3] 传感器与检测技术 . 胡向东 . 机械工业出版社[4] 微控制其原理及应用 . 向敏 . 人民邮电出版社五、附录附录一:系统总体电路图图5-1 超声波探测程序流程图附录二:系统软件源代码/*****************************************************课设名称:基于51单片机的超声波测距系统设计*硬件平台: 超声波模块+51最小系统*显示模块:4个数码管*输入模块:3个按键*实现的功能:用超声波模块把距离测量出来,用数码管显示,可通过按键设置要报警的距离,低于设置* 的值则自动报警,一直按住调值的键会越加越快,超出量程(3.8m)则显示888 *接口说明:数码管位P3^4 P3^5 P3^6 P3^7* 超声波发射=>P3^2* 超声波接收=>P3^3按键用的接口是P2口*待改进的地方:温度补偿,提高精度*当前的缺陷:不能测出4m的距离*测量单位:米(m)****************************************************/#include <reg52.h>#include <intrins.h>#include <string.h>#include <eepom52.h>#define uchar unsigned char#define uint unsigned int//数码管段选定义设0 1 2 3 4 5 6 7 8 9uchar code smg_duan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管位选uchar dis_smg[4] ={0,1,2,3};sbit smg_we1 = P3^4; //数码管位选端口sbit smg_we2 = P3^5;sbit smg_we3 = P3^6;sbit smg_we4 = P3^7;sbit c_send = P3^1; //超声波发射sbit c_recive = P3^0; //超声波接收uchar flag_hc_value; //超声波中间变量sbit beep = P2^3; //蜂鸣器IO口定义uchar smg_i = 3; //显示数码管的个数:3bit flag_300ms ; //主程序300ms处理一次的标识符bit key_500ms ; //按键程序500ms处理一次的标识符long distance; //定义测量距离uint set_d; //定义设定距离uchar flag_csb_juli; //超声波超出量程long flag_time0;//按键的IO变量的定义uchar key_can; //按键值的变量uchar zd_break_en,zd_break_value; //自动退出设置界面uchar menu_ljsd = 10; //用来控制连加的速度bit flag_lj_en; //按键连加使能bit flag_lj_3_en; //按键连3次连加后使能加的数就越大了uchar key_time; //定时器用,作为连加的中间变量,按键时间uchar flag_value; //定时器用,作为连加的中间变量uchar menu_1; //菜单设计的变量uchar a_a; //设定值写入单片机标志符/***********************数码管位选函数*****************************/ void smg_we_switch(uchar i){switch(i){case 3: smg_we1 = 0; smg_we2 = 1; smg_we3 = 1; smg_we4 = 1; break;case 2: smg_we1 = 1; smg_we2 = 0; smg_we3 = 1; smg_we4 = 1; break;case 1: smg_we1 = 1; smg_we2 = 1; smg_we3 = 0; smg_we4 = 1; break;case 0: smg_we1 = 1; smg_we2 = 1; smg_we3 = 1; smg_we4 = 0; break;}}/***********************数码管显示函数*****************************/ void display(){static uchar i;i++;if(i >= smg_i) //smg_i=3,i = 0;smg_we_switch(i); //调用位选函数P1 = dis_smg[i]; //段选}/******************把数据保存到单片机内部eepom中******************/void write_eepom(){SectorErase(0x2000);byte_write(0x2000, set_d % 256); //写入set_d值byte_write(0x2001, set_d / 256);byte_write(0x2058, a_a); //a_a标识符}/******************把数据从单片机内部eepom中读出来*****************/void read_eepom(){set_d = byte_read(0x2001); //读出set_d值set_d <<= 8;set_d |= byte_read(0x2000);a_a = byte_read(0x2058);}/******************开机自检eepom初始化****************************/void init_eepom(){read_eepom(); //先读if(a_a != 1) //新的单片机初始单片机内问EEPOM{set_d = 100;a_a = 1;write_eepom();}}/****************独立按键检测函数********************/void key(){static uchar key_new = 0,key_old = 0,key_value = 0;//key_new、key_old 按键标识符,key_new=0表示有键瞬间按下,//检测确认按键后,key_old=1. key_value按键检测中间变量if(key_new == 0) //初始有键按下{if((P2 & 0x07) == 0x07) //松手检测(5次)key_value ++;elsekey_value = 0;if(key_value >= 5) //确认无键按下{key_value = 0;key_new = 1; //置位key_new,表初始无键按下flag_lj_en = 0; //关闭连加的使能flag_lj_3_en = 0; //关闭3秒后连加的使能flag_value = 0; //连加变量清零key_time = 0;write_eepom(); //值(set_d)写入单片机}}else //初始无键按下{if((P2 & 0x07) != 0x07) //按键检测(5次)key_value ++;elsekey_value = 0;if(key_value >= 5) //确认按键{key_value = 0;key_new = 0;flag_lj_en = 1; //连加使能zd_break_en = 1; //自动退出设置界使能zd_break_value = 0; //自动退出设置界变量清零,30秒后退出设置界面}}key_can = 20;if(key_500ms == 1) //连按500ms,启动连加{key_500ms = 0;key_new = 0;key_old = 1;zd_break_value = 0; //自动退出设置界变量清零,30秒后退出设置界面}if((key_new == 0) && (key_old == 1)) //确认有键按下{switch(P2 & 0x07){case 0x06: key_can = 1; break; //得到k2键值(设定键)case 0x05: key_can = 2; break; //得到k3键值(加)case 0x03: key_can = 3; break; //得到k4键值(减)}}key_old = key_new; //初始化标识符}/*******************按键处理数函数***************************/void key_with(){if(key_can == 1) //得到k2键值(设定键){menu_1 ++;if(menu_1 >= 2){menu_1 = 0;}if(menu_1 == 0) //退出设定界面{menu_ljsd = 10; //连加速度控制变量(复位为500ms)dis_smg[0] = smg_duan[distance % 10]; //测量值显示用dis_smg[1] = smg_duan[distance / 10 % 10] ;dis_smg[2] = smg_duan[distance / 100 % 10] & 0x7f;smg_i = 3;}if(menu_1 == 1) //设置界面{menu_ljsd = 1; //连加速度变量(50ms)dis_smg[0] = smg_duan[set_d % 10]; //设定值显示用dis_smg[1] = smg_duan[set_d / 10 % 10];dis_smg[2] = smg_duan[set_d / 100 % 10] & 0x7f ;dis_smg[3] = 0x88;smg_i = 4; //A,设定值修改标识符}}if(menu_1 == 1) //设置报警值{if(flag_lj_3_en == 0) //三次连加之后速度加快menu_ljsd = 10 ; //500ms 加减一次elsemenu_ljsd = 1; //50ms 加减一次if(key_can == 2) //得到k3键值(加){set_d ++ ;if(set_d > 350)set_d = 350;dis_smg[0] = smg_duan[set_d % 10]; //设定值显示dis_smg[1] = smg_duan[set_d / 10 % 10] ;dis_smg[2] = smg_duan[set_d / 100 % 10] & 0x7f;dis_smg[3] = 0x88;}if(key_can == 3) //得到k4键值(减){set_d -- ;if(set_d <= 1)set_d = 1;dis_smg[0] = smg_duan[set_d % 10]; //设定值显示dis_smg[1] = smg_duan[set_d / 10 % 10] ;dis_smg[2] = smg_duan[set_d / 100 % 10] & 0x7f ;dis_smg[3] = 0x88; //a}}}/*********************定时器0、定时器1初始化******************/void time_init(){EA = 1; //开总中断TMOD = 0X11; //定时器0、定时器1工作方式1ET0 = 1; //开定时器0中断TR0 = 1; //允许定时器0定时ET1 = 1; //开定时器1中断TR1 = 1; //允许定时器1定时}/****************延迟函数(10us,超声波发射需要)********************/void delay(){int i=10;for(i;i>=0;i--){_nop_(); //执行一条_nop_()指令就是1us}}/*********************超声波测距程序*****************************/void send_wave(){long temp = 888;c_send = 1; //10us的高电平触发delay();c_send = 0;TH0 = 0; //给定时器0清零TL0 = 0;TR0 = 0; //关定时器0定时flag_hc_value = 0;while(!c_recive); //当c_recive为零时等待TR0=1;while(c_recive) //当c_recive为1计数并等待{flag_time0 = TH0 * 256 + TL0;if((flag_hc_value > 1) || (flag_time0 > 21000)) //当超声波超过测量范围时,显示3个888{TR0 = 0;flag_csb_juli = 2;temp = 888;flag_hc_value = 0;break ;}else{flag_csb_juli = 1;}}if(flag_csb_juli == 1) //距离处理{TR0=0; //关定时器0定时EA = 0;temp = TH0; //读出定时器0的时间temp = temp * 256 + TL0;temp /= 59; //HC-SR04超声波模块距离(厘米)=T*uS/58.823EA = 1;if(temp > 380) //如果大于3.8m就超出超声波的量程{temp = 888;}}EA = 0;distance = temp; //距离EA = 1;}/****************冒泡排序(最大值沉底)**************************/int iBuff[5];void choise(int *a,int n) //选择法排序{int i,j,k,temp;for(i=0;i<n-1;i++) {k=i; //给记号赋值for(j=i+1;j<n;j++)if(a[k]>a[j]) k=j; //是k总是指向最小元素*/if(i!=k) { //当k!=i是才交换,否则a[i]即为最小temp=a[i];a[i]=a[k];a[k]=temp;}}}/*******************测量距离处理及显示函数**********************/void smg_display(){int Buff[5];char i;if(distance == 95)return; //95去掉iBuff[4] = iBuff[3];iBuff[3] = iBuff[2];iBuff[2] = iBuff[1];iBuff[1] = iBuff[0];iBuff[0] = (int)distance;for(i = 0; i<5; i++)Buff[i] = iBuff[i];choise(Buff,5); //调用choise函数,冒泡排序distance = (long)Buff[2]; //取得排序后5值的中间值,以消弱误触,稳定测量结果EA = 0; //关中断dis_smg[0] = smg_duan[distance % 10]; //取百分位(厘米级)dis_smg[1] = smg_duan[distance / 10 % 10]; //取十分位(分米级)dis_smg[2] = smg_duan[distance / 100 % 10] & 0x7f; //取个位(米级)EA = 1; //开中断}/*********************报警函数****************************************/void clock_h_l(){static uchar value;if(distance <= set_d){value ++; //多次检测,消除实际距离在设定距离左右变化时的干扰if(value >= 5){beep = ~beep; //蜂鸣器报警}}else{value = 0;beep = 1; //取消报警}}void main(){send_wave(); //测距离函数smg_display(); //处理距离显示函数time_init(); //定时器初始化init_eepom(); //初始化eepom(读取set_d)while(1){if(flag_300ms == 1) //300ms执行一次{flag_300ms = 0;clock_h_l(); //报警函数send_wave(); //测距离函数if(menu_1 == 0) //没有键按下时才给缓冲数组赋新值smg_display(); //处理距离显示函数if(zd_break_en == 1) //自动退出设置界面程序{zd_break_value ++; //每300ms加一次if(zd_break_value > 100) //30秒后自动退出设置界面{menu_1 = 0;smg_i = 3;zd_break_en = 0;zd_break_value = 0;}}}key(); //按键函数if(key_can < 4){key_with(); //按键处理函数}}}/************定时器0中断服务程序用做超声波测距的******************/ void time0_int() interrupt 1{}/**************定时器1中断服务程序,用作主程序********************/ void time1_int() interrupt 3{static uchar value;TH1 = 0xf8;TL1 = 0x30; //定时2msdisplay(); //数码管显示函数value++;if(value >= 150) //300ms中断一次{value = 0;flag_300ms = 1;}if(value % 25 == 0){if(flag_lj_en == 1) //按下按键使能50ms{key_time ++;if(key_time >= menu_ljsd) //500ms{key_time = 0;key_500ms = 1; //500msflag_value ++;if(flag_value >= 3){flag_value = 10;flag_lj_3_en = 1; //3次后1.5秒后连加大些}}}}}。

相关主题