本代码基于QH - 5A平台,测试通过,适用于51系列单片机平台,不同的型号只需要移植一下即可,SR04超声波模块是一个精度较高的测距模块,本人测试精度1cm,模块可直接与开发板连接,具体连接请参考本贴下面的内容,连接模块时一定要断电连接,不要带电操作,容易损坏并且工作可能不正常。模块实物如下图所示:

开发板图片:
1、SR04模块主要技术参数:
1.使用电压:DC5V
2.静态电流:小于2mA
3:电平输出:高5V
4:电平输出:低0V
5:感应角度:不大于15度
6:探测距离:2cm-450cm
7:高精度:可达3mm
2、接线方式:VCC、trig(控制端)、 echo(接收端)、 GND地线(若采用QH-5A开发板直接插上即可)
3、使用方法: 一个控制口trig发一个10US以上的高电平,就可以在接收口echo等待高电平输出.一有输出就可以开定时器计时,当echo此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,方可算出距离.如此不断的周期测,就可以达到你移动测量的值了~~
4、模块工作原理:
(1)采用IO触发测距,给至少10us的高电平信号;
(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2或距离=(331.4+0.61*当前温度)*定时器时间/2000000 CM;
5、程序功能:
本程序是采用第二公式编写的,显然有温度矫正的超声波测距更加准确,同时本程序还带有内部存储功能,可设定报警距离,程序有详细注释
水平有限,本程序只供学习,欢迎大家一起交流
单片机源程序如下:
- /*-----------------------------------------------
- 说明:
- 功能:超声波测距,DS18b20矫正;数码管显示
- 晶振:12MHz
- 测量范围:1CM - 500CM
- 温度显示:0.0 C - 99.9 C
- 警报范围设置:5CM - 400CM(可以永久存储设定值)
- ------------------------------------------------*/
- #include "reg52.h" //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
- #include "18b20.h"
- #include "eeprom.h"
- #include "delay.h"
- #define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P1 替换
- sbit DUAN=P2^6;//定义锁存使能端口 段锁存
- sbit WEI=P2^7;// 位锁存
- /***************超声波引脚定义******************/
- sbit Echo = P3 ^ 3; //回波引脚
- sbit Trig = P1 ^ 5; //触发引脚
- sbit buzzer = P1 ^ 0; //蜂鸣器引脚
- /*****************按键定义**********************/
- uchar bdata key,key1,lastkey;
- bit key1Mark;//设置键标志
- /*****************测距变量**********************/
- uchar EchoTimeH,EchoTimeL; //自定义寄存器存储8位回波时间
- uint Distance,EchoTime; //测量距离,回波总时间
- uint Distance_Alarm; //报警距离通过自己设定(初始为0)
- bit succeed_flag; //测量成功标志
- uchar code Table[18] = //段码表
- {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9
- uchar code WeiMa[4]={0xfe,0xfd,0xfb,0xf7}; //分别对应相应的数码管点亮,即位码
- uint Temperature,temp;//读取温度
- bit flag200ms,flag300ms;//获取时间标志
- /*****************显示变量**********************/
- uint DispData;
- uchar TempData[4]; //存储显示值的全局变量
- uchar mod;//显示模式切换
- /*****************函数声明**********************/
- void delay_20us(); //20us延迟
- void CountDat(uint ShowData); //显示数据处理
- void readkey(); //按键读取
- void CountKey(); //显示散转
- void CSBFunction(); //超声波测距
- void Display(); //数码管显示函数
- void Init_Timer0(void); //定时器0初始化
- /*------------------------------------------------
- 主函数
- ------------------------------------------------*/
- void main (void)
- {
- float speed = 0;
- buzzer=1; //初始化蜂鸣器引脚
- Trig=0; //首先拉低脉冲输入引脚
- TMOD|=0x11; //定时器0,定时器1,16位工作方式
- IT1=0; //低电平触发外部中断
- EX1=0; //关闭外部中断
- Init_Timer0();
- ISP_IAP_readData(0x2ff0,ReadBuf,2);
- Distance_Alarm = ReadBuf[0] | (ReadBuf[1] << 8);//读取警报距离值
- while (1) //主循环
- {
- CSBFunction(); //开始测距
- if(succeed_flag)
- {
- succeed_flag=0; //清测量成功标志
- EchoTime = (EchoTimeH << 8) | EchoTimeL; //与低8位合并成为16位结果数据
- //公式说明: 1、V=(331.4+0.61*T)*D/2000000 CM;2、回波时间D是us单位,最终
- //距离以CM单位要除以20000,这里为了减小计算量转成uchar,先/200,再/100;
- speed = (331.4 + 0.61 * (TempData[0]*10+TempData[1])) / 200;
- Distance = (EchoTime * speed) / 100; //算出来是CM
- CountDat(DispData);//计算需要显示数据的各个位
- }
- if(mod != 2)
- readkey();//按键读取,警报时显示温度不能设定
- CountKey();//报警距离设置
- if(flag200ms)
- {
- flag200ms = 0;
- temp = ReadTemperature();//
- Temperature = temp * 6;//小数近似处理,采用中间变量temp是防止中断导致最终温度值异常
- if(Distance < Distance_Alarm)
- {
- buzzer = 0;mod = 2;
- }
- else
- {
- buzzer = 1;
- if(!key1Mark)
- mod = 0;
- }
- } //蜂鸣器产生300Hz频率
- if(flag300ms)
- {
- flag300ms = 0;
- if(Distance < Distance_Alarm)
- {
- buzzer = 1;
- }
- }
- }
- }
- /*------------------------------------------------
-
- 显示函数,用于动态扫描数码管
- ------------------------------------------------*/
- void Display()
- {
- static unsigned char i=0;
- DataPort=0; //清空数据,防止有交替重影
- DUAN=1; //段锁存
- DUAN=0;
-
- DataPort=WeiMa[i]; //取位码
- WEI=1; //位锁存
- WEI=0;
- if((i == 1) && (mod == 2))
- {
- DataPort = Table[TempData[i]] & 0xef;//温度显示点
- }
- else
- {
- DataPort = Table[TempData[i]] ; //取显示数据,段码
- }
- DUAN=1; //段锁存
- DUAN=0;
-
- i ++;
- if(i == 4)
- i = 0;
- }
- //******************************************************************
- //20us短延时
- void delay_20us()
- {
- uchar bt;
- for(bt=0;bt<20;bt++);
- }
- /*
- 处理需要显示的数据
- 入口参数:ShowData
- */
- void CountDat(uint ShowData)
- {
- EA=0;
- TempData[0] = ShowData / 1000 % 10;
- TempData[1] = ShowData / 100 % 10;
- TempData[2] = ShowData / 10 % 10;
- TempData[3] = ShowData % 10;
- EA=1;
- }
- /*扫描K1 - K3*/
- void readkey()
- {
- static uchar keycnt = 0;
- uchar R0,R1;
- P3 |= 0x07; //51单片机作为输入时先置相应位位1
- R0 = (P3 ^ 0x07) & 0x07; //将键值转换成正逻辑
- keycnt ++;
- if(R0)
- {
- if(keycnt > 1) //用做延迟,根据MCU速度进行调整
- {
- keycnt = 0;
- key1 = R0;
- }
- else
- {
- key1 = key;
- }
- }
- else
- {
- key1 = 0; //无按键按下都为0
- keycnt = 0;
- }
- R1 = key1;
- key1 = key1 & (key ^ key1);//key^key1判断键值有0变1,或1变0;再&key1若key1不为0则有按键按下(由0变1)
- key = R1;
- }
- /*读取按键后,根据键值处理数据*/
- void CountKey()
- {
- switch(key1)
- {
- case 0x01:if(!key1Mark){mod = 1;key1Mark = 1;}
- else
- {
- mod = 0;key1Mark = 0;
- WriteBuf[0] = Distance_Alarm & 0xff; WriteBuf[1] = (Distance_Alarm >> 8) & 0xff;
- ISP_IAP_sectorErase(0x2e00);//扇区擦除,一块512字节
- ISP_IAP_writeData(0x2ff0,WriteBuf,2); //写警报值到 EEPROM
- }
- break;
- case 0x02:if(mod == 1){Distance_Alarm += 5;if(Distance_Alarm > 400)Distance_Alarm=400;}
- break;
- case 0x04:if(mod == 1){Distance_Alarm -= 5;if(Distance_Alarm < 5)Distance_Alarm=5;}
- break;
- default : break;
- }
- switch(0) //数据显示模式散转
- {
- case 0:DispData = Distance; //正常默认下显示测得的距离
- break;
- case 1:DispData = Distance_Alarm; //设置模式下显示警报距离
- break;
- case 2:DispData = Temperature; //警报下显示当前温度值
- break;
- default : break;
- }
- }
- /*超声波测距*/
- void CSBFunction()
- {
- EA=0;
- Trig=1;
- delay_20us();
- Trig=0; //产生一个20us的脉冲,在Trig引脚
- while(Echo==0); //等待Echo回波引脚变高电平,高电平持续的时间就是超声波从发射到返回的时间
- {
- EX1=1; //打开外部中断
- TH1=0; //定时器1清零
- TL1=0; //定时器1清零
- TF1=0;
- TR1=1; //启动定时器1
- EA=1;
- }
- while(TH1 < 255);//等待测量的结果,周期65.535毫秒(可用中断实现),在这段时间内等待外部中断
- {
- TR1=0; //关闭定时器1
- EX1=0; //关闭外部中断
- }
- }
- /*------------------------------------------------
- 定时器初始化子程序
- ------------------------------------------------*/
- void Init_Timer0(void)
- {
- TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
- TH0=(65536-2000)/256; //给定初值 2ms
- TL0=(65536-2000)%256;
- EA=1; //总中断打开
- ET0=1; //定时器中断打开
- TR0=1; //定时器开关打开
- }
- /*------------------------------------------------
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
eeprom超声波.rar
(57.28 KB, 下载次数: 41)
|