4.9 (HC-SR04)超声波测距模块
4.9.1 超声波模块实物图
实验板上没有超声波测距模块,这里采用外接模块的形式使用。
超声波模块GPIO口功能介绍:
(1)、VCC供5V 电源
(2)、GND 为地线
(3)、TRIG 触发控制信号输入
(4)、ECHO 回响信号输出
4.9.2 超声波模块功能与工作原理介绍
HC-SR04 超声波测距模块可提供 2cm-400cm 的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、 接收器与控制电路。
基本工作原理:
(1)、单片机控制超声波的TRIG 口至少给10us的高电平信号,触发测距;
(2)、模块会自动发送8个 40khz 的方波, 并自动检测是否有信号返回;
(3)、有信号返回, 模块会通过 ECHO 口输出一个高电平, 高电平持续的时间就是超声波从发射到返回的时间。 公式:uS/58=厘米 或者 uS/148=英寸 或是 距离=高电平时间*声速(340M/S)
以上时序图表明,单片机只需要提供一个 10uS 以上脉冲触发信号, 该模块内部将发出 8 个 40kHz 周期电平并检测回波,模块一旦检测到有回波信号则输出回响信号,回响信号的脉冲宽度与所测的距离成正比。
由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。
公式: uS/58=厘米或者 uS/148=英寸; 或 距离=高电平时间*声速(340M/S) /2;
建议测量周期为 60ms 以上, 以防止发射信号对回响信号的影响。
4.9.3 超声波测距示例代码
当前使用的实验板上没有超声波模块,当前采用外接模块的形式与实验板进行连接。
超声波模块型号是:HC-SR04。
由于当前51单片机(STC90C51)的中断没法配置成上升沿触发,主程序里采用阻塞判断的方式等待测距结束,使用定时器0记录经过的时间,定时器0开启了溢出中断,在中断里使用变量记录中断溢出的次数。当测距结束时,通过定时器的溢出次数和当前定时器的值得到记录的时间,计算测量的距离,最终将测量的距离通过串口打印到电脑终端查看。
(当前使用的测距模块最大测量的距离是4米,16位定时器完全足够计数,可以不用开启定时器溢出中断,下面程序设计的思路比较通用,如果其他测距模块测量的距离更加远,也可以使用)
(硬件平台说明:CPU是STC90C516RD 、晶振频率12MHZ 、工作在12T模式下、一个机器周期为1us时间)
示例代码:
#include <reg51.h> sbit ECHO=P1^0; //超声波的回响信号输出脚 sbit TRIG=P1^1; //触发超声波测距的引脚 u32 timt0_cnt=0; //记录定时器0溢出的次数 u16 time_val=0; float distance=0.0; //保存测量的距离 void Timer0_16bit_Init(u16 us); void DelayMs(u32 ms); void delay20us(void); int main() { ECHO=0; TRIG=0; UART_Init(); //初始化串口波特率为4800 while(1) { TRIG=1;//触发测距 delay20us(); //延时20us TRIG=0; //停止触发 while(ECHO==0){} //等待回响信号返回 Timer0_16bit_Init(65535); //初始化定时器0,并开始计数 while(ECHO==1){} //等待回响信号结束 TR0=0; //关闭定时器0 time_val=(TH0<<8|TL0)+timt0_cnt*65535; //计算时间 distance=time_val/58.0; //得到距离。单位是厘米 printf("distance=%f CM\r\n",distance); timt0_cnt=0; //溢出次数清零 DelayMs(1000); //延时1秒 } } u16 T0_Update_data;//定时器0的初始值 void Timer0_16bit_Init(u16 us) { //当前实验板上的晶振实际频率为: 12MHZ u16 val=us/(12/12); //得到计数的时间,只要整数部分 T0_Update_data=65535-val; //得到重装载值 TMOD&=0xF0; //清除配置 TMOD|=0x01; //配置定时器0工作在16位定时器模式 TH0=T0_Update_data>>8; //定时器0高位重装值 TL0=T0_Update_data; //定时器0低位重装值 TR0=1; //开启定时器0 } extern timt0_cnt; //记录定时器0的溢出次数 //定时器0的重装值更新函数 void Timer0_Update(void) { TH0=T0_Update_data>>8; //定时器0高位重装值 TL0=T0_Update_data; //定时器0低位重装值 timt0_cnt++; //记录定时器0的溢出次数 } void DelayMs(u32 ms) { u32 i; u8 a,b; for(i=0;i<ms;i++) { for(b=199;b>0;b--) for(a=1;a>0;a--); } } void delay20us(void) //误差 0us { unsigned char a,b; for(b=1;b>0;b--) for(a=7;a>0;a--); }