硬件平台:stm32f103c8t6
这里我就不列一些复杂的资料和文件来说明,我尽量用我觉得很好理解的口水化的语言来把这个模块解释清楚。
HC-SR04超声波测距模块是较常用的模块之一,比如可以用在避障小车上。
这里我用的是PWM输入捕获的方法来驱动此模块,在此之前我们先简单的了解一下该模块
这里我们可以看出来,该模块的工作原理:
1.trig脚发送一个大于10us的高电平,该模块就会发送一个超声波
2.在发送超声波的同时,echo脚被拉为高电平
3.超声波遇到障碍物就会反弹回来,当模块接收到反弹回的超声波时,拉低echo脚
4.通过得到echo脚被拉为高电平持续的时间,将该时间通过公式转化为所测的距离
测试距离 = (高电平时间声速(340M/S)/2)= ((float)t/58.0)
聪明的同学应该一下就明白该模块的工作原理了,且我们可以看出该模块的难点就是如何得到echo脚持续的高电平,这里我用的是PWM输入捕获的方法
方法简要:
1.选择定时器,这里我用的是PA6(TIM3)作为echo口,trig口随意,将TIM3定时器配置为输入捕获,这里我不建议大家用主从机来做输入捕获 ,因为我一开始用这个做得有点问题
2.将TIM3ch1配置为上升沿触发,将TIM3ch2配置为下降沿触发,开启定时器中断,ch1中断函数里将TIM3的计数器清零,ch2中断函数里将TIM3的计数器里的数读取出来,读取出来的数就可以转换为高电平持续的时间了
话不多说,上代码 ps:作为嵌入式学习者,建议大家多借鉴别人的代码,但不能照抄,而是了解原理后自己码一遍
void HCSR_Init(void)
{
//开启GPIOA和TIM3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//初始化trig引脚
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//初始化echo引脚
GPIO_InitTypeDef GPIO_InitStructe;
GPIO_InitStructe.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructe.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructe.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructe);
//开启时钟源
TIM_InternalClockConfig(TIM3);
//配置时钟基元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 65536-1;
TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//配置输入捕获,PWMI模式
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0XF;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);
//开启定时中断
TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);
TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE);
//开启NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel =TIM3_IRQn ;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
//开启时钟源
TIM_Cmd(TIM3,ENABLE);
}
float count=0;
float distance=0;
//trig口发射信号
void HCSR_Start(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_5);
Delay_us(15);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
}
//将高电平持续时间转化为距离,声速=340m / s;
float HCSR_GetDistance(void)
{
distance = count / 10000 * 340 / 2;
return distance;
}
//TIM3中断
void TIM3_IRQHandler()
{
if(TIM_GetITStatus(TIM3,TIM_IT_CC1))
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
TIM_SetCounter(TIM3,0);
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC2))
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
count = TIM_GetCounter(TIM3);
}
}
主函数:
int main(void)
{
OLED_Init();
HCSR_Init();
while(1)
{
HCSR_Start();
OLED_ShowNum(1,1,HCSR_GetDistance(),3);
}
}
为什么换算公式是这个 distance = count / 10000 * 340 / 2;
我们知道声速为340m/s,时钟基元里我arr=65535,psc=72,所以周期为72MHZ/psc=1MHZ=1us
所以记一次数的时间为1us,将us->s,所以 distance = count / 10000 * 340 / 2;
还有,大家变量类型不要定义错了,不然显示不出来数据
大概就是这么多了,有什么不懂的欢迎评论区提问,我将一一为大家解答