STM32定时器输入捕获测量高电平时间
- 输入捕获
- 测量高电平时间
- CuebMX配置
- 代码部分
本篇内容要求读者对STM32通用定时器有一点理解,如有不解,请看 夜深人静学32系列15——通用定时器
输入捕获
- 输入捕获是STM32通用定时器的一种功能,可以捕获特定引脚的电平变化(上升沿/下降沿)
- 对于一个变化的信号。只需要测量上升沿与下降沿的时间间隔,即可计算出高电平的时间。
当上述时间间隔过长时,由于定时器计数范围有限,因此可能存在溢出的情况,这点需要注意。解决办法如下:
- 检测到第一个有效沿时清空定时器计数值,创建一个变量TIM5CH1_CAP_STA,在每次定时器溢出时,TIM5CH1_CAP_STA加1,检测到第二个有效沿时,读取定时器计数值,那么:
- 时间间隔 = TIM5CH1_CAP_STA*定时器计数值最大值+定时器当前计数值
测量高电平时间
CuebMX配置
其它部分设置,请参照往期内容,这里不做赘述,同时需开启定时器3的中断
代码部分
- main.c
extern uint8_t TIM5CH1_CAP_STA;
extern uint16_t TIM5CH1_CAP_VAL;
int main(void)
{
/* USER CODE BEGIN 1 */
long long temp = 0;// 定义一个变量用以存储捕获到的时间 long long型是为了防止数据溢出
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_3); // 一定要开启TIM5通道1的捕获中断
__HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE); // 一定要开启TIM5的更新中断
printf("This is Timer3_Channel_Input_Capture test...\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(500);
if(TIM5CH1_CAP_STA & 0X80) // 完成一次高电平捕获
{
temp = TIM5CH1_CAP_STA & 0X3F;
temp *= 65536; // 溢出总时间
temp += TIM5CH1_CAP_VAL; // 总的高电平时间
printf("High level duration:%lld us\r\n",temp);
TIM5CH1_CAP_STA = 0; // 准备下一次捕获
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
- tim.c
/* TIM5CH1_CAP_STA 各数据位说明
** bit7 捕获完成标志
** bit6 捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0; // 输入捕获状态
uint16_t TIM5CH1_CAP_VAL; // 输入捕获值
// 中断服务函数里面会自动调用这个回调函数,这个是定时器更新中断处理的函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3) // 判断定时器5是否发生中断
{
if((TIM5CH1_CAP_STA & 0X80) == 0) // 还未成功捕获
{
if(TIM5CH1_CAP_STA & 0X40) // 已经捕获到高电平
{
if((TIM5CH1_CAP_STA & 0X3F) == 0X3F)// 高电平时间太长了,做溢出处理
{
TIM5CH1_CAP_STA |= 0X80; // 标记为完成一次捕获
TIM5CH1_CAP_VAL = 0XFFFF; // 计数器值
}
else
{
TIM5CH1_CAP_STA++; // 若没有溢出,就只让TIM5CH1_CAP_STA自加
}
}
}
}
}
// 定时器输入捕获中断处理回调函数,该函数在 HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim) 中会被调用
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if((TIM5CH1_CAP_STA & 0X80) == 0) // 还未成功捕获
{
if(TIM5CH1_CAP_STA & 0X40) // 捕获到一个下降沿
{
TIM5CH1_CAP_STA |= 0X80; // 标记成功捕获到一次高电平脉宽
TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_3); // 获取当前的计数器值
TIM_RESET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_3); // 清除原来的设置
TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_3, TIM_ICPOLARITY_RISING);// 设置上升沿捕获
}
else
{
TIM5CH1_CAP_STA = 0; // 清空自定义的状态寄存器
TIM5CH1_CAP_VAL = 0; // 清空捕获值
TIM5CH1_CAP_STA |= 0X40; // 标记捕获到上升沿
__HAL_TIM_DISABLE(&htim3); // 关闭定时器
__HAL_TIM_SET_COUNTER(&htim3, 0); // 计数器值清零
TIM_RESET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_3); // 一定要先清除原来的设置 !!
TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_3,TIM_ICPOLARITY_FALLING); // 设置下降沿捕获
__HAL_TIM_ENABLE(&htim3); // 使能定时器
}
}
}
串口重定向部分代码,这里不做展示,往期内容中有…下面来讲一下代码流程
- 系统正常运行,检测到第一个上升沿,进入HAL_TIM_IC_CaptureCallback(),执行以下代码
清除定时器计数值,设置下一次触发为下降沿触发。。。
2.等待下一次下降沿触发,期间定时器一直计数,过程中可能存在定时器溢出,溢出进入HAL_TIM_PeriodElapsedCallback(),执行以下代码
记录期间定时器溢出的次数。
- 检测到第二个下降沿,进入HAL_TIM_IC_CaptureCallback(),执行以下代码
读取当前定时器计数值,标记捕获高电平持续时间完成
- main函数里面计算持续时间,至此完成一次高电平持续时间检测