深入了解TIM在STM32微控制器中的应用

一、TIM简介

  • TIM(timer)定时器
  • 在STM32中,定时器的基准时钟一般为主频72MHZ的
  • 关键结构:由16位计数器、预分频器、自动重装寄存器组成的时基单元。
  • 基本定时中断功能:定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
  • 除了基本的定时中断功能,还具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能。
  • STM32的定时器可以分为基本定时器、通用定时器(最常用)、高级定时器三种类型。
  • 二、TIM基本结构

    2.1 定时器类型介绍


    2.2 各类型定时器基本结构图

    2.2.1 基本定时器

    时基单元部分

  • 红框部分为时基单元,是TIM最基本的计数计时模块。
  • PSC预分频器:对输入的时钟频率进行分频,输出频率=输入频率/(PSC+1)
  • PSC=0为一分频(不分频),PSC=1为二分频,以此类推。
  • CNT计数器:每一个上升沿,计数器计数,计数至目标值后重新置0。
  • 每次计数至目标值并置0时,都会触发一次定时中断,实现定时器的定时中断功能(也可以不产生中断,而更新事件,触发内部其他电路)
  • ARR自动重装寄存器:CNT计数器的目标值。
  • 定时中断频率计算:定时中断频率 = 时钟源频率 / (PSC+1)/(ARR+1)
  • 其他部分

  • 时基单元的输入为连接着内部时钟的触发控制器,基本定时器的时钟源只能是内部时钟,频率为系统的主频72MHZ。(通用定时器和高级定时器可以选择不同的时钟源)
  • 基本定时器还有主模式触发DAC的功能:触发控制器的TRGO直接接到DAC的触发引脚,以触发DAC,不需要软件的参与。
  • 2.2.2 通用定时器


    时基单元部分

  • 时基单元部分与基本定时器一致,但CNT计数器的计数模式不再只有向上计数模式一种了,通用计数器和高级计数器还支持向下计数模式和中央对齐模式(但仍常用向上计数模式)。
  • 时钟源选择部分

  • 通用定时器可以选择内部时钟(72MHZ)或者外部时钟
  • 外部时钟来源:
    1. ETRF,来自外部时钟源ETR,此时为外部时钟模式2
    2. TRGI,此时为外部时钟模式1,来源可以是ETR外部时钟源(与模式2效果相同),也可以是ITR(ITR连接其他定时器的TRGO输出),也可以是TI1F_ED(TI1F_ED连接输入捕获单元的CH1引脚)
  • 输出比较电路

  • 可用于输出PWM波形,驱动电机
  • 输入捕获电路

  • 可用于测量输入方波的频率
  • 因为与输出比较电路的寄存器、输入输出引脚都是共用的,所以与输出比较电路不能同时使用。
  • 2.2.3 高级定时器

  • 重复计数器:可以实现若干个计数周期才触发一次更新事件或更新中断,延长了最大定时时间。

  • 对输出比较模块的升级:对输出比较模块的前三个通道加了额外的死区生成和互补输出功能,用于三相电机,略。

  • 三、定时中断功能

    3.1 定时中断简介

  • 功能介绍:时基单元中的CNT计数器会对输入的时钟进行计数,并在计数值达到设定值(ARR)时触发中断或更新事件(即每个一段指定时间就触发一次中断)。
  • 3.2 定时中断基本结构

  • 针对通用定时器,针对定时中断功能
  • 使用定时中断功能流程:开启定时器的RCC时钟 → 选择时基单元的时钟源 → 配置时基单元 → 配置中断输出控制 → 配置NVIC → 配置运行控制 → 编写中断函数
  • 3.3 定时中断初始化配置

    '1. 开启RCC时钟'
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);		// 使能TIM2的时钟(位于APB1总线上)
    
    '2. 选择时基单元的时钟源'
    TIM_InternalClockConfig(TIM2);		// 选择内部时钟作为时钟源(内部时钟是定时器初始化后的默认时钟源,所以可以不写)
    
    '3. 配置时基单元'
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;		// 结构体初始化,然后填入结构体
    TIM_TimeBaseInitstruct.TIM_ClockDivision = TIM_DIV1;		// 选择滤波器频率分频值
    TIM_TimeBaseInitstruct.TIM_CounterMode = TIM_CounterMode_Up;		// 选择计数器模式
    TIM_TimeBaseInitstruct.TIM_Period =10000 - 1;		// 选择ARR自动重装器的值(0-65535)
    TIM_TimeBaseInitstruct.TIM_Prescaler = 7200 - 1;		// 选择PSC预分频器的值(0-65535)
    TIM_TimeBaseInitstruct.TIM_RepetitionCounter = 0;		// 选择重复计数器的值(高级定时器才有,配置通用定时器时写0即可)
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitstruct);
    
    '4. 配置输出中断控制'
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    '5. 配置NVIC'
    //见EXTI外设
    
    '6. 运行控制'
    TIM_Cmd(TIM2, ENABLE);
    
    '7. 定时中断的初始化已完成,编写对应中断函数'
    void TIM2_IRQHandler(void)
    {
    	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    	{
    		'中断需要执行的代码'
    		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    	}
    }
    

    3.4 常用TIM库函数

    void TIM_DeInit(TIM_TypeDef* TIMx)
    		// 重置配置
    void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitstruct);
    		// 时基单元初始化(对应----3. 配置时基单元)
    void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitstruct);
    		// 初始化结构体变量
    
    xvoid TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct);
    xvoid TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitstruct);
    
    void TIM_Cmd(TIM_TypeDef* TIMx, Functionalstate NewState);
    		// 计数器使能/失能(对应----6. 运行控制)
    void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, Functionalstate Newstate);
    		// 中断输出信号使能/失能(对应----4.配置输出中断控制)
    		
    xvoid TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_Eventsource);
    xvoid TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16 t_TIM_DMABurstlength);
    xvoid TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, Functionalstate Newstate);
    
    // 以下6个函数对应----2. 选择时基单元的时钟源
    void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
    		// 选择内部时钟
    void TIM_ITRxExternalclockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
    		// 选择ITRx其他定时器的时钟
    void TIM_TIxExternalclockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIXExternalciksource,uint16_t TIM_ICPolarity,uint16_t ICFilter);
    		// 选择TIX捕获通道的时钟
    void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
    		// 选择ETR通过外部时钟模式1输入的时钟
    void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
    		// 选择ETR通过外部时钟模式2输入的时钟
    void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolar, uint16_t ExtTRGFilter);
    		// 配置ETR引脚的预分频器、极性、滤波器等参数
    void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
    		// 单独写入预分频值
    void TIM_CounterModeConfig(TIM_TypeDef* TIMx,uint16_t TIM_CounterMode);
    		// 单独改变计数器的计数模式
    void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
    		// 计数器预装功能使能/失能
    		
    xvoid TIM_SelectCOM(TIM_TypeDef* TIMx, FunctionalState NewState);
    xvoid TIM_SelectCCDMA(TIM_TypeDef* TIMx, FunctionalState NewState);
    xvoid TIM_CCPreloadControl(TIM_TypeDef* TIMx, FunctionalState NewState);
    xvoid TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
    xvoid TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
    xvoid TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource);
    xvoid TIM_SelectHallSensor(TIM_TypeDef* TIMx, FunctionalState NewState);
    xvoid TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode);
    xvoid TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode);
    
    void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
    		// 给计数器写入一个值
    void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
    		// 给自动重装器写入一个值
    
    xvoid TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);
    
    uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
    		// 获取当前计数器的值
    uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);
    		// 获取当前预分频器的值
    // 以下四个函数为获取/清除标志位函数,各外设的库函数形式一致,可参考EXTI模块
    FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
    void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
    ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
    void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
    

    四、输出比较功能

    4.1 输出比较简介

  • OC(Output Compare)输出比较
  • 功能介绍:输出比较功能可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作(即通过比较计数器和寄存器的大小,对输出电平定时执行置1置0翻转等操作),可用于输出一定频率和占空比的PWM波形。
  • 每个高级定时器和通用定时器都拥有4个输出比较通道
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能,用于三项电机。
  • PWM(Pulse Width Modulation)脉冲宽度调制。在具有惯性的系统中(电机速度惯性、人眼视觉惯性等),可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域(即用方波脉冲占空比的变化来表示模拟量的变化)。
  • 单片机只需要对电机输出PWM的电平波形即可,电机会根据电平波形输出不同的转速。
  • PWM参数:
    频率 = 1 / Ts;占空比 = Ton / Ts;分辨率 = 占空比变化步距
  • 4.2输出比较基本结构

  • 输出比较单元中的第二个模块“输出模式控制器”,能控制输出比较模式
  • 常用PWM模式
  • 使用输出比较功能流程:开启定时器/GPIO的RCC时钟 → 选择时基单元的时钟源 → 配置时基单元 → 配置输出比较单元(CCR的值、输出比较模式、极性选择、输出使能) → 配置GPIO → 配置运行控制
  • 4.3 输出比较初始化配置

    '1. 开启RCC时钟'
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);		// 使能TIM2的时钟(位于APB1总线上)
    
    '2. 选择时基单元的时钟源'
    TIM_InternalClockConfig(TIM2);		// 选择内部时钟作为时钟源(内部时钟是定时器初始化后的默认时钟源,所以可以不写)
    
    '3. 配置时基单元'
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;		// 结构体初始化,然后填入结构体
    TIM_TimeBaseInitstruct.TIM_ClockDivision = TIM_DIV1;		// 选择滤波器频率分频值
    TIM_TimeBaseInitstruct.TIM_CounterMode = TIM_CounterMode_Up;		// 选择计数器模式
    TIM_TimeBaseInitstruct.TIM_Period =10000 - 1;		// 选择ARR自动重装器的值(0-65535)
    TIM_TimeBaseInitstruct.TIM_Prescaler = 7200 - 1;		// 选择PSC预分频器的值(0-65535)
    TIM_TimeBaseInitstruct.TIM_RepetitionCounter = 0;		// 选择重复计数器的值(高级定时器才有,配置通用定时器时写0即可)
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitstruct);
    
    '4. 配置输出比较单元'
    TIM_OCInitTypeDef TIM_OCInitStructure;			// 定义结构体变量,然后填入结构体
    TIM_OCStructInit(TIM_OCInitStructure);			// 结构体初始化,防止一些参数没赋值导致问题
    TIM_OCInitStructure.OCMode = TIM_OCMode_PWM1;			// 设置输出模式
    TIM_OCInitStructure.OCPolarity = TIM_OCPolarity_High;	//设置输出比较极性
    TIM_OCInitStructure.OutputState = ENABLE;				// 设置使能
    TIM_OCInitStructure.Pulse = ;							// 设置CCR寄存器的值(0-0xffff)
    TIM_OC1Init(TIM2, &TIM_OCInitStructure)
    
    '5. 开启GPIO时钟以及配置GPIO'
    // 见GPIO		// 需要选用复用推挽输出模式
    
    '6. 运行控制'
    TIM_Cmd(TIM2, ENABLE);
    
    

    4.4 常用TIM库函数

    void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitstruct);
    void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitstruct);
    void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitstruct);
    void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitstruct);
    		// 四个输出比较通道的输出比较单元初始化函数
    void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitstruct);
    		// 结构体初始化函数
    void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
    		// 四个通道配置强制输出模式
    void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
    		// 四个通道配置CCR寄存器的预装功能(影子寄存器)
    void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
    		// 四个通道配置快速使能
    void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
    		// 四个通道清除REF信号
    void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
    void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
    void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
    void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
    		// 四个通道修改输出极性,(第四个通道没有互补通道)
    void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
    void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
    		// 修改输出使能参数
    void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
    		// 修改输出比较模式
    void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
    void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
    void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
    void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
    		// 四个通道修改CCR寄存器的值(用来改变PWM的占空比)
    

    五、输入捕获功能

    5.1 输入捕获简介

  • IC(Input Capture)输入捕获
  • 功能介绍:输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中(即寄存器会记录输入引脚跳变瞬间的计数器值),可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数。
  • 每个高级定时器和通用定时器都拥有4个输入捕获通道。
  • 可配置为PWMI模式,同时测量频率和占空比。
  • 可配合主从触发模式,实现硬件全自动测量。
  • 频率测量方法:测频法、测周法:略
  • 5.2 输入捕获基本结构

  • 执行逻辑:GPIO口连接输入捕获单元的输入口,GPIO的电平信号经过滤波器、边沿检测、极性选择后成为TI1FP1信号,当检测到触发信号(上升沿)时,CCR寄存器记录当前CNT计数器的值,同时TI1FP1信号作为从模式的触发源,触发从模式执行Reset操作,清零CNT计数器。
  • 使用输入捕获功能流程:开启定时器/GPIO的RCC时钟 → 选择时基单元的时钟源 → 配置时基单元 → 配置输入捕获单元(滤波器、极性选择(边沿检测)、通道选择、分频器) → 选择从模式的触发源 → 选择从模式执行的操作 → 配置GPIO → 配置运行控制
  • PWMI模式基本结构

  • PWMI模式使用两个输入捕获通道,同时捕获同一个GPIO的信号。
  • 第一个通道与上面相同,捕获GPIO触发信号(上升沿),记录每次上升沿的CNT计数器
  • 第二个通道选择交叉通道输入,配置为下降沿触发,记录每次下降沿的CNT计数器,达到测量信号占空比的功能
  • 5.3 输入捕获初始化配置

    '1. 开启RCC时钟'
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);		// 使能TIM2的时钟(位于APB1总线上)
    
    '2. 选择时基单元的时钟源'
    TIM_InternalClockConfig(TIM2);		// 选择内部时钟作为时钟源(内部时钟是定时器初始化后的默认时钟源,所以可以不写)
    
    '3. 配置时基单元'
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;		// 结构体初始化,然后填入结构体
    TIM_TimeBaseInitstruct.TIM_ClockDivision = TIM_DIV1;		// 选择滤波器频率分频值
    TIM_TimeBaseInitstruct.TIM_CounterMode = TIM_CounterMode_Up;		// 选择计数器模式
    TIM_TimeBaseInitstruct.TIM_Period =10000 - 1;		// 选择ARR自动重装器的值(0-65535)
    TIM_TimeBaseInitstruct.TIM_Prescaler = 7200 - 1;		// 选择PSC预分频器的值(0-65535)
    TIM_TimeBaseInitstruct.TIM_RepetitionCounter = 0;		// 选择重复计数器的值(高级定时器才有,配置通用定时器时写0即可)
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitstruct);
    
    '4. 配置输入捕获单元'
    TIM_ICInitTypeDef TIM_ICInitStructure;				// 结构体初始化,然后填入结构体
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;	// 选择输入捕获电路的通道(1~4)
    TIM_ICInitStructure.TIM_ICFilter = 0xf;				// 配置输入捕获滤波器(0x0~0xf)
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;			// 配置极性选择(边沿检测),上升沿触发
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPrescaler_DIV1;			// 配置分频器
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;		// 配置数据选择器(直连通道or交叉通道)
    TIM_ICInit(TIM2, &TIM_ICInitStructure)
    
    '5. 选择从模式触发源、选择从模式的操作模式'
    TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);
    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);
    
    '6. 开启GPIO时钟以及配置GPIO'
    // 见GPIO		// 需要选用上拉输入模式
    
    '7. 运行控制'
    TIM_Cmd(TIM2, ENABLE);
    
    '8. 用库函数获取CCR寄存器的值进行运算,就能得到信号频率了'
    
    '9. 如果使用PWMI模式'
    '将4中的TIM_ICInit改为TIM_PWMIConfig即可'
    TIM_PWMIConfig(TIM2, &TIM_ICInitStructure)
    		// 该函数会自动将结构体变量中没选择的另一个通道设置为交叉通道反向触发
    
    

    5.4 常用TIM库函数

    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);
    		// 选择从模式输入的触发源
    void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
    		// 选择主模式输出的触发源
    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);
    		// 四个通道配置分频器
    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);
    		// 四个通道读取CCR寄存器的值
    

    六、编码器接口功能

    6.1 编码器接口简介

  • Encoder Interface 编码器接口
  • 编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度。(即通过外部设备正交编码器生成正交脉冲信号,通过GPIO导入信号到定时器,定时器可以根据导入的正交信号自动控制CNT计数器的增减,以此判断编码器的位置、方向、速度
  • 每个高级定时器和通用定时器都拥有1个编码器接口
  • 两个输入引脚借用了输入捕获的通道1和通道2
  • 正交信号可以有效消除毛刺/抖动。
  • 6.2 编码器接口基本结构

  • 编码器接口功能的输入通道无法更改,固定为前两个通道,外部引脚也固定为TIMx_CH1和TIMx_CH2。
  • 编码器接口功能不需要选择时基单元的时钟源,因为编码器接口会代替时钟源来控制时基单元计数。
  • 使用编码器接口功能流程:开启定时器/GPIO的RCC时钟 → 配置时基单元 → 配置输入捕获单元(滤波器、极性选择) → 配置编码器接口模式 → 配置GPIO → 配置运行控制
  • 编码器接口的工作模式
  • 基本的逻辑是:在TI1和TI2信号的上升沿和下降沿时都进行判断,根据边沿的升降、另一相的高低电平,按照编码器接口设置的工作模式,进行向上计数/向下计数/不计数
  • 6.3 编码器接口初始化配置

    '1. 开启RCC时钟'
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);		// 使能TIM2的时钟(位于APB1总线上)
    '2. 配置时基单元(一般PSC选择不分频,ARR选择最大值)'
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;				// 结构体初始化,然后填入结构体
    TIM_TimeBaseStructInit(&TIM_TimeBaseInitstruct);			// 初始化结构体,防止有参数未赋值
    TIM_TimeBaseInitstruct.TIM_ClockDivision = TIM_DIV1;		// 选择滤波器频率分频值
    // 参数TIM_CounterMode		// 选择计数器模式,此处不需要配置,因为计数器被编码器接口控制
    TIM_TimeBaseInitstruct.TIM_Period =65536 - 1;		// 选择ARR自动重装器的值,编码器接口功能一般选择最大值65535
    TIM_TimeBaseInitstruct.TIM_Prescaler = 1 - 1;		// 选择PSC预分频器的值,编码器接口功能一般选择不分频0
    TIM_TimeBaseInitstruct.TIM_RepetitionCounter = 0;	// 选择重复计数器的值(高级定时器才有,配置通用定时器时写0即可)
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitstruct);
    '3. 配置输入捕获单元(滤波器、极性选择)'
    TIM_ICInitTypeDef TIM_ICInitStructure;				// 结构体初始化,然后填入结构体
    TIM_ICStructInit(&TIM_ICInitStructure);				// 初始化结构体,防止有参数未赋值
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;	// 选择输入捕获电路的通道(1~4)
    TIM_ICInitStructure.TIM_ICFilter = 0xf;				// 配置输入捕获滤波器(0x0~0xf)
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;			// 配置极性选择(边沿检测),此处上升沿代表高低电平极性不反转,若为下降沿则代表极性反转
    // 参数TIM_ICPrescaler		// 配置分频器,此处不需要配置,没有使用到
    // 参数TIM_ICSelection		// 配置数据选择器,此处不需要配置,没有使用到
    TIM_ICInit(TIM2, &TIM_ICInitStructure);			// 配置通道1完成
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;	// 选择输入捕获电路的通道(1~4)
    TIM_ICInitStructure.TIM_ICFilter = 0xf;				// 配置输入捕获滤波器(0x0~0xf)
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;			// 配置极性选择,此处上升沿代表高低电平极性不反转,若为下降沿则代表极性反转
    TIM_ICInit(TIM2, &TIM_ICInitStructure)			// 改变结构体的通道号,配置通道2完成
    '4. 配置编码器接口模式'
    TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);		
    								// 配置编码器接口;工作模式选择TI1、2都计数;IC12极性选择
    '5. 配置GPIO'
    // 略,需要配置为输入模式,上拉/下拉需要跟外部电路保持一致
    '6. 配置运行控制'
    TIM_Cmd(TIM2, ENABLE);
    

    6.4 常用TIM库函数

    void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                    uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
                                    // 编码器接口配置函数
                                    // 参数:选择定时器;选择编码器接口工作模式;选择IC1的极性;选择IC2的极性
    

    补充

  • 3.3定时中断功能初始化完成时,会立刻进入一次中断,如果不希望如此,可以在初始化过程‘3’和‘4’之间,加入语句:
  • 	TIM_ClearFlag(TIM2, TIM_FLAG_Upadate);
    
  • RCC时钟树:略

  • Reference
    STM32入门教程-2023版(江科大)

    物联沃分享整理
    物联沃-IOTWORD物联网 » 深入了解TIM在STM32微控制器中的应用

    发表评论