STM32驱动HC-SR04超声波测距模块

硬件平台: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;

还有,大家变量类型不要定义错了,不然显示不出来数据

大概就是这么多了,有什么不懂的欢迎评论区提问,我将一一为大家解答

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值