STM32定时器输入捕获测量高电平时间

STM32定时器输入捕获测量高电平时间

本篇内容要求读者对STM32通用定时器有一点理解,如有不解,请看 夜深人静学32系列15------通用定时器

输入捕获

  • 输入捕获是STM32通用定时器的一种功能,可以捕获特定引脚的电平变化(上升沿/下降沿)
  • 对于一个变化的信号。只需要测量上升沿与下降沿的时间间隔,即可计算出高电平的时间。

当上述时间间隔过长时,由于定时器计数范围有限,因此可能存在溢出的情况,这点需要注意。解决办法如下:

  • 检测到第一个有效沿时清空定时器计数值,创建一个变量TIM5CH1_CAP_STA,在每次定时器溢出时,TIM5CH1_CAP_STA加1,检测到第二个有效沿时,读取定时器计数值,那么:
  • 时间间隔 = TIM5CH1_CAP_STA*定时器计数值最大值+定时器当前计数值

测量高电平时间

CuebMX配置


其它部分设置,请参照往期内容,这里不做赘述,同时需开启定时器3的中断

代码部分

  • main.c
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
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);               // 使能定时器        
        }   
    }
}

串口重定向部分代码,这里不做展示,往期内容中有...下面来讲一下代码流程

  1. 系统正常运行,检测到第一个上升沿,进入HAL_TIM_IC_CaptureCallback(),执行以下代码

清除定时器计数值,设置下一次触发为下降沿触发。。。

2.等待下一次下降沿触发,期间定时器一直计数,过程中可能存在定时器溢出,溢出进入HAL_TIM_PeriodElapsedCallback(),执行以下代码

记录期间定时器溢出的次数。

  1. 检测到第二个下降沿,进入HAL_TIM_IC_CaptureCallback(),执行以下代码

读取当前定时器计数值,标记捕获高电平持续时间完成

  1. main函数里面计算持续时间,至此完成一次高电平持续时间检测
相关推荐
嵌新程2 小时前
day06(单片机高级)PCB设计
单片机·嵌入式硬件·pcb
stm 学习ing3 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
LateBloomer7776 小时前
FreeRTOS——信号量
笔记·stm32·学习·freertos
wenchm7 小时前
细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法
stm32·单片机·嵌入式硬件
编码追梦人8 小时前
如何实现单片机的安全启动和安全固件更新
单片机
电子工程师UP学堂8 小时前
电子应用设计方案-16:智能闹钟系统方案设计
单片机·嵌入式硬件
飞凌嵌入式8 小时前
飞凌嵌入式T113-i开发板RISC-V核的实时应用方案
人工智能·嵌入式硬件·嵌入式·risc-v·飞凌嵌入式
blessing。。10 小时前
I2C学习
linux·单片机·嵌入式硬件·嵌入式
嵌新程11 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin20123011 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件