超声波测距模块HC SR-04(下文简写SR-04)是我们在DIY时常用的一个测距模块,其稳定,可靠,价格便宜都是它的优势,当然,它还有其它一些特性,这里不做过多介绍,请参看论坛网友keyboard007的帖子《NUCLEO-U083RC学习历程36+使用超声波模块制作实现测量距离》https://forum.eepw.com.cn/thread/393964/1。从其帖子里面可以学习整个超声波测距模块实现过程,本文仅改进其测量SR-04的高电平的实现。
距离(m)=高电平持续时间(s)*声速(340m/s)/2
对于SR-04的精度我们确认完毕,我们再来看看其最大量程。按帖子内容,可以知道SR-04的如果超过最大量程其高电平为33ms。如上所取值,如果一个tick为1us,则如果按16位计数器设置下65535计数溢出后应为65ms左右,满足我们测量33ms的需求。故,我们将Timer的tick的周期暂定为1us。
在梳理完成SR-04的原理后,我们再来看看STM32H503的性能。STM32H503为ST公司推出的一颗基于ARM公司Cortex-M33 32位RISC内核的高性能微控制器,工作频率高达250MHz。Cortex-M33核心具有一个单精度浮点单元(FPU),支持所有Arm单精度数据处理指令和所有数据类型。Cortex-M33核心还实现了一整套DSP(数字信号处理)指令和内存保护单元(MPU),增强了应用程序的安全性。该设备嵌入高速存储器(128kbytes的双bank闪存和32kbytes的SRAM),以及连接到3个APB总线、3个AHB总线和32位多AHB总线矩阵的大量增强型I/ o和外设。该器件具有多种针对嵌入式闪存和SRAM的保护机制:安全生命周期管理、写保护和隐藏保护区域。
该设备嵌入了几个增强安全性的外设:一个哈希硬件加速器和一个真正的随机数发生器。该设备提供主动篡改检测,并对瞬态和环境扰动攻击提供保护。
该器件提供一个快速的12位ADC,两个DAC通道,一个运放,一个比较器,一个低功耗RTC,一个32位通用定时器,一个16位PWM定时器专用于电机控制,一个16位通用定时器,两个16位基本定时器和两个16位低功耗定时器。该设备还具有标准和先进的通信接口,如:2个I²C, 2个i3c与I²C共享,3个spi与muxed全双工I2S, 3个USARTs和1个低功耗UART, 1个FDCAN, 1个USB全速。

配置完成Timer2的配置参数,我们再来看看我们的实现方案:

/**
* @brief TIM2 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_IC_InitTypeDef sConfigIC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 249;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4294967295;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 3;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}由于在上升沿边沿触发时,我们清空了TIM2的计数器的值,故在下降沿触发的时候其计数值即为高电平的tick数值。我们只需要将其回读出来,并代入上一章的公式即可计算出来超声波距离的数值。
实验代码就这么完成了吗?
如果我们仅仅是做个实验,一个DIY,上述代码可以完成,提交代码了。但我们仍然要多思考一下。上面的应用场景是是假设定时器没有溢出为前提的。实际上,t1到2时间段,定时器可能会产生N次溢出,这就需要我们对定时器溢出做相应的处理,防止高电平太长,导致测量出错。
在t1到t2时间段,假设定时器溢出N次,那么高电平脉冲时间内,计数器计数的个数计算方法为:N*(ARR+1)+CCRx2,CCRx2表示t2时间点,捕获/比较寄存器的值。经过计算得到高电平脉宽时间内计数器计数个数后,用这个个数乘以计数器的计数周期,就可得到高电平持续的时间。就是输入捕获测量高电平脉宽时间的整个过程。
写在最后
读到这里,细心的网友,或者正在复刻的网友会发现,其实STM32H503的输入捕获功能支持双边沿触发功能。我们只需要在触发中断里面回读一下边沿状态即可完成对应的事件处理,而不再需要重新配置TIM2的触发方式。这里我的目的在于对于普通MCU来说,其仅有边沿触发时,需要经过上述处理过程,如果有双边沿触发,我们就直接使用硬件的双边沿触发即可。简单才是可靠,越复杂,越容易出错。
我要赚赏金
