基于stm32使用标准外设库写一个hcsr04进行测距的驱动程序,要求:PB5为trig脚,PB6为echo脚,使用定时器3中断的方式实现,计算返回一个int类型的sonar_mm()函数,以毫米为单位
时间: 2025-03-28 22:18:42 浏览: 41
基于STM32使用标准外设库编写HCSR04超声波模块的测距驱动程序,以下是实现思路及代码结构说明:
### 硬件配置
1. **TRIG** 引脚连接到 STM32 的 PB5。
2. **ECHO** 引脚连接到 STM32 的 PB6。
### 软件设计步骤
#### 1. 配置GPIO口
- 将PB5配置为推挽输出模式(用于发送触发信号)。
- 将PB6配置为浮空输入模式(接收回响信号)。
#### 2. 配置定时器3 (TIM3)
- 使用 TIM3 捕获功能捕获 ECHO 脉冲宽度。
- 设置上升沿和下降沿捕获中断。
- 记录两次捕获的时间差值作为脉冲持续时间。
#### 3. 编写 `sonar_mm()` 函数
- 触发 TRIG 发送高电平脉冲。
- 利用 TIM3 中断测量 ECHO 脉宽,并通过公式换算成距离。
- 返回结果为 int 类型的距离值,单位为毫米。
---
### 示例代码
```c
#include "stm32f1xx.h"
// 定义全局变量存储捕获的时间戳
uint32_t capture_rise = 0; // 上升沿捕获时间
uint32_t capture_fall = 0; // 下降沿捕获时间
void GPIO_Config(void);
void TIM3_Config(void);
float sonar_mm();
int main(void) {
GPIO_Config(); // 初始化 GPIO
TIM3_Config(); // 初始化 TIM3
while(1) {
float distance = sonar_mm();
printf("Distance: %.2f mm\r\n", distance); // 打印当前距离
Delay_ms(500); // 延迟一段时间再次测量
}
}
/**
* @brief 配置 GPIO 口
*/
void GPIO_Config() {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 启用 GPIOB 时钟
GPIO_InitTypeDef GPIO_InitStruct;
// 配置 PB5 为推挽输出模式 (TRIG)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// 配置 PB6 为浮空输入模式 (ECHO)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/**
* @brief 配置 TIM3 进行捕获操作
*/
void TIM3_Config() {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 启用 TIM3 时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
// 配置 TIM3 工作频率
TIM_TimeBaseStruct.TIM_Period = 0xFFFF; // 自动重装载值
TIM_TimeBaseStruct.TIM_Prescaler = 72 - 1; // 分频系数:系统时钟 72 MHz -> 1us分辨率
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
// 配置通道 1 输入捕获功能
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; // 选择 CH1(PB6) 作为捕获通道
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising_Falling; // 上升沿、下降沿捕获
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接映射 TI1
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 捕获不分频
TIM_ICInitStruct.TIM_ICFilter = 0x0F; // 数字滤波器设置
TIM_ICInit(TIM3, &TIM_ICInitStruct);
// 开启中断并使能 NVIC
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_Update, ENABLE); // 允许 CC1 和更新中断
NVIC_EnableIRQ(TIM3_IRQn);
TIM_Cmd(TIM3, ENABLE); // 启用计数器
}
/**
* @brief 测量距离函数 (返回以毫米为单位的结果)
* @return int 类型的距离值
*/
float sonar_mm() {
uint32_t duration_us;
// 触发一次 TRIG 信号
GPIO_ResetBits(GPIOB, GPIO_Pin_5); // 清零 TRIG
Delay_us(2); // 延时 2 us
GPIO_SetBits(GPIOB, GPIO_Pin_5); // 输出高电平
Delay_us(10); // 维持高电平 10 us
GPIO_ResetBits(GPIOB, GPIO_Pin_5); // 再次清零
// 等待完成一次完整的捕获过程
while(capture_fall == 0 || capture_rise == 0);
// 获取脉冲宽度
duration_us = capture_fall - capture_rise;
// 根据公式计算距离 (速度 V=340m/s, 时间 T=duration_us / 2)
return ((float)(duration_us / 2)) * 0.034; // 单位转换至毫米
}
/**
* @brief TIM3 中断服务函数
*/
void TIM3_IRQHandler(void) {
if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) { // 如果发生捕获事件
if((TIM3->CCR1 & 0x8000) == 0x0000) { // 捕获到上升沿
capture_rise = TIM3->CNT;
} else { // 捕获到下降沿
capture_fall = TIM3->CNT;
}
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); // 清除标志位
}
}
/**
* @brief 微秒级延时函数
* @param nTime 延时微秒数
*/
void Delay_us(uint16_t nTime) {
SysTick->LOAD = (SystemCoreClock / 1000000) * nTime - 1;
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
```
---
### 注意事项
1. **时钟源校准**: 系统时钟需要精确稳定才能保证测量精度。
2. **噪声影响**: HCSR04 对电磁干扰较为敏感,建议将硬件远离强电流设备运行。
3. **最大范围限制**: 此算法默认支持的最大测程由溢出条件决定,请根据实际需求调整定时器周期。
阅读全文
相关推荐
















