分享

HC

 lixinhecom 2016-06-14

HC-SR04 是最常见的用于单片机的超声波测距模块。

我拿到手后,研究了一番,改进了厂方提供的代码,重新整理成一个函数库。

如果最近你也在研究的话,可以参考一下。测距速度很快。调用也很方便,使用T0计数器。

并且采用串口方式将测距结果传回下位机。



代码部分,首先是接口管脚配置UltrasonicDistanceConfig.h

  1. #ifndef  __ULTRASONIC_DISTANCE_CONFIG_H__  
  2. #define  __ULTRASONIC_DISTANCE_CONFIG_H__  
  3. #include <reg52.h>  
  4. //***************************************************//  
  5. //        HC-SR04 超声波测距模块配置文件             //  
  6. //---------------------------------------------------//  
  7. // 晶振:11.0592                                      //  
  8. // Create Date:2011-09-27  User:JerryLi              //  
  9. // email:lijian@dzs.mobi                             //  
  10. // 工作时将会占用 T0 计数器                          //  
  11. // HC-SR04 的探测精度范围为 2cm-400cm                //   
  12. // 在当前晶振工作频率下,一次有效测距需要23.42ms     //    
  13. //---------------------------------------------------//  
  14. #define DOUBLE_CRYSTAL_FREQ 11.0592 //晶振频率(单位M)(11.94477)  
  15. /** 
  16.  *管脚硬件连接配置 
  17.  * Echo回波引脚为 RX 
  18.  * Trig触发信号控制端 TX 
  19. */  
  20. sbit RX =P1^1; //Echo回波引脚  
  21. sbit TX =P1^2; //Trig触发信号控制端      
  22. #endif  

其次为函数库头文件UltrasonicDistanceDriver.h

  1. #ifndef  __ULTRASONIC_DISTANCE_DRIVER_H__  
  2. #define  __ULTRASONIC_DISTANCE_DRIVER_H__  
  3. #include <reg52.h>  
  4. //***************************************************//  
  5. //        HC-SR04 超声波测距模块操作库               //  
  6. //---------------------------------------------------//  
  7. // 晶振:11.0592                                      //  
  8. // Create Date:2011-09-27  User:JerryLi              //  
  9. // email:lijian@dzs.mobi                             //  
  10. // 工作时将会占用 T0 计数器                          //  
  11. // HC-SR04 的探测精度范围为 2cm-400cm                //   
  12. // 在当前晶振工作频率下,一次有效测距需要23.42ms     //   
  13. //---------------------------------------------------//  
  14.   
  15. /*------------------------------------------------------- 
  16.  *超声波测距模块初始化函数 
  17.  *@return void 
  18.  *-------------------------------------------------------*/  
  19. extern void InitUltrasonicDistance(void);  
  20.   
  21. /*------------------------------------------------------- 
  22.  *获取最近一次测得的距离 
  23.  *  注意:每次成功测距,需要耗时100ms-150ms左右时间 
  24.  *-------------------------------------------------------*/  
  25. extern unsigned int getDistance(void);  
  26.   
  27. /*------------------------------------------------------- 
  28.  *获取最近一次的测距状态 
  29.  *@return unsigned int 0:正常 / 1:(err)距离太近 /2:(err)超量程 
  30.  *-------------------------------------------------------*/  
  31. extern unsigned int getDistanceState(void);  
  32.   
  33. /*------------------------------------------------------- 
  34.  *检查距离操作(将测得的距离保存在公共变量中) 
  35.  *  备注:本函数调用完成后,需要通过getDistance()或getDistanceState()获得结果 
  36.  *  注意:每次成功测距,需要耗时100ms-150ms左右时间 
  37.  * @return 0:完成测距操作 / 1:正在延迟等待下次测距的开始 
  38.  *-------------------------------------------------------*/  
  39. extern unsigned char refreshDistance(void);  
  40. #endif  
  41.   
  42. /*使用方式: 
  43. #include "SerialComm.h" //串口通讯操作类 
  44. void main(void) 
  45.     uchar pcOutBuf[30]; 
  46.     uint iOld=0; 
  47.  
  48.     InitUltrasonicDistance(); 
  49.     InitSerialComm(); 
  50.     while(1) 
  51.     {    
  52.         //当调用测距函数后,返回为0,表示测距成功,否则测距函数正在延迟中 
  53.         if (0 == refreshDistance()) 
  54.         { 
  55.             //当取值有效时,如果与前次值没变化,则不作更新 
  56.             if (0 == getDistanceState() && (iOld != getDistance())) 
  57.             { 
  58.                 iOld = getDistance(); 
  59.                 sprintf(pcOutBuf, "S=%d\r\n", iOld); 
  60.                 SerialSendStr(pcOutBuf); //送到串口          
  61.             } 
  62.         }    
  63.     } 
  64. */  

最后是函数库文件UltrasonicDistanceDriver.c

  1. #include <reg52.h>        //包函8051内部资源的定义  
  2. #include <intrins.h>  
  3. #include "UltrasonicDistanceDriver.h"  
  4. #include "UltrasonicDistanceConfig.h"  
  5. //***************************************************//  
  6. //        HC-SR04 超声波测距模块操作库               //  
  7. //---------------------------------------------------//  
  8. // 晶振:11.0592                                      //  
  9. // Create Date:2011-09-27  User:JerryLi              //  
  10. // email:lijian@dzs.mobi                             //  
  11. // 工作时将会占用 T0 计数器                          //  
  12. // HC-SR04 的探测精度范围为 2cm-400cm                //   
  13. // 在当前晶振工作频率下,一次有效测距需要23.42ms     //   
  14. //---------------------------------------------------//  
  15. #define uchar unsigned char  
  16. /*1m所需周期:1000mm/(1微秒的声波距离mm * 1周期的us时间) => 1000/(0.17*1.0851); 
  17.  *4m = 1000/(0.17*1.0851) * 4 = 21684 
  18.  */  
  19. #define iMAX_LEN 21684  
  20. #define iMIN_LEN 109  
  21.   
  22. unsigned int miDistance=0; //测距的距离值  
  23. uchar mcDistanceErr=0; //测距错误标记(0:正常 / 1:距离太近 /2:超量程)  
  24. bit mbDelayOverFlg = 1; //延迟程序的控制标记(默认为延迟结束否则无法进入refreshDistance()函数)  
  25. uchar mbDelay10H, mbDelay10L; //测距的小单位时间延迟  
  26. /*------------------------------------------------------- 
  27.  *超声波测距模块初始化函数 
  28.  *@return void 
  29.  *-------------------------------------------------------*/  
  30. void InitUltrasonicDistance(void)  
  31. {  
  32.     unsigned int iTmp;  
  33.   
  34.     TMOD |=0x01; //设T0为方式1,GATE=1;  
  35.     //T0计数器初始化  
  36.     TH0=0; //高位置0  
  37.     TL0=0; //低位置0  
  38.     TR0=0; //开始前先关闭计数器  
  39.     ET0=1; //允许T0中断  
  40.     EA=1; //开启总中断  
  41.   
  42.     iTmp = (unsigned int)(65536-(10000/(12/DOUBLE_CRYSTAL_FREQ))); //10ms的延迟提前计算  
  43.     mbDelay10H = iTmp >> 8; //高8位值  
  44.     mbDelay10L = iTmp &0x0F; //低8位值  
  45. }  
  46.   
  47. /**------------------------------------------------------- 
  48.  * 定时器函数,T0计数器使用1号中断 
  49.  *   作用:用于延迟出发测距,每次测距完成后,需要延迟>60ms 
  50.  *         因此当计数器溢出时,time=65.535ms,mbDelayCtlFlg=1 
  51.  * -------------------------------------------------------  
  52. */  
  53. void tim0_()interrupt 1   
  54. {     
  55.     TR0 = 0; //T0关闭计数器  
  56.     mbDelayOverFlg = 1; //设定延迟结束  
  57. }  
  58.   
  59. /*------------------------------------------------------- 
  60.  *启动超声波测距模块,TX保持22us的高电平 
  61.  *-------------------------------------------------------*/  
  62. void StartModule()  
  63. {  
  64.     TX = 1; //控制端置1  
  65.     _nop_();  
  66.     _nop_();  
  67.     _nop_();  
  68.     _nop_();  
  69.     _nop_();  
  70.     _nop_();  
  71.     _nop_();  
  72.     _nop_();  
  73.     _nop_();  
  74.     _nop_();  
  75.     _nop_();  
  76.     _nop_();  
  77.     _nop_();  
  78.     _nop_();  
  79.     _nop_();  
  80.     _nop_();  
  81.     _nop_();  
  82.     _nop_();  
  83.     _nop_();  
  84.     _nop_();  
  85.     _nop_();  
  86.     TX=0; //控制端置0,等待接收回波  
  87. }  
  88.   
  89. /*------------------------------------------------------- 
  90.  *获取最近一次测得的距离 
  91.  *  注意:每次成功测距,需要耗时100ms-150ms左右时间 
  92.  *-------------------------------------------------------*/  
  93. unsigned int getDistance(void)  
  94. {  
  95.     return miDistance;  
  96. }  
  97.   
  98. /*------------------------------------------------------- 
  99.  *获取最近一次的测距状态 
  100.  *@return unsigned int 0:正常 / 1:(err)距离太近 /2:(err)超量程 
  101.  *-------------------------------------------------------*/  
  102. unsigned int getDistanceState(void)  
  103. {  
  104.     return mcDistanceErr;  
  105. }  
  106.   
  107. /*------------------------------------------------------- 
  108.  *检查距离操作(将测得的距离保存在公共变量中) 
  109.  *  备注:本函数调用完成后,需要通过getDistance()或getDistanceState()获得结果 
  110.  *  注意:每次成功测距,需要耗时100ms-150ms左右时间 
  111.  * @return 0:完成测距操作 / 1:正在延迟等待下次测距的开始 
  112.  *-------------------------------------------------------*/  
  113. unsigned char refreshDistance(void)  
  114. {  
  115.     unsigned int i; //超量程检测变量  
  116.     unsigned int iCycle; //计算总周期  
  117.   
  118.     if (1 == mbDelayOverFlg)//判断是否在延迟期  
  119.     {     
  120.         i = iMAX_LEN; //置入最大量程  
  121.         StartModule(); //发送测距模块启动信号  
  122.         /** 
  123.          * 此语句的作用: 
  124.          *   没有收到回波且在N(iMAX_LEN*N)米障碍物信号返回需要的时间前则等待 
  125.          *   (无信号即时返回,防止死循环,阻碍其它程序的执行) 
  126.          */  
  127.         while(!RX && i-->0);  
  128.         //判断处理结果  
  129.         if (i>0) //小于N米  
  130.         {  
  131.             TR0=1; //收到回波的上边沿(RX=1),打开计数器  
  132.             while(RX);//当回波RX=0时,测距结束  
  133.             TR0=0; //关闭定时器(需要一个时钟周期)  
  134.             iCycle = (TH0 * 256 + TL0) + 1; //计算总消耗的周期  
  135.             TH0=0;  
  136.             TL0=0;  
  137.       
  138.             if (iCycle <= iMIN_LEN)  
  139.             {  
  140.                 mcDistanceErr = 1;//距离太近  
  141.                 /** 
  142.                  * 距离超近:重启延迟时间 >10ms,保证上一个声波回波已经消失 
  143.                  *           T0计数器重装值mbDelay10H, mbDelay10L,在 
  144.                  *           InitUltrasonicDistance()初始化函数中生成 
  145.                  */  
  146.                 mbDelayOverFlg = 0; //复位延迟标志  
  147.                 TH0 = mbDelay10H; //重装计数器高8位  
  148.                 TL0 = mbDelay10L; //重装计数器低8位  
  149.                 TR0 = 1; //启动延迟计数器  
  150.             }  
  151.             else  
  152.             {  
  153.                 //(iCycle * 1.0851 * 0.17 / 10) => iCycle * 0.01844670   
  154.                 miDistance = (unsigned int)(iCycle * 0.01844670);//(单位cm)  
  155.                 mcDistanceErr = 0;//测距正常值  
  156.                 /** 
  157.                  * 一次测距完成需要延迟>60ms的时间,保证上一个声波回波已经消失 
  158.                  * 这儿使用16位计数器的整个空间,> 65.535ms 
  159.                  */  
  160.                 mbDelayOverFlg = 0; //复位延迟标志  
  161.                 TH0 = 0; //T0,高位归0复位  
  162.                 TL0 = 0; //T0,低位归0复位  
  163.                 TR0=1;//打开T0延迟计数器(此时不测距,所以不影响测距的计算)  
  164.             }  
  165.         }  
  166.         else   
  167.             mcDistanceErr = 2; //超量程  
  168.   
  169.         return 0; //完成测距操作  
  170.     }  
  171.     else //正在延迟等待下次测距的开始  
  172.         return 1;  
  173. }  


串口通信配置文件SerialComm.h

  1. #ifndef  __Serial_Comm_H__  
  2. #define  __Serial_Comm_H__  
  3. #include <reg52.h>  
  4. //***************************************************//  
  5. //                    串口通讯操作库                 //  
  6. //---------------------------------------------------//  
  7. // 波特率:9600, 11.0592, 无奇偶校验, 8数据位,1停止位//  
  8. // Create Date:2011-09-22  User:JerryLi              //  
  9. // email:lijian@dzs.mobi                             //  
  10. // 工作时将会占用 interrupt 4 using 1 这个中断       //  
  11. // 即: 占用 T1 计数器                                //  
  12. //---------------------------------------------------//  
  13.   
  14. /*------------------------------------------------------- 
  15.  *串口初始化,波特率9600 方式1 8 UART 
  16.  *@return void 
  17.  *-------------------------------------------------------*/  
  18. extern void InitSerialComm(void);  
  19.   
  20. /*------------------------------------------------------- 
  21.  *读取串口接收状态 
  22.  *@return 0:无数据 / 1:有数据 
  23.  *-------------------------------------------------------*/  
  24. extern bit getReceiveFlg(void);  
  25.   
  26. /*------------------------------------------------------- 
  27.  *读取串口中的一个字节 
  28.  *  读取条件,必须当getReceiveFlg() == 1的时候才能读取 
  29.  *@return void 
  30.  *-------------------------------------------------------*/  
  31. extern char ReadChar(void);  
  32.   
  33. /*------------------------------------------------------- 
  34.  *读取一个字符串 
  35.  * 备注:当读取到第一个字符时,直到出现'\0'或'\r'结束, 
  36.  *       或者当缓冲区填满的时候结束,输出字符串以'\0'结束 
  37.  * 注意:务必注意结束符,如果发送端没有传入结束符将会一直 
  38.  *       死循环等着,直到等到出现有结束符为止。 
  39.  *@param char *pOutBuf 在缓存中存放接收到字符并以 '\0'结束 
  40.  *@param short sLen 缓冲区的长度 
  41.  *@return short 返回成功接收到的字符数量,<0表示未读到数据 
  42.  *-------------------------------------------------------*/  
  43. extern short ReadStr(char *pOutBuf, short sLen);  
  44.   
  45. /*------------------------------------------------------- 
  46.  *向串口发送单字节 
  47.  *@param char cData 要发送的数据 
  48.  *@return void 
  49.  *-----------------------------------------------------*/  
  50. extern void SerialSendByte(char cData);  
  51.   
  52. /*------------------------------------------------------- 
  53.  *向串口发送一个字符串 以'\0'结束 
  54.  *@param char *str 需要发送的字符串指针 
  55.  *@return void 
  56.  *-----------------------------------------------------*/  
  57. extern void SerialSendStr(char *str);  
  58. #endif  
  59.   
  60. /*使用方式: 
  61. #include "SerialComm.h" //串口通讯操作类 
  62. void main (void) 
  63.     char pReBuf[20]; 
  64. //  char cBuf; 
  65.  
  66.     InitSerialComm(); 
  67.     while(1) 
  68.     {  
  69.         if (getReceiveFlg()) 
  70.         { 
  71.             //测试时,字符接收与字符串接收不要一起用 
  72. //          SerialSendByte(ReadChar()); //发送一个字符 
  73.             ReadStr(pReBuf, 20); //接收一个字符串 
  74.             SerialSendStr(pReBuf); //发送一个字符串 
  75.         } 
  76.     } 
  77. */  

串口通信程序文件SerialComm.c

  1. /* 
  2.    串口通讯操作库 
  3. */  
  4. #include "SerialComm.h"  
  5.   
  6.  /**全局变量定义**/  
  7. bit mbSerialReceiveFlg;  
  8. char mcSerialInData;  
  9. /*------------------------------------------------------- 
  10.  *串口初始化,波特率9600 方式1 8 UART 
  11.  *@return void 
  12.  *-------------------------------------------------------*/  
  13. void InitSerialComm(void)  
  14. {  
  15.     TMOD |= 0x20;   //定时器1方式2,8位自动重装模式。0010 0000  
  16.     PCON = 0x00;    //SMOD:波特率倍增位 SMOD=0,波特率不备增  
  17.     SCON = 0x50;    //串口模式1,8位UART,波特率可变。  
  18.     /*波特率定时器初始化,定时器初始值0xFD*/  
  19.     TH1 = 0xFD;     //256-(11.5920*10^6)/(384*9600)  
  20.     TL1 = 0xFD;  
  21.     /*启动定时器1*/  
  22.     TR1 = 1;  
  23.     /*中断处理*/  
  24.     ES = 1; //允许串口中断  
  25.     EA = 1; //允许总中断开关  
  26.   
  27.     mbSerialReceiveFlg = 0; //接收状态标志初始化  
  28. }  
  29.   
  30. /*------------------------------------------------------- 
  31.  *读取串口接收状态 
  32.  *@return 0:无数据 / 1:有数据 
  33.  *-------------------------------------------------------*/  
  34. bit getReceiveFlg(void)  
  35. {  
  36.     return mbSerialReceiveFlg;  
  37. }   
  38.   
  39. /*------------------------------------------------------- 
  40.  *读取串口中的一个字节 
  41.  *  读取条件,必须当getReceiveFlg() == 1的时候才能读取 
  42.  *@return void 
  43.  *-------------------------------------------------------*/  
  44. char ReadChar(void)  
  45. {  
  46.     mbSerialReceiveFlg = 0;  
  47.     return mcSerialInData;  
  48. }    
  49.   
  50. /*------------------------------------------------------- 
  51.  *读取一个字符串 
  52.  * 备注:当读取到第一个字符时,直到出现'\0'或'\r'结束, 
  53.  *       或者当缓冲区填满的时候结束,输出字符串以'\0'结束 
  54.  * 注意:务必注意结束符,如果发送端没有传入结束符将会一直 
  55.  *       死循环等着,直到等到出现有结束符为止。 
  56.  *@param char *pOutBuf 在缓存中存放接收到字符并以 '\0'结束 
  57.  *@param short sLen 缓冲区的长度 
  58.  *@return short 返回成功接收到的字符数量,<0表示未读到数据 
  59.  *-------------------------------------------------------*/  
  60. short ReadStr(char *pOutBuf, short sLen)  
  61. {  
  62.     short sGetLen; //保存已经读取的字符串长度  
  63.   
  64.     if (getReceiveFlg())  
  65.     {  
  66.         sGetLen = 0; //初始化  
  67.         sLen -= 1; //减去一个存放'0'的区域  
  68.         while(1)  
  69.         {  
  70.             if (getReceiveFlg() && sGetLen < sLen)  
  71.             {  
  72.                 *(pOutBuf+sGetLen) = ReadChar();  
  73.                 if (*(pOutBuf+sGetLen) == '\0' || *(pOutBuf+sGetLen) == '\r')  
  74.                 {   //接收到'\0'或者'\r'回车符时结束  
  75.                     *(pOutBuf+sGetLen) = '\0';  
  76.                     break;   
  77.                 }  
  78.                 else  
  79.                     sGetLen++; //指针下移一个单位  
  80.             }  
  81.             //当前的缓冲区已填满,接收结束  
  82.             if (sGetLen == sLen-1)  
  83.                 *(pOutBuf+sGetLen) = '\0';  
  84.         }         
  85.         return sGetLen;  
  86.     }  
  87.     else  
  88.         return -1;    
  89. }    
  90.   
  91. /*------------------------------------------------------- 
  92.  *向串口发送单字节 
  93.  *@param char cData 要发送的数据 
  94.  *@return void 
  95.  *-----------------------------------------------------*/  
  96. void SerialSendByte(char cData)   
  97. {   
  98.     SBUF=cData; //写入待发数据  
  99.     while(!TI); //等待数据发送结束(TI=0数据发送完成)   
  100.     TI=0;   
  101. }  
  102.   
  103. /*------------------------------------------------------- 
  104.  *向串口发送一个字符串 以'\0'结束 
  105.  *@param char *str 需要发送的字符串指针 
  106.  *@return void 
  107.  *-----------------------------------------------------*/  
  108. void SerialSendStr(char *str)  
  109. {  
  110.     while(*str)  
  111.         SerialSendByte(*str++);  
  112. }     
  113.   
  114. /*------------------------------------------------------- 
  115.  *接收中断处理 
  116.  *中断开始时,读取数据,并立即关闭中断 
  117.  *-----------------------------------------------------*/  
  118. void ser_int (void) interrupt 4 using 1  
  119. {  
  120.     if(RI)        //RI接受中断标志  
  121.     {  
  122.         RI = 0;         //清除RI接受中断标志  
  123.         mcSerialInData = SBUF;  //SUBF接受/发送缓冲器  
  124.         mbSerialReceiveFlg = 1;  
  125.     }  
  126. }  


这个是函数库的调用文件,主程序main.c

我是用自己的串口通信函数送回收到的数据的,你可以使用系统的print函数来输出数据到串口,结构很简单看了就懂。

  1. /***********************************************************************************************************/  
  2. //HC-SR04 超声波测距模块 DEMO 程序  
  3. //晶振:11.0592  
  4. //接线:模块TRIG接 P1.2  ECH0 接P1.1  
  5. //串口波特率:9600  
  6. /***********************************************************************************************************/  
  7. #include <reg52.h>        //包函8051内部资源的定义  
  8. #include <STDIO.H>  
  9. #include "SerialComm.h"  
  10. #include "UltrasonicDistanceDriver.h"  
  11. /********************************************************/  
  12. void main(void)  
  13. {  
  14.     char pcOutBuf[30];  
  15.     unsigned int iOld=0;  
  16.   
  17.     InitUltrasonicDistance();  
  18.     InitSerialComm();  
  19.     while(1)  
  20.     {     
  21.         //当调用测距函数后,返回为0,表示测距成功,否则测距函数正在延迟中  
  22.         if (0 == refreshDistance())  
  23.         {  
  24.             //当取值有效时,如果与前次值没变化,则不作更新  
  25.             if (0 == getDistanceState() && (iOld != getDistance()))  
  26.             {  
  27.                 iOld = getDistance();  
  28.                 sprintf(pcOutBuf, "S=%d\r\n", iOld);  
  29.                 SerialSendStr(pcOutBuf); //送到串口           
  30.                 P2=~(unsigned int)(iOld); //点灯  
  31.             }  
  32.         }         
  33.     }  
  34. }  


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多