STM32基于HAL库的HC-SR04超声波测距学习

本章要实现的功能是实现超声波测距并将距离显示在oled屏上,所用的板子仍是stm32f103c8t6。

目录

效果:

 cube配置:

代码部分:

关于溢出问题的补充:


效果:

首先来看一下HC-SR04超声波测距模块:

 cube配置:

1.选择定时器2通道3作为echo管脚,选择PA1作为trig管脚,并使能定时器中断。

2.使能I2C2,为了实现将距离显示在oled屏上,或者使用串口查看测量结果也可。

3.生成工程。

代码部分:

全局变量定义:

第一个是标志位,用来判断是不是第一次被捕获,第一次捕获是上升沿,第二次是下降沿,两次相减才是我们需要的中间高电平的时间。

/* USER CODE BEGIN PM */
uint8_t IS_FIRST_CAPTURED = 0;
uint32_t IC_Val1=0;
uint32_t IC_Val2=0;
uint32_t Difference=0;
uint16_t Distance=0;
/* USER CODE END PM */

先使能定时器中断和输入捕获中断:

    /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim2);
	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_3);	
    /* USER CODE END 2 */

因为前面写了要给至少10us的高电平信号,而HAL_Delay是ms级别的,所以这里要写一个us延时函数,定时器是16位的,所以传入的参数类型是uint16_t 。

void delay_us(uint16_t us)
{
	__HAL_TIM_SET_COUNTER (&htim2 ,0);
	while(__HAL_TIM_GET_COUNTER (&htim2 )<us );
}

然后编写超声波读取的函数:

先把电平拉低,确保测距开始之前是低电平,否则不能准确的拉到10us,然后拉高一段时间(10us以上)再拉低,然后就可以进入测距了,开始等待接收回波,这个可以在中断中写。

uint16_t HCSR04_Read(void )
{
	HAL_GPIO_WritePin (TRIG_GPIO_Port ,TRIG_Pin ,GPIO_PIN_RESET );
	delay_us (10);
	HAL_GPIO_WritePin (TRIG_GPIO_Port ,TRIG_Pin ,GPIO_PIN_SET );
	delay_us (12);
	HAL_GPIO_WritePin (TRIG_GPIO_Port ,TRIG_Pin ,GPIO_PIN_RESET );	
	__HAL_TIM_ENABLE_IT (&htim2 ,TIM_IT_CC3 );
	HAL_Delay (100);
	return Distance ;
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim ->Channel ==HAL_TIM_ACTIVE_CHANNEL_3 )//判断是不是通道3
	{
		if(IS_FIRST_CAPTURED ==0)
		{
			IS_FIRST_CAPTURED =1;
			IC_Val1 =	HAL_TIM_ReadCapturedValue (htim ,TIM_CHANNEL_3 );//读取当前值
			__HAL_TIM_SET_CAPTUREPOLARITY (htim ,TIM_CHANNEL_3 ,TIM_INPUTCHANNELPOLARITY_FALLING );
		}	
		else if (IS_FIRST_CAPTURED ==1)
		{
			IS_FIRST_CAPTURED =0;
			IC_Val2 =	HAL_TIM_ReadCapturedValue (htim ,TIM_CHANNEL_3 );
			__HAL_TIM_SET_COUNTER (htim ,0);
			
			if(IC_Val1 <IC_Val2 )
			{
				Difference=IC_Val2 -IC_Val1 ;
			}
			else if(IC_Val1 >IC_Val2)
			{
				Difference=0xffff- IC_Val1 +IC_Val2 ;
			}
		Distance = Difference *0.017;
		__HAL_TIM_SET_CAPTUREPOLARITY (htim ,TIM_CHANNEL_3 ,TIM_INPUTCHANNELPOLARITY_RISING );
		__HAL_TIM_DISABLE_IT (&htim2 ,TIM_IT_CC3 );
		}
	
	}
}

然后在主函数中调用该函数即可,最后加上oled显示部分的代码:OLED_ShowNum(30,6,Distance,2,16);
        HAL_Delay (100);

(上一篇文章已经记过oled模块,这里不再赘述)(39条消息) 智能门锁学习一,按键解锁,蓝牙解锁、oled显示,步进电机_泡菜鱼111的博客-CSDN博客

关于溢出问题的补充:

昨天经过一位大佬的指导,对这个问题有了更深刻的理解,赶紧记下来以防忘了哈哈哈哈==

上面的那种方法arr设置的是最大65535,一般不会溢出,自然也就避免了这个问题。

如果要考虑溢出问题的话,比如arr设置的99,即数99个数就溢出一次,我们就要用一个变量来记下溢出次数,定时器设置成100微秒的话(71  99)在溢出回调里对这个变量++来记录次数,然后输入捕获回调里和上面的类似,捕获到上升沿时记下此时定时器的计数值给buff[0],并对定时器计数值清零,记录溢出次数的变量清零,然后设置成下降沿捕获,捕获到下降沿时进入case 1 ,读取此时定时器的计数值给buff[1],关闭输入捕获,此时计数器计的数等于:buff[1] 加上溢出次数*99,由于设置的是微秒,所以高电平时间等于定时器计的数除以990(0.1毫秒溢出99次,1毫秒溢出990次),得到的是毫秒级的,然后距离等于高电平时间乘声速除以2,注意变换单位,最后对变量清零,设置上升沿,重新打开捕获即可。

大致思路就是这些,巧妙的运用两个回调解决了溢出的问题,已经很详细了,大佬的代码就不放上来了===

  • 5
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值