你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32的驱动HC-SR04超声波测距模块的经验分享

[复制链接]
攻城狮Melo 发布时间:2023-3-18 14:38
超声波测距原理
利用HC-SR04超声波测距模块可以实现比较精确的直线测距,其测距原理图如下:

20191123190005785.png

HC-SR04的一端发出超声波,接触到反射物后反射,被另一个端口接收到,所以只要知道发射和接收的时间差,就可以根据声波传播的速率算出HC-SR04和反射物直接的距离。
所以实现超声波测距就需要俩个条件:
发射和接收的时间差
超声波传输的速率
HC-SR04工作原理
HC-SR04模块的电气参数如示:

2019112319045710.png

HC-SR04模块的实物图如示:

20191123190743986.png

有四个引脚:
Vcc:+5V电源供电
Trig:输入触发信号(可以触发测距)
Echo:传出信号回响(可以传回时间差)
Gnd:接地

用Trig和Echo引脚实现测距的流程:
1.通过Trig输出一段至少10us的高电平(脉冲),触发一次测距,超声波在传输的过程中Echo一直输出高电平。
2.在Trig脉冲输出后,立即检测Echo引脚的电平,测出Echo高电平持续的时间t,t就是超声波在所测距离一个来回所需时间。

测距时序图如示:

20191123191907919.png

STM32实现驱动
利用STM32驱动HC-SR04需要做好几个关键点:
引脚的配置
时序的控制
时间差的测量

下面来分开实现几个关键点

1.引脚的配置
HC-SR04四个引脚,Vcc和Gnd直接接在开发板的电源上即可,主要是Trig和Echo引脚的配置,我选择了PB1连接Trig引脚、PB2连接Echo引脚。
因为要控制Trig输出电平,所以PB1引脚模式是推挽输出GPIO_Mode_Out_PP
Echo要检测高电平持续的时间,所以PB2引脚模式是浮空输入GPIO_Mode_IN_FLOATING
相关的配置代码如下:
  1. void SR04_GPIO_Init( void )
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStruct;
  4.         RCC_APB2PeriphClockCmd( Trig_Clock  |Echo_Clock , ENABLE );
  5.        
  6.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  7.         GPIO_InitStruct.GPIO_Pin = Trig_PIN;
  8.         GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  9.         GPIO_Init(Trig_PORT, &GPIO_InitStruct);
  10.        
  11.         GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  12.         GPIO_InitStruct.GPIO_Pin = Echo_PIN;
  13.         GPIO_Init(Echo_PORT, &GPIO_InitStruct);
  14. }
复制代码

2.时序控制
HC-SR04的时序是:先来一段10us的Trig高电平,接着接收一段Echo的高电平,伪代码如下:
  1. #define Trig_H  GPIO_SetBits(GPIOB, GPIO_Pin_1)
  2. #define Trig_L  GPIO_ResetBits(GPIOB, GPIO_Pin_1)

  3. /* Trig给一个至少10us的高电平,超声波进行一次测距 */
  4.         Trig_H;
  5.         Delay_us( 10 );
  6.         Trig_L;
  7. /* 等待Echo高电平 */
复制代码

3.时间差测量
这个是最重要的一步,要测量Echo高电平持续的时间,因为光传播的速率是340m/s,而测距的范围大多是cm级别,所以相应Echo高电平持续的时间也就是us级别的。
所以,测量时间差的条件就比较苛刻,我是利用SysTick(系统计数器)的原理实现计时的。SysTick计数器原理是对通过SysTick_Config()函数配置每俩次中断之间的节拍数,也就是俩次中断之间的机器周期,我大概算出了,测出0.1cm距离的Echo高电平时间约为6um,而系统时钟的频率是72MHz,所以配置每俩次中断之间的节拍为432的时候,进入一次中断就代表0.1cm的距离,所以只需要记录进入中断的次数就可以算出距离。通过一个全局变量在中断函数中自增来记录中断次数。SysTick_Config函数源代码如下:
  1. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  2. {
  3.         /* 判断ticks 是否超出装填值和重装值的最大值 */
  4.   if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            
  5.   
  6.   /* 配置 装载寄存器 */       
  7.   SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;     
  8.         /* 配置 内核中断的优先级,也是在NVIC中 */
  9.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
  10.         /* 加载计数器的值 */
  11.         /* SysTick->VAL是当前数值寄存器的值 */
  12.   SysTick->VAL   = 0;      

  13.         /* CTRL是SysTick控制及状态寄存器:
  14.                 CLKSOURCE:位段2 时钟源选择,0=APB/8;1=APB  APB即72MHz
  15.           TICKINT:   位段1 当置为1时,计数器递减到0时会产生中断请求;当置为0时无动作
  16.           ENABLE:   位段0 使能位,可以启动SysTick定时器*/
  17.         SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
  18.                    SysTick_CTRL_TICKINT_Msk   |
  19.                    SysTick_CTRL_ENABLE_Msk;                  
  20.   return (0);                                             
  21. }

复制代码

SysTick的具体原理可以参考一下我之前的博客:SysTick原理

注意:SysTick_Config()函数执行完就开启了中断,所以必须在Echo为低电平后及时关闭中断,并且将记录中断的变量清零。

中断函数如示:
  1. /* 用extern和volatile关键字修饰的 全局变量n */
  2. extern volatile uint32_t n;

  3. void SysTick_Handler(void)
  4. {
  5.         n++;
  6. }
复制代码

关闭中断及清零n的代码如下:
  1. /* 本来的使能位取反 */
  2. SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
复制代码

SysTick->CTRL寄存器的0位控制着中断的使能,具体情况在之前SysTick的博客中已做详细说明。

4.如何将距离测出来
我在main函数中实现了距离的测量,并且通过串口打印函数将距离传到上位机,具体代码如示:
  1. int main(void)
  2. {

  3.         int i=1,q;
  4.         float p;
  5.         /* HC-SR04模块引脚初始化 */
  6.         SR04_GPIO_Init();
  7.         /* 串口相关配置 */
  8.         GQ_UART_Config();
  9.         /* 打印调试信息 */
  10.         printf("慢漫的测距实验\n ");
  11.        
  12.        
  13.         while( 1 )
  14.         {
  15.                 /* 每0.5s测一次距离 */
  16.                 Delay_ms( 500 );
  17.        
  18.                 /* Trig给一个至少10us的高电平,超声波进行一次测距 */
  19.                 Trig_H;
  20.                 Delay_us( 10 );
  21.                 Trig_L;
  22.                 /* 等待Echo高电平 */
  23.                 while( Echo_Value != 1 );
  24.                 /* 打开中断,对Echo高电平时间计时 */
  25.                 /* 配置计数器的装载值是72*6=432,即一次中断6um,正好是超声波的0.1cm,所以中断次数n对应着n*0.1cm */
  26.                 /* SysTick_Config()中已经使能计数器了,所以无需再开启        */
  27.                 SysTick_Config( 432 );
  28.                 /* 等待直到Echo为低电平 */
  29.                 while(Echo_Value == 1);
  30.                 /* 关闭中断,通过参数n来取得距离参数 */
  31.                 /* 本来的使能位取反 */
  32.                 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
  33.                 /* p、q分别是距离的整数部分和小数部分 */
  34.                 p=n/10;
  35.                 q=n%10;
  36.                 /* 打印距离信息 */
  37.                 /* p-50时经过调试的,因为测量的距离和诸多因素有关,这个操作减小了误差 */
  38.                 printf("第%d次测量为:%.0f.%dcm\n",i,p-50,q);
  39.                 i++;
  40.                 /* 清零中断记录变量n */
  41.                 n=0;
  42.         }
  43.        
  44. }
复制代码

————————————————
版权声明:Aspirant-GQ
如有侵权请联系删除

收藏 评论0 发布时间:2023-3-18 14:38

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版