基于STM32和HC-SR04的超声波测距实验
一.HC-SR04简介
HC-SR04是一款超声波测距模块,提供2cm到400cm的测距功能,精度达到3mm。以下是对HC-SR04超声波测距模块的介绍:
-
工作原理
- 触发信号:HC-SR04的工作始于单片机向其Trig引脚发送一个至少10us的高电平TTL脉冲信号,这会触发模块发射8个40kHz的方波。
- 信号接收:发射后,模块自动切换至监测模式,等待超声波信号的返回。当超声波遇到障碍物并返回时,Echo引脚输出高电平,该高电平持续的时间代表了超声波从发射到接收的总时间。
- 计算距离:声音在空气中的传播速度约为340m/s,通过测量回声信号的时间长度,可以计算出超声波往返的距离,进而得知障碍物与模块之间的距离[。
-
模块组成
- 发射器和接收器:模块包含超声波发射器和接收器,分别负责超声波的发送和接收[2]。
- 控制电路:模块内置的控制电路负责处理信号的发送、接收以及数据处理[2]。
-
应用领域
- 智能小车避障:在智能小车中用于检测路径上的障碍物,实现自动避障[2]。
- 盲人拐杖:安装在盲人拐杖中,帮助盲人感知前方的障碍物,提高行走安全性[2]。
- 倒车雷达:应用于汽车倒车雷达系统,辅助驾驶员安全停车[2]。
-
电气参数
- 供电电压:HC-SR04的标准工作电压为5V[3]。
- 输出信号:模块通过Echo引脚输出与距离成正比的高电平信号[1]。
-
使用注意事项
- 电源隔离:由于HC-SR04需要单独的5V供电,因此不能与某些微控制器共用电源VCC,以避免电压不匹配的问题[1]。
- 接线端口:模块的Trig和Echo接口应正确连接至微控制器的对应GPIO口,并注意中断通道的配置[1]。
- 定时器配置:在使用定时器计时时,需要合理设置预分频器和自动重装器的值,以确保计时的准确性[1]。
-
编程实践
- 初始化设置:在编程时,需要初始化Trig引脚为输出模式,Echo引脚为浮空输入模式,并配置定时器进行计时[2]。
- 中断处理:设置Echo引脚的中断事件,使其能在上升沿和下降沿触发,以便捕捉回声信号的开始和结束[1]。
- 距离计算:根据回声信号的持续时间和声速,计算并输出最终的距离测量结果[2]。
HC-SR04超声波传感器引脚
二.超声波测距实验
1.实验准备
硬件:STM32F103C8T6系统板,HC-SR04超声波测距模块,OLED显示屏,蜂鸣器,STlinK
软件:keil5,野火串口调试助手
接线图
2.实验主要代码
HC-SR04.h
#ifndef __HCSR04_H
#define __HCSR04_H
extern u32 g_cap_distance; //超声波测量距离
void timer4_cap_init(u16 timer_arr, u16 timer_psc);
void hcsr04_read_distance(void);
void TIM4_IRQHandler(void);
#endif
HC-SR04.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
TIM_ICInitTypeDef tim_ic_init;
u16 g_cap_state, g_cap_val;
u32 g_cap_distance; //超声波测量距离
//g_cap_state:捕获状态标志(bit7:完成捕获; bit6:捕获高电平;bit5-bit0:捕获高电平溢出次数)
//---------------------------------------------------------------------------------------------------------------------------------------------
// 函 数 名: timer4_cap_init
// 功能说明: TIM4初始化
// 形 参: timer_arr:自动重装值; timer_psc:时钟分频系数
// 返 回 值: 无
// 日 期:
// 作 者:
// 备 注:
//---------------------------------------------------------------------------------------------------------------------------------------------
void timer4_cap_init(u16 timer_arr, u16 timer_psc)
{
GPIO_InitTypeDef gp_init;
TIM_TimeBaseInitTypeDef tim_base_init;
NVIC_InitTypeDef nvic_init_config;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB时钟
gp_init.GPIO_Pin = GPIO_Pin_8;
gp_init.GPIO_Mode = GPIO_Mode_IPD; //PB8 输入 (ECHO)
GPIO_Init(GPIOB, &gp_init);
gp_init.GPIO_Pin = GPIO_Pin_9;
gp_init.GPIO_Mode = GPIO_Mode_Out_PP; //PB9 输出 (TRIG)
gp_init.GPIO_Speed = GPIO_Speed_2MHz; //2M
GPIO_Init(GPIOB, &gp_init);
//初始化定时器4 TIM4
tim_base_init.TIM_Period = timer_arr; //设定计数器自动重装值
tim_base_init.TIM_Prescaler = timer_psc; //预分频器
tim_base_init.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
tim_base_init.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &tim_base_init); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//初始化TIM4输入捕获参数
tim_ic_init.TIM_Channel = TIM_Channel_3; //CC1S=03 选择输入端 IC3映射到TI1上
tim_ic_init.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
tim_ic_init.TIM_ICSelection = TIM_ICSelection_DirectTI;
tim_ic_init.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
tim_ic_init.TIM_ICFilter = 0x00;//配置输入滤波器 不滤波
TIM_ICInit(TIM4, &tim_ic_init);
//中断分组初始化
nvic_init_config.NVIC_IRQChannel = TIM4_IRQn; //TIM4中断
nvic_init_config.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
nvic_init_config.NVIC_IRQChannelSubPriority = 3; //从优先级0级
nvic_init_config.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&nvic_init_config); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_ITConfig(TIM4, TIM_IT_Update|TIM_IT_CC3, ENABLE);//允许更新中断 ,允许CC3IE捕获中断
TIM_Cmd(TIM4, ENABLE); //使能定时器3
}
//---------------------------------------------------------------------------------------------------------------------------------------------
// 函 数 名: hcsr04_read_distance
// 功能说明: 超声波测量距离
// 形 参: 无
// 返 回 值: 无
// 日 期:
// 作 者:
// 备 注:
//---------------------------------------------------------------------------------------------------------------------------------------------
void hcsr04_read_distance(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_9); //启动超声波测量
Delay_us(15);
GPIO_ResetBits(GPIOB, GPIO_Pin_9);
if (g_cap_state & 0X80) //捕获一次高电平
{
g_cap_distance = g_cap_state & 0X3f;
g_cap_distance *= 65535;
g_cap_distance += g_cap_val;
g_cap_distance = g_cap_distance * 170 / 1000; //计算距离(mm)
g_cap_state = 0X00;
}
}
void TIM4_IRQHandler(void)
{
u16 sta_val;
sta_val = TIM4->SR;
if ((g_cap_state & 0X80) == 0X00) //未捕获
{
if (sta_val & 0X01) //溢出
{
if (g_cap_state & 0X40) //捕获到高电平
{
if ((g_cap_state & 0X3f) == 0X3f) //高电平时间过长
{
g_cap_state |= 0X80; //记录一次捕获
g_cap_val = 0Xffff; //溢出时间
}
else
{
g_cap_state++; //继续捕获
}
}
}
if (sta_val & 0X08) //捕获3(通道3)发生捕获事件
{
if (g_cap_state & 0X40) //捕获下降沿
{
g_cap_state |= 0X80; //标记成功捕获一次高电平
g_cap_val = TIM4->CCR3; //获取当前捕获值
TIM4->CCER &= ~(1<<9); //CC1P=0 设置为上升沿捕获
}
else
{
g_cap_state = 0;
g_cap_val = 0;
g_cap_state |= 0X40; //标记捕获到上升沿
TIM4->CNT = 0; //清空计数器
TIM4->CCER |= (1<<9); //CC1P=1 设置为下降沿捕获
}
}
}
TIM4->SR = 0; //清除中断标志位
}
main .c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "hcsr04.h"
#include "usart.h"
#include "OLED.h"
#include "beep.h"
//超声波测试函数
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart1_init(115200 * 8); //串口初始化为961200
timer4_cap_init(0Xffff, 72 - 1);
OLED_Init();
beep_init();
while (1)
{
OLED_Clear();
hcsr04_read_distance();
printf("g_cap_distance = %d \r\n", g_cap_distance); //用串口1打印输出
if(g_cap_distance<100&&(g_cap_distance>50)){
beep_on_1();
}
if(g_cap_distance<50&&(g_cap_distance>30)){
beep_on_2();
}
if(g_cap_distance<30){
beep_on_3();
}
OLED_ShowNum(2,2,g_cap_distance,5);
OLED_ShowString(2,8,"mm");
Delay_ms(200);
}
}
3.效果展示
串口调试结果
在这里插入图片描述