文章目录
一、 内容概要
Ⅰ 采用stm32F103和HC-SR04超声波模块, 使用标准库或HAL库+ 定时器中断,完成1或2路的超声波障碍物测距功能。
Ⅱ 当前智能汽车上一般配置有12路超声波雷达,这些专用超声波雷达内置了MCU,直接输出数字化的测距结果,一般硬件接口采用串口RS485,通信协议采用modbus。
① 了解 RS485与RS232(UART),Modbus协议
② 如果让你设计一款 12路车载超声波雷达,采用 stm32F103+HC-SR04超声波模块,对外提供RS485和Modbus协议,你的设计方案是什么?
二、 stm32超声波测距实现
2.1 准备工作
CubeMx32
keil
stm32c8t6
HC-SR04超声波模块
2.2 器件介绍
HC-SR04:
HC-SR04超声波测距模块提供2cm~400cm的测距功能,精度达3mm。
STM32F103的 HC-SR04超声波测距
功能需求
数据采集与滤波处理 - 测试数据包含噪声,程序需要进行滤波处理; - 将测距数值通过串口上传到上位机串口助手。
控制蜂鸣器或LED - 根据障碍物距离远近,控制一个蜂鸣器(可以用LED灯代替)发出频率不同的声音(或LED不同闪烁),即输出占空比变化的PWM波形。
仿真测试 - 在没有超声波模块硬件的场景下,使用Keil中的仿真逻辑分析仪,观察分析对应管脚上的时序波形,判读是否符合协议规范。
以下图片截取自深圳市捷深科技有限公司的《HC-SR04超声波测距模块说明书》
通过时序图我们可以知道,我们给HC-SR04发送长达10us的TTL脉冲,然后模块就会进行测距,测距的结果通过回响信号传达,回响的TTL电平信号时间即是超声波从HC-SR04模块发出,触碰到障碍物后返回到HC-SR04模块的时间总和。
TTL是逻辑电平标准,当电压达到2.4V5V之间,那么为逻辑1(高电平),电压在0V0.4V之间,那么为逻辑0(低电平)。所以我们可以直接通过GPIO口来输出以及输入时序所需的电平信号。
总所周知,声音的速度为340m/s,因此我们将回响电平的时间除340再除2之后得到的就是单位为米的测距结果。
编写思路:
结合说明书我们可以知道,我们仅需提供10us的高电平给Trig口即可。然后HC-SR04在测量完毕之后会将结果通过Echo回响回来。
所以我们只需要将Trig口拉高,等待10us(最好再延长一些,代码中用的是15us)后再拉低即可。
接着就只需要等待Echo将数据传输回来,通过时序图我们可以得知回响信号是拉高Echo口,再拉低,中间持续的时间就是测距的结果。
所以我们给Echo口配置一个中断事件,设置为上跳变下跳变都触发,另外再用一个变量记录Echo口到底是拉高还是拉低即可。
如果是拉高,那么我们需要记录下持续的时间,这时候我们需要用定时器计时,所以需要在一开始的时候就配置好定时器的初始化。唯一的问题就是该如何配置定时器的预分频器和自动重装器了。
根据说明书我们可以知道HC-SR04的精度为3mm,而测距的公式为 us/58-cm,稍加计算可知,如果我们需要测量3mm,那么得到的时间为17.4us,以此为一个刻度,那么定时器的频率应该为57471Hz。然而这样太麻烦了,而且也不好用,因此我们可以随意一些,我在代码中使用的是预分频器为72,自动重装器为100,那么得到的频率为72MHz/72/100=1000Hz,也就是一次定时器中断的时间为100us,而自动重装器里的每一个值就是1us,所以每次外部中断的下降沿触发之后只需要将定时器触发的次数*100再加上自动重装器里的值就可以得到回响信号的持续时间了,单位是us。
2.3 搭建编程环境
打开CubeMx,新建一个项目
管脚配置大致如图所示
距离传感器模块获取数据
TRIG管脚,和蜂鸣器管脚
RTOS多任务程序设计
按照教程导入项目
2.4代码编写
实现
TIM_ICInitTypeDef tim_ic_init;
//g_cap_state:捕获状态标志(bit7:完成捕获; bit6:捕获高电平;bit5-bit0:捕获高电平溢出次数)
u16 g_cap_state, g_cap_val;
u32 g_cap_distance; //超声波测量距离
//---------------------------------------------------------------------------------------------------------------------------------------------
// 函 数 名: 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; //清除中断标志位
}
主函数
//超声波测试函数
int main_hcr(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart_init(1, 115200 * 8); //串口初始化为961200
Bsp_LedInit(); //初始化与LED连接的硬件接口
timer4_cap_init(0Xffff, 72 - 1);
while (1)
{
hcsr04_read_distance();
delay_ms(500);
LED0 = 1;
delay_ms(500);
LED0 = 0;
printf("g_cap_distance = %d \r\n", g_cap_distance); //用串口1打印输出
}
}
2.5结果展示
三. 超声波雷达设计方案
3.1. RS485与RS232(UART)有什么不同?
电气特性:
RS232(UART)使用单端信号传输,信号线和地线之间的电压变化代表逻辑电平,传输距离较短,抗干扰能力较弱。
RS485使用差分信号传输,信号通过两根线之间的电压差来表示逻辑电平,传输距离长,抗干扰能力强。
连接方式:
RS232通常用于点对点通信,一对一连接。
RS485支持多点通信,可以连接多个设备,最多支持32个设备。
通信距离:
RS232的最大传输距离通常为15米。
RS485的最大传输距离可以达到1200米。
3.2. Modbus协议是什么?
Modbus是一种串行通信协议,广泛用于工业自动化和控制系统。Modbus协议有以下特点:
主从结构:一个主设备可以与多个从设备通信。
传输模式:支持RTU(Remote Terminal Unit)模式和ASCII模式,RTU模式采用二进制传输,效率较高;ASCII模式采用文本传输,便于调试。
功能码:Modbus协议定义了多个功能码,用于读写设备的寄存器和位状态。
错误检测:RTU模式使用CRC校验,ASCII模式使用LRC校验,保证数据传输的可靠性。
3.3. 12路车载超声波雷达设计方案
设计一款12路车载超声波雷达,采用STM32F103和HC-SR04超声波模块,对外提供RS485和Modbus协议,设计方案如下:
硬件设计
主控芯片:STM32F103,用于控制12个HC-SR04超声波模块,处理测距数据,并通过RS485接口与上位机通信。
超声波模块:12个HC-SR04模块,分别连接到STM32F103的GPIO引脚。
RS485接口:使用RS485收发芯片(如MAX485)与STM32F103的UART接口连接,实现RS485通信。
电源管理:提供稳定的电源,确保所有模块正常工作。
软件设计
初始化:
初始化12个HC-SR04模块的GPIO引脚;
初始化定时器,实现多路超声波模块的轮询测距;
初始化串口,配置为RS485通信模式,支持Modbus协议。
测距处理:
使用定时器中断,实现12路超声波模块的轮询测距;
对测量数据进行滤波处理,去除噪声。
Modbus协议实现:
实现Modbus RTU协议栈,支持常用的功能码(如读保持寄存器、写单个寄存器等);
处理Modbus请求,返回测距数据。
数据传输:
通过RS485接口,将测距数据传输到上位机;
支持Modbus协议,保证数据传输的可靠性和兼容性。
协议。
2. 测距处理:
使用定时器中断,实现12路超声波模块的轮询测距;
对测量数据进行滤波处理,去除噪声。
Modbus协议实现:
实现Modbus RTU协议栈,支持常用的功能码(如读保持寄存器、写单个寄存器等);
处理Modbus请求,返回测距数据。
数据传输:
通过RS485接口,将测距数据传输到上位机;
支持Modbus协议,保证数据传输的可靠性和兼容性。
四、总结
认识了HC-SR04模块,并利用该模块进行了汽车倒车雷达的模拟,通过对12路车载超声波雷达的设计,对该模块有了更深刻的认识