前言
本篇文章将带大家使用HAL库驱动HC-SR04超声波模块。超声波模块作为智能小车必备的模块,要学习智能小车的同学是必须掌握好这个模块的使用的。
一、HC-SR04超声波模块介绍
HC-SR04是一种常用的超声波传感器模块,也被称为超声波测距模块,广泛应用于各种自动化控制和测距系统中。它通常由超声波发射器、接收器、控制电路和外壳组成,可以实现非接触式的距离测量。
下面是HC-SR04超声波模块的一些特性和技术参数:
距离测量范围:2cm ~ 400cm(可调)。
测量精度:0.3cm。
工作电压:DC 5V。
工作电流:15mA。
频率:40kHz。
传播速度:340 m/s。
工作温度:-20℃ ~ 70℃。
HC-SR04超声波模块的工作原理与常规的超声波测距器类似,主要分为发送信号和接收信号两个部分。当模块接收到控制电路传输的触发信号时,超声波发射器就会向测距目标物体发送一定频率的超声波脉冲,然后超声波接收器会接收到反射回来的超声波信号。根据超声波从发射器到目标物体再返回接收器需要的时间,可以计算出目标物体与传感器之间的距离。
超声波模块有4个引脚,接线方法如下:
VCC--5V
GND--GND
Trig--板子上的输出引脚(用来发射超声波信号)
Echo--板子上的输入引脚(用来接收返回的超声波信号)
二、HC-SR04超声波模块原理
下图是超声波模块驱动时序图:
驱动步骤:
1.首先需要发送一个至少10us的TTL电平信号用来触发超声波模块。
2.发送完触发信号后模块内部会自动循环发出8个40KHZ的脉冲。
3.接收回响信号,根据高电平的时间来计算出距离。
计算公式:T(s) * 340(m/s) / 2
这里的计算需要除2,因为超声波发出的信号是需要往返的。
三、代码编写
创建HC-R04.c和HC-R04.h两个文件:
HC-R04.h
#ifndef _HC_SR04_H #define _HC_SR04_H #include "sys.h" #include "delay.h" #include "stm32f4xx_hal.h" void HCSR04_Init(void); #define Trig_ON HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET) #define Trig_OFF HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET) void SR04_Trigger(void); uint32_t Get_Distance(void); #endif
HC-R04.c
这里我们把Trig引脚配置为输出引脚,Echo配置为外部中断引脚,触发方式设置为双边沿触发。
这里需要配置一个定时器来计算高电平的时间。
在外部中断回调函数中进行判断是上身沿还是下降沿。
当上身沿到达时清空定时器计数值开始计数,当下降沿达到时取出定时器的计数值作为往返的时间,根据公式即可计算出距离。
#include "HC-SR04.h" /* PC8:Trig(发射引脚) PC9:Echo(接收引脚) */ TIM_HandleTypeDef TIM4_Handler; uint32_t pulse_width_us = 0; uint32_t distance_cm = 0; void HCSR04_Init(void) { // 定义GPIO的结构体变量 GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOC_CLK_ENABLE(); // 使能超声波的GPIO对应的时钟 /*Trig引脚*/ GPIO_InitStruct.Pin = GPIO_PIN_8; // 选择超声波的引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出 GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 引脚输出速度设置为快 // 初始化引脚配置 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Echo引脚*/ GPIO_InitStruct.Pin = GPIO_PIN_9; // 选择超声波的引脚 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; // 设置为双边沿触发外部中断 GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 引脚输出速度设置为快 // 初始化引脚配置 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);// 设置外部中断优先级 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); // 使能外部中断 /*配置定时器4为us级定时器*/ __HAL_RCC_TIM4_CLK_ENABLE(); //使能TIM4时钟 TIM4_Handler.Instance = TIM4; //通用定时器4 TIM4_Handler.Init.Prescaler = 83; //分频系数 TIM4_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器 TIM4_Handler.Init.Period = 0xffff; //自动装载值 TIM4_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子 HAL_TIM_Base_Init(&TIM4_Handler); } //外部中断中断处理函数 void EXTI9_5_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9); } void SR04_Trigger(void) { // 发送10us的高电平脉冲 Trig_ON; delay_us(10); Trig_OFF; } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { static int count = 0; if(GPIO_Pin == GPIO_PIN_9) { if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9)) { HAL_TIM_Base_Start(&TIM4_Handler); // 启动定时器 __HAL_TIM_SetCounter(&TIM4_Handler, 0); //清空定时器的值 } else if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_9) == 0) { HAL_TIM_Base_Stop(&TIM4_Handler); // 停止定时器 count = __HAL_TIM_GetCounter(&TIM4_Handler); //获取当前计数值 distance_cm = count * 340/2*0.000001*100; printf("distance_cm is %d\r\n", distance_cm); count = 0; } } } /*返回距离*/ uint32_t Get_Distance(void) { return distance_cm; }
四、程序测试
在while1循环中每隔50ms发射一次超声波信号,在外部中断中使用printf函数来打印出距离到串口中。
while(1) { int SR04_tick = 0; /*50ms发射一次超声波*/ if(HAL_GetTick() - SR04_tick > 50) { SR04_tick = HAL_GetTick(); SR04_Trigger(); } }
总结
超声波模块的原理和使用就介绍到这里了,有什么问题的同学可以留言或者私信。需要源代码的同学可以关注微信公众号私信我。