STM32 TIM输入捕获功能详解

文章目录

  • 一、TIM输入捕获
  • 输入捕获简介
  • 频率测量
  • 二、通用定时器的输入捕获通道
  • 通用定时器框图
  • 通道的输出部分
  • 三、主从触发模式
  • 主模式
  • 从模式
  • 四、输入捕获基本结构
  • 五、PWMI基本结构
  • 六、输入捕获模式测频率
  • 电路设计
  • 关键代码
  • 七、PWMI模式测频率占空比
  • 电路设计
  • 关键代码
  • 八、定时器库函数(tim.h)
  • 一、TIM输入捕获

    输入捕获简介

  • IC(Input Capture)输入捕获
  • 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔(频率)、电平持续时间(占空比)等参数
  • 每个高级定时器和通用定时器都拥有4个输入捕获通道
  • 可配置为PWMI模式,同时测量频率和占空比
  • 可配合主从触发模式,实现硬件全自动测量
  • 对于同一个定时器,由于其通道引脚是共用的,输入捕获和输出比较只能使用其中一个
  • 输入捕获的功能和外部中断类似,但是在外部中断中,引脚出现指定电平跳变的时候是向CPU申请中断,而输入捕获是将CNT锁存在CCR中,而不是进行比较
  • 频率测量

  • 测频法:在闸门时间T内【一般是1s】,对上升沿计次【一个上升沿就是一个周期】,得到N,则频率【适合高频】

  • 测周法(利用周期的倒数是频率):两个上升沿内,以标准频率fc计次【通过已知频率求】,得到N ,则频率【适合低频】

  • 中界频率:测频法与测周法误差相等的频率点【设N相同求解】,大于中界频率选测频法,小于中界频率选测周法。因为N越大,+1/1误差对频率的影响越小

  • 二、通用定时器的输入捕获通道

    通用定时器框图

  • CH1/2/3三个引脚接到异或门,只要有一个引脚电平翻转就触发一次电平翻转。该设计是为三相无刷电机服务,三个霍尔传感器检测转子的位置
  • TI1左边是数据选择器,可以选择是异或通道输出还是各个通道各自输出
  • 输入滤波器和边沿检测器:有两套滤波和边沿检测,分别输出TI1FP1和TI2FP2
  • IC1和IC2旁边的数据选择器负责交换连接:1. 灵活切换后续输入捕获电路的输入。2. 一个引脚的输入映射到两个捕获单元,也就是PWMI模式,两个通道同时对一个引脚捕获,测量占空比和频率
  • 预分频器:每来一个上升沿,将CNT存在CCR中,用于计数计时(内部时钟源可以计算时间)同时还可以触发捕获中断
  • 通道的输出部分

  • 从TI1F_ED通道或TI1FP1通道到从模式:有硬件电路可以自动完成CNT清零,
  • IC1PS通道:手动完成CNT清零
  • IC1F寄存器:

  • 滤波器:采样频率越低,采样个数N越大,滤波效果越好
  • 三、主从触发模式

    主模式

  • 将定时器内部信号映射到TRGO引脚
  • 接收其他外设信号或自身外设的信号,用于控制自身定时器的运行
  • 主模式选择
  • 从模式

  • 如图所示,通道3和4没有触发源可以选择,但可以通过触发捕获中断,在中断函数中手动清零CNT,容易消耗软件资源,不断进入中断

  • 触发源选择

  • 从模式选择

  • TIM输入捕获采用从模式:触发源选择TI1FP1,从模式中选择Reset

    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//选择输入触发源TRGI
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//选择从模式
    
  • 四、输入捕获基本结构

  • 从模式只有通道1和通道2,通道3和4只能通过在捕获中断函数里面清除CNT的值

  • 采用测周法,需要知道标准频率fc和计次N,fc就等于CNT的驱动时钟即预分频的值

  • 每次捕获完成都需要将CNT的值清零,可以用主从触发模式完成

  • 设置为输入捕获通道需要配置成浮空输入

    五、PWMI基本结构

  • CCR2捕获并不会触发CNT清零,此时高电平的计数值存放在CCR2里面

  • CCR2/CCR1=占空比

  • 函数

    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//该函数只需要传入一个通道即可,会默认将另一个通道取反配置
    
  • 六、输入捕获模式测频率

    电路设计

  • PA0通过输出比较电路输出PWM波,PA6为输入捕获通道
  • 关键代码

    IC.c

    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	TIM_InternalClockConfig(TIM3);
    	
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR,设定数值大防止溢出
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC,计数器自增频率=fc=72MHZ/(PSC+1)
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    	
    	TIM_ICInitTypeDef TIM_ICInitStructure;
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//输入捕获通道
    	TIM_ICInitStructure.TIM_ICFilter = 0xF;//滤波器
    	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//极性选择
    	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//预分频
    	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//直连还是交叉连接
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);
    	
    	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//主模式触发源
    	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//从模式配置为RESET
    	
    	TIM_Cmd(TIM3, ENABLE);
    }
    
    uint32_t IC_GetFreq(void)
    {
    	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
    	//TIM_GetCapture1/2/3/4()获取输入捕获模式下CCR寄存器的值
    }
    
    
  • 由于输出比较通道使用TIM2,而捕获/比较寄存器是不能共用的,所以输入捕获通道采用TIM3
  • PWM.c

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	TIM_InternalClockConfig(TIM2);
    	
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    	
    	TIM_OCInitTypeDef TIM_OCInitStructure;
    	TIM_OCStructInit(&TIM_OCInitStructure);
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
    	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
    	
    	TIM_Cmd(TIM2, ENABLE);
    }
    //调节PWM占空比,当ARR为100-1时,CCR就是占空比
    void PWM_SetCompare1(uint16_t Compare)
    {
    	TIM_SetCompare1(TIM2, Compare);
    }
    //调节PWM频率,由于频率收到ARR和PSC影响,修改ARR还会影响到占空比,此处只修改PSC的值
    void PWM_SetPrescaler(uint16_t Prescaler)
    {
    	TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
    	//第三个参数指定预分频器的重装模式:可以选立即生效和更新事件后生效
    }
    
    

    main.c

    修改预分频,观察输入捕获测量的频率

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "PWM.h"
    #include "IC.h"
    
    int main(void)
    {
    	OLED_Init();
    	PWM_Init();
    	IC_Init();
    	
    	OLED_ShowString(1, 1, "Freq:00000Hz");
    	
    	PWM_SetPrescaler(720 - 1);			//Freq = 72M / (PSC + 1) / 100
    	PWM_SetCompare1(50);				//Duty = CCR / 100
    	
    	while (1)
    	{
    		OLED_ShowNum(1, 6, IC_GetFreq(), 5);
    	}
    }
    
    

    七、PWMI模式测频率占空比

    电路设计

  • PA0通过输出比较电路输出PWM波,PA6为输入捕获通道
  • 关键代码

    IC.c

    #include "stm32f10x.h"                  // Device header
    
    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	TIM_InternalClockConfig(TIM3);
    	
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    	
    	TIM_ICInitTypeDef TIM_ICInitStructure;
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    	TIM_ICInitStructure.TIM_ICFilter = 0xF;
    	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    	TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//快速配置两个通道
    
    	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
    	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
    	
    	TIM_Cmd(TIM3, ENABLE);
    }
    
    uint32_t IC_GetFreq(void)
    {
    	return 1000000 / (TIM_GetCapture1(TIM3) + 1);
    }
    //获取占空比=CCR2/CCR1
    uint32_t IC_GetDuty(void)
    {
    	return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
    }
    
    

    八、定时器库函数(tim.h)

    void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//输入捕获通道初始化,四个通道占用一个函数,在结构体中可以选定通道
    void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);//快速配置两个通道,用于PWMI模式
    void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);//结构体初始化
    void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择输入触发源TRGI
    void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);//选择输出触发源TRGO
    void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);//选择从模式
    //分别配置通道的分频器
    void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
    void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
    void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
    void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
    void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);
    //分别读取四个通道的CCR值
    uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
    uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
    uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
    uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);
    
    

    参考视频:江科大自化协

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 TIM输入捕获功能详解

    发表评论