• STM32标准库通用定时器输入捕获


    STM32标准库定时器输入捕获

    1.输入捕获介绍

    输入捕获为STM32定时器的一个功能,可以用来测量输入信号的频率和占空比。

    具体原理:当输入信号经过比较捕获通道时,STM32会依据通道的极性设置决定是否触发捕获中断TIM_IT_CCx。此时定时器会将当前计数值TIMx->CNT的值保存在TIMx->CCRx中,通过计算两次捕获中断的时间差便可计算出捕获的电平时长,由此可计算出输入信号的频率、周期、占空比等信息。

    在本文中,使用野火指南者开发板,配置TIM2定时器的通道4为输入通道,TIM3定时器的通道1为输出通道。

    2. 输入捕获通道与定时器初始化

    需要引用头文件

    #include "stm32f10x_gpio.h"
    #include "stm32f10x_rcc.h"
    #include "stm32f10x_tim.h"
    void TIM2_Init()                                            // 定时器2初始化
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     // 使能定时器2的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);    // 使能GPIOA的时钟
    	
    	GPIO_InitTypeDef GPIO_InitStructure;                    // 定义GPIO_InitTypeDef类型的结构体
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;      // 定义TIM_TimeBaseInitTypeDef类型的结构体
    	TIM_ICInitTypeDef TIM_IC_nitStructure;                  // 定义TIM_ICInitTypeDef类型的结构体
    	
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ;              // 选择通道4的引脚
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 设置通道4为浮空输入
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速度为50MHz
    	GPIO_Init(GPIOA,&GPIO_InitStructure);                   // 初始化GPIOA
    	
    	TIM_TimeBaseInitStructure.TIM_Period = 1000-1;          // 设置定时器2的自动重装值,计数到1000-1
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;	    // 设置定时器2的预分频值,分频720-1
    	TIM_TimeBaseInitStructure.TIM_ClockDivision  = TIM_CKD_DIV1;    // 设置时钟分割
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数器模式为向上计数
    	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);      // 初始化定时器2
    	
    	TIM_IC_nitStructure.TIM_Channel = TIM_Channel_4;        // 选择通道4
    	TIM_IC_nitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;     // 设置通道4的上升沿触发
    	TIM_IC_nitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;   // 设置通道4的输入分频器
    	TIM_IC_nitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 设置通道4映射到TI4
    	TIM_IC_nitStructure.TIM_ICFilter = 0x00;                // 设置通道4的滤波器
    	TIM_ICInit(TIM2,&TIM_IC_nitStructure);                  // 初始化定时器2的通道4
    	
    	NVIC_InitTypeDef NVIC_InitStructure;                    // 定义NVIC_InitTypeDef结构体变量
    	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;         // 选择定时器2的中断通道
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       // 设置中断优先级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      // 设置中断子优先级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         // 使能中断通道
    	
    	NVIC_Init(&NVIC_InitStructure);                         // 初始化NVIC_InitTypeDef结构体变量
    	
    	TIM_ITConfig(TIM2,TIM_IT_CC4 | TIM_IT_Update ,ENABLE);  // 使能定时器2的通道4的中断和更新中断
    	
    	TIM_Cmd(TIM2,ENABLE);                                   // 使能定时器2
    }

    需要注意输入通道引脚为GPIO_Mode_IN_FLOATING模式,TIM_Period为定时器溢出值。

    • TIM_ICInitTypeDef:输入捕获通道配置结构体。

      • TIM_Channel:输入通道,可选参数为TIM_Channel_x。

      • TIM_ICPolarity:输入通道极性设置,可选参数为TIM_ICSelection_DirectTI、TIM_ICSelection_IndirectTI、TIM_ICSelection_TRC。

        • TIM_ICSelection_DirectTI:将定时器输入通道1、2、3、4依次映射到IC1、IC2、IC3、IC4。

        • TIM_ICSelection_IndirectTI:将定时器输入通道1、2、3、4依次映射到IC2、IC1、IC4、IC3。

        • TIM_ICSelection_TRC:将定时器输入通道1、2、3、4连接至TRC我暂时也不知道这个TRC是啥

      • TIM_ICFilter:输入通道滤波器设置,可选参数为0x0~0xF。决定了多少次边沿变换会触发一次输入捕获。

    3. 中断函数编写

    输入捕获中断与定时器中断共用一个中断NVIC。

    uint16_t Up_Capture_Cnt,Down_Capture_Cnt,Up_Capture,Up_Capture_Cnt_Temp,Down_Capture;
    uint16_t timer_cnt2,timer_cnt1 = 0;
    uint16_t Get_State = 0,Get_State1 = 0;
    
    void TIM2_IRQHandler()                              // 定时器2中断函数
    {
    	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)  // 定时器2更新中断
    	{
    		timer_cnt1++;                               // 定时器计数标志量1每溢出一次加一
    		timer_cnt2++;                               // 定时器计数标志量2每溢出一次加一
    		if(timer_cnt1 == 10000)                     // 定时器计数标志量1溢出时清零
    		{
    			timer_cnt1 = 0;                         // 定时器计数标志量1清零
    		}
    		if(timer_cnt2 == 10000)                     // 定时器计数标志量2溢出时清零
    		{
    			timer_cnt2 = 0;                         // 定时器计数标志量2清零
    		}
    	}
    	if(TIM_GetITStatus(TIM2,TIM_IT_CC4) == SET)     // 定时器2输入捕获中断
    	{
    		switch(Get_State)                           // 判断输入捕获状态
    		{
    			case 0 :            
    				Up_Capture_Cnt_Temp = Up_Capture_Cnt;       // 保存上一次输入捕获通道的值
    				Down_Capture_Cnt =  TIM_GetCapture4(TIM2);  // 获取当前输入捕获通道的值
    				Down_Capture = Down_Capture_Cnt + (timer_cnt2 * 1000) - Up_Capture_Cnt_Temp;    // 计算脉冲宽度
    				timer_cnt1 = 0;                             // 定时器计数标志量1清零
    				timer_cnt2 = 0;                             // 定时器计数标志量2清零
    				TIM_ClearITPendingBit(TIM2,TIM_IT_CC4);     // 清除输入捕获通道的中断标志位
    				TIM_OC4PolarityConfig(TIM2,TIM_ICPolarity_Falling); // 设置输入捕获通道的极性为下降沿
    				Get_State = 1;                              // 设置输入捕获通道的状态为1
    				break;                                      // 跳出switch语句
    			case 1:         
    				Up_Capture_Cnt =  TIM_GetCapture4(TIM2);    // 获取当前输入捕获通道的值
    				Up_Capture = Up_Capture_Cnt + (timer_cnt1 * 1000) - Down_Capture_Cnt;           // 计算脉冲宽度
    				timer_cnt1 = 0;                             // 定时器计数标志量1清零
    				timer_cnt2 = 0;                             // 定时器计数标志量2清零
    				TIM_ClearITPendingBit(TIM2,TIM_IT_CC4);     // 清除输入捕获通道的中断标志位
    				TIM_OC4PolarityConfig(TIM2,TIM_ICPolarity_Rising);  // 设置输入捕获通道的极性为上升沿
    				Get_State = 0;                              // 设置输入捕获通道的状态为0
    				break;                                      // 跳出switch语句
    		}
    	}
    	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);              // 清除定时器溢出中断标志位
    }

    4. 中断函数代码具体逻辑解释

    光看代码可能捋不清先后关系,来看下图就知道了,如图1所示:

    alt text

    图1.采集输入捕获信号矢量图
    在图中可以看到,当输入捕获通道的信号周期要长于输入捕获的通道时钟周期时,会导致第二次读取的值比第一次读取的值小,如果不使用定时器溢出次数进行辅助运算会导致算出来的是负数。之后第一次读取的值+溢出时间-第二次读取的值,得到的结果就是脉冲宽度,第二次读取的值+溢出时间-第一次读取的值,得到的就是周期中另一部分的宽度。有了这些信息,就可以得到频率、周期和占空比了。

    __EOF__

  • 本文作者: T7H
  • 本文链接: https://www.cnblogs.com/tqht7h/p/18067071
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    防脱发、再生发
    Oracle如何快速删除表中重复的数据
    第5章 Object Interactive
    某电商网站的数据库设计(4)——创建各个基础表之间的关联视图
    CocosCreator-常见问题和解决-持续更新
    【JavaEE进阶系列 | 从小白到工程师】基本类型包装类的使用,装箱以及拆箱与parseInt方法
    New Concept English3 Lesson 1. A puma at large【精讲学习笔记】
    如何下不可选中的文章
    XML文件的解析读取(详解)
    设计模式--builder 模式
  • 原文地址:https://www.cnblogs.com/tqht7h/p/18067071