Abstract: 超声波测距模块HC-SR04模块的代码,提供两种思路
模块介绍
懒得写,看这里。
代码部分
思路一
- 用 15us 的高电平启动模块
- 使用间断计时的方法,用每隔一段时间(这里是 10us)触发一次的中断进行计时
- 用计时的值和声速算出距离
HCSR04.h
1 2 3 4 5 6 7 8
| #ifndef __HCSR04_H #define __HCSR04_H
void HCSR04_Init(void); uint8_t HCSR04_GetDistance(void);
#endif
|
HCSR04.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| #include "stm32f10x.h" #include "Delay.h"
#define Trig_Pin GPIO_Pin_7 #define Echo_Pin GPIO_Pin_6
uint16_t Count=0; uint64_t Time=0; uint64_t Time_end=0;
void HCSR04_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = Trig_Pin; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = Echo_Pin; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_ResetBits(GPIOB, Trig_Pin); TIM_InternalClockConfig(TIM4); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_Prescaler = (72-1); TIM_TimeBaseInitStructure.TIM_Period = (10-1); TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); TIM_ClearFlag(TIM4, TIM_FLAG_Update); TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM4,ENABLE); }
void HCSR04_Start(void) { GPIO_SetBits(GPIOB, Trig_Pin); Delay_us(15); GPIO_ResetBits(GPIOB, Trig_Pin); }
uint16_t HCSR04_GetDistance(void) { HCSR04_Start(); uint32_t Distance = 0; while(GPIO_ReadInputDataBit(GPIOB,Echo_Pin)==0); Time=0; while(GPIO_ReadInputDataBit(GPIOB,Echo_Pin)==1); Time_end=Time; Distance=(Time_end/2)*3.46; return Distance; }
void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) { Time++; TIM_ClearITPendingBit(TIM4, TIM_IT_Update); } }
|
思路二
- 用 15us 的高电平启动模块
- 使用不间断计时的方法,当检测到模块的返回信号时开始计时,直到返回信号结束,读取出计数器的值
- 用计数的值和声速算出距离
HCSR04.h
1 2 3 4 5 6 7 8
| #ifndef __HCSR04_H #define __HCSR04_H
void HCSR04_Init(void); uint8_t HCSR04_GetDistance(void);
#endif
|
HCSR04.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include "stm32f10x.h" #include "Delay.h"
#define Trig_Pin GPIO_Pin_7 #define Echo_Pin GPIO_Pin_6
uint16_t Count=0;
void HCSR04_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = Trig_Pin; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = Echo_Pin; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_ResetBits(GPIOB, Trig_Pin); TIM_InternalClockConfig(TIM4); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_Prescaler = (72-1); TIM_TimeBaseInitStructure.TIM_Period = (50000-1); TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); }
void HCSR04_Start(void) { GPIO_SetBits(GPIOB, Trig_Pin); Delay_us(15); GPIO_ResetBits(GPIOB, Trig_Pin); }
uint16_t HCSR04_GetDistance(void) { HCSR04_Start(); uint32_t Distance = 0; TIM_SetCounter(TIM4,0); while(GPIO_ReadInputDataBit(GPIOB,Echo_Pin)==0); TIM_Cmd(TIM4,ENABLE); while(GPIO_ReadInputDataBit(GPIOB,Echo_Pin)==1); Count=TIM_GetCounter(TIM4); TIM_Cmd(TIM4,DISABLE); Distance=(Count/2)*0.346; return Distance; }
|
值得注意的点
HC-SR04模块使用 DC 5V 供电,但是也有其他电压的产品
模块检测距离时需要注意反射超声波的物体的大小和面倾角,若物体太小或面倾角过大将不能得到准确的结果
考虑到 STM32 GPIO 口的电压耐受,建议使用 FT (即 5V 耐受)的引脚,例如这里使用的PB6、PB7引脚,也有人使用普通引脚,这里不做尝试
这里两种思路的代码,从精度上看几乎一样,但是频繁进中断不太优雅,所以更偏向于思路二
思路一的代码需要额外配置中断优先级组,如在主函数中加上 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
也可以使用定时器的输入捕获实现功能,但是精度不理想且受外部影响较大,这里就不考虑了