STM32CubeMX | STM32使用HAL库进行脉冲宽度和周期测量
使用芯片:STM32F103RCT6
思路:定时器设置为1MHZ的计数频率,定时计数器增加一就是增加1us
① 首先设置为上升沿捕获,捕获上升沿记录此刻的时间计数值;
② 然后切换为下降沿捕获,捕获下降沿记录此刻的时间计数值;
③ 最后设置为上升沿捕获,捕获上升沿记录此刻的时间计数值;**
对于16bit定时器,最大可计数0xFFFF,也就是65535us,那么:高电平持续的时间 = 定时器溢出计数 * 0xFFFF + 当前计数值
对于32bit定时器,最大可计数0xFFFFFFFF,也就是4294.967295s,这个时间足够测量脉冲宽度的了,那么:高电平持续的时间 = 当前计数值
高电平持续的时间 = ② - ①
周期 = ③ - ①
定时器配置
设置定时器2的计数频率为1MHz,输入捕获使用通道一,也就是PA0引脚,将PA0引脚设置为下拉模式,目的是为了在空闲时间保持信号稳定:
中断分组设置
代码配置
tim.c中添加如下代码:
__IO uint32_t TIM2_TIMEOUT_COUNT = 0; ///< 定时器2定时溢出计数
uint32_t TIM2_CAPTURE_BUF[3] = {0, 0, 0}; ///< 分别存储上升沿计数、下降沿计数、下个上升沿计数
__IO uint8_t TIM2_CAPTURE_STA = 0xFF; ///< 状态标记
/**
* 设置TIM2输入捕获极性
* @param TIM_ICPolarity:
* TIM_INPUTCHANNELPOLARITY_RISING :上升沿捕获
* TIM_INPUTCHANNELPOLARITY_FALLING :下降沿捕获
* TIM_INPUTCHANNELPOLARITY_BOTHEDGE:上升沿和下降沿都捕获
*/
inline void TIM2_SetCapturePolarity(uint32_t TIM_ICPolarity)
{
htim2.Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP);
htim2.Instance->CCER |= (TIM_ICPolarity & (TIM_CCER_CC1P | TIM_CCER_CC1NP));
}
/// 定时器2时间溢出回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == htim2.Instance)
{
TIM2_TIMEOUT_COUNT++; // 溢出次数计数
}
}
///< 输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == htim2.Instance)
{
switch (TIM2_CAPTURE_STA)
{
case 1:
{
printf("准备捕获下降沿...\r\n");
TIM2_CAPTURE_BUF[0] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + TIM2_TIMEOUT_COUNT * 0xFFFF;
TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_FALLING); // 设置为下降沿触发
TIM2_CAPTURE_STA++;
break;
}
case 2:
{
printf("准备捕获下个上升沿...\r\n");
TIM2_CAPTURE_BUF[1] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + TIM2_TIMEOUT_COUNT * 0xFFFF;
TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING); // 设置为上升沿触发
TIM2_CAPTURE_STA++;
break;
}
case 3:
{
printf("捕获结束...\r\n");
printf("# end ----------------------------------------------------\r\n");
TIM2_CAPTURE_BUF[2] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + TIM2_TIMEOUT_COUNT * 0xFFFF;
HAL_TIM_IC_Stop_IT(htim, TIM_CHANNEL_1); // 停止捕获
HAL_TIM_Base_Stop_IT(&htim2); // 停止定时器更新中断
TIM2_CAPTURE_STA++;
break;
}
default:
break;
}
}
}
///< TIM2轮训状态切换
inline void TIM2_Poll(void)
{
switch (TIM2_CAPTURE_STA)
{
case 0:
{
printf("# start ----------------------------------------------------\r\n");
printf("准备捕获上升沿...\r\n");
TIM2_TIMEOUT_COUNT = 0;
__HAL_TIM_SET_COUNTER(&htim2, 0); // 清除定时器2现有计数
memset(TIM2_CAPTURE_BUF, 0, sizeof(TIM2_CAPTURE_BUF)); // 清除捕获计数
TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING); // 设置为上升沿触发
HAL_TIM_Base_Start_IT(&htim2); // 启动定时器更新中断
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // 启动捕获中断
TIM2_CAPTURE_STA++;
break;
}
case 4:
{
uint32_t high = TIM2_CAPTURE_BUF[1] - TIM2_CAPTURE_BUF[0];
uint32_t cycle = TIM2_CAPTURE_BUF[2] - TIM2_CAPTURE_BUF[0];
float frq = 1.0 / (((float)cycle) / 1000000.0);
TIM2_CAPTURE_STA++;
printf("\r\n\r\n");
printf("################################# START #########################################\r\n");
printf("高电平持续时间:%dms\r\n", high / 1000);
printf("周期 :%dms\r\n", cycle / 1000);
printf("频率 :%fHz\r\n", frq);
printf("################################## END ##########################################\r\n\r\n");
break;
}
default:
break;
}
}
main.c:
int main()
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
DEBUG_UART_Init();
MX_TIM2_Init();
printf("================================ 系统运行! ================================ \r\n");
while(1)
{
TIM2_Poll();
DEBUG_UART_RecvHandler();
}
}
说明:串口一接串口调试助手,勾选发送新行,向单片机发送任意字符以此来启动输入捕获。
ends…