本章要实现的功能是实现超声波测距并将距离显示在oled屏上,所用的板子仍是stm32f103c8t6。
目录
效果:
首先来看一下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,注意变换单位,最后对变量清零,设置上升沿,重新打开捕获即可。
大致思路就是这些,巧妙的运用两个回调解决了溢出的问题,已经很详细了,大佬的代码就不放上来了===