STM32 HAL库 STM32CubeMX -- TIM(定时器输入捕获)


一、输入捕获

输入捕获可以对输入的信号的上升沿、下降沿或者双边沿进行捕获,常用的有测量输入信号的脉宽测量PWM 输入信号的频率占空比这两种。

输入捕获的原理就是,当捕获到信号的跳变沿的时候,把计数器CNT 的值锁存到捕获寄存器CCR 中,把前后两次捕获到的CCR 寄存器中的值相减,就可以算出脉宽或者频率。
如果捕获的脉宽的时间长度超过你的捕获定时器的周期,就会发生溢出,这个就需要做额外的处理。

二、输入捕获功能框图

功能框图

输入通道

需要被测量的信号从定时器的外部引脚TIMx_CH1/2/3/4 进入,通常叫TI1/2/3/4,在后面的捕获讲解中对于要被测量的信号我们都以TIx 为标准叫法。

输入滤波器和边沿检测器

当输入的信号存在高频干扰的时候,我们需要对输入信号进行滤波,即进行重新采样;

根据采样定律,采样的频率必须大于等于两倍的输入信号。比如输入的信号为1M,又存在高频的信号干扰,那么此时就很有必要进行滤波,我们可以设置采样频率为2M,这样可以在保证采样到有效信号的基础上把高于2M 的高频干扰信号过滤掉。

滤波器的配置由CR1 寄存器的位CKD[1:0] 和CCMR1/2 的位ICxF[3:0] 控制。从ICxF 位的描述可知,采样频率fSAMPLE 可以由fCK_INT 和fDTS 分频后的时钟提供,其中是fCK_INT 内部时钟,fDTS是fCK_INT 经过分频后得到的频率,分频因子由CKD[1:0] 决定,可以是不分频,2 分频或者是4分频。

边沿检测器用来设置信号捕获模式:上升沿,下降沿,或双边沿,具体的由CCER 寄存器的位CCxP 和CCxNP 决定。

捕获通道

捕获通道就是图中的IC1/2/3/4,每个捕获通道都有相对应的捕获寄存器CCR1/2/3/4,当发生捕获的时候,计数器CNT 的值就会被锁存到捕获寄存器中。

输入通道是用来输入信号的,捕获通道是用来捕获输入信号的通道;

预分频器

ICx 的输出信号会经过一个预分频器,用于决定发生多少个事件时进行一次捕获。具体的由寄存器CCMRx 的位ICxPSC 配置,如果希望捕获信号的每一个边沿,则不分频。

例如:
每2个事件触发一次捕获,如上升沿捕获时,连续获取到两个上升沿后才会触发计数
每4个事件触发一次捕获
每8个事件触发一次捕获

捕获寄存器

经过预分频器的信号ICxPS 是最终被捕获的信号,当发生捕获时(第一次),计数器CNT 的值会被锁存到捕获寄存器CCR 中,还会产生CCxI 中断,相应的中断位CCxIF(在SR 寄存器中)会被置位,通过软件或者读取CCR 中的值可以将CCxIF 清0。

如果发生第二次捕获(即重复捕获:CCR 寄存器中已捕获到计数器值且CCxIF 标志已置1),则捕获溢出标志位CCxOF(在SR 寄存器中)会被置位,CCxOF 只能通过软件清零。

三、STM32Cube MX配置

基础STM32Cube MX 的配置,参考这篇博客:STM32 CubeMx教程 – 基础知识及配置使用教程

配置RCC,选择使用外部晶振模式

RCC

配置SYS,debug模式选择使用Serial Wire

SYS

配置一个串口,用于输出调试信息

USART

配置定时器,配置TIM,
将时钟源配置为内部时钟源;
配置通道1为输入捕获模式;

TIM

配置TIM里面 GPIO模式;
配置为输入模式(input mode);
配置为上拉模式(Pull - up),上拉模式模式初始电平为高电平;
按键另一端接地,初始化按键另一边为高电平,当按键按下的时候,就可以检测到低电平;

GPIO

配置打开定时器中断

中断

配置TIM详细参数;
预分频系数为7199,重装载值 99;
检测周期 Tout = (7199+1)*(99+1) / 72 000 000 = 10ms

GPIO初始为高电平,按键按下成为低电平,所以触发模式设置为下降沿模式

TIM

配置时钟树

时钟树

四、代码详解

涉及的HAL库函数

	HAL_TIM_Base_Start_IT(&htim2);  		//开启定时器2溢出中断

	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);    //开启输入捕获中断

	HAL_TIM_IC_Stop_IT(&htim2, TIM_CHANNEL_2)      //关闭输入捕获中断
       

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);	//定时器溢出回调函数

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);		//捕获中断回调函数

测量低电平的持续时间,先下降沿后上升沿,记录计数值,最终输出us单位。

代码示例:

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

//变量存储
typedef struct 
{   
    uint8_t   flg; 						//0为未开始,1已经开始,2为结束
    uint16_t  num;						//计数值
    uint16_t  num_period;			//溢出次数
}COUNT_TEMP;
 
COUNT_TEMP count_temp={0};
/* USER CODE END PD */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* 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_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

	HAL_TIM_Base_Start_IT(&htim2);  		//开启定时器2溢出中断

	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);    //开启输入捕获中断
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		
		if(count_temp.flg == 2 )		//等待测量
	{
    //计数计数值,0xFFFF为最大计数
    uint32_t ulTime = (uint32_t)count_temp .num_period * 0xFFFF + count_temp .num;
    //输出测量的值
    printf ( "low time :%d us\n",ulTime); 
    count_temp .flg = 0;     //复位测量       
	}
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/* USER CODE BEGIN 4 */

/* 每隔10ms进入一次定时器中断函数,每按下一次按键都会进入一次捕获中断函数 */
/* 捕获中断设置为下降沿捕获,因为初始电平设置的高电平 */
/* 没按下一次按键,也就是经过一个下降沿,就进入一次捕获中断函数 */
/* 进入捕获中断函数以后,开始计时,并且设置为上升沿触发下一次捕获中断 */
/* 当按键拿起,重回高电平,也就是捕获一次上升沿高电平,再次进入捕获中断函数 */
/* 进入捕获中断函数,获取记录的时间,并设置为下降沿触发中断,如此往复 */
//捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
      //判断定时器2
        if(TIM2 == htim->Instance){
            if ( count_temp.flg == 0 )
            {   
                // 清零定时器计数
                __HAL_TIM_SET_COUNTER(htim,0); 
                //设置上升沿触发
                __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
                count_temp .flg = 1;    //设置已经开始    
                count_temp .num_period = 0;    //溢出计数清零        
                count_temp .num = 0; //计数清零
            }        
            else
            {
                // 获取定时器计数值
                count_temp .num = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
                //设置下降沿触发
                __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
                count_temp .flg = 2;
            }
        }
}    
 
//定时器溢出回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(TIM2 == htim->Instance){
    //每次溢出时间为65536us
    if(count_temp.flg==1)//还未成功捕获
    {
                if(count_temp.num_period==0XFFFF)//电平太长了
                {
                    count_temp.flg=2;        //标记成功捕获了一次
                    count_temp .num=0XFFFF;
                }else count_temp .num_period ++;
    }
    }
}
/* USER CODE END 4 */

附录

本文涉及到的代码:STM32 HAL库 定时器输入捕获

  • 11
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值