【STM32】细说TIM的Channels与应用
寄存器层
1、TIM_Base_Set初始化常用:
CR1:TIM control reg 1
该寄存器内容决定定时器计数模式CounterMode、分频比ClockDivision和ARR重装值何时写入有效判断AutoReloadPreload
PSC:TIM prescaler reg
该寄存器内容决定预分频Prescaler,对输入的步长进行预处理为单位时间
ARR:TIM auto_reload_reg
该寄存器内容决定周期Period
CNT:TIM counter reg
定时器计数寄存器,Period对单位时间的count
EGR:TIM event generation reg
2、TIM_OC_Set初始化常用:
CR2:TIM control reg 2
该寄存器内容决定输出引脚电平状态OCIdleState或OCNIdleState
CCMRx:TIM_capture/compare mode reg x
channel1/2-------------x = 1
channel3/4-------------x = 2
该寄存器内容决定输出模式OCMode,其中就包含了PWM
CCER:TIM capture/compare enable reg
该寄存器内容决定输出极性设置OCPolarity/OCNPolarity
CCRx:TIM capture/compare regx
该寄存器在OC模式下决定PWM的Pulse值
3、TIM_TIx_Set初始化常用:
CCMRx:TIM capture/compare reg x
channel1/2-------------x = 1
channel3/4-------------x = 2
该寄存器决定捕获通道选择ICSelection和捕获滤波器ICFilter,以及输入捕获预分频ICPrescaler,注意ICPrescaler与寄存器是直接建立联系,而不是通过TIM_TIx_Set传入寄存器的,这与TIx的定义有关
CCER:TIM capture/compare enable reg
该寄存器决定输入触发极性ICPolarity,可选择上升沿、下降沿或者双沿触发
CCRx:TIM capture/compare regx
该寄存器存储上一个输入捕获事件发生时的计数值
上述各个寄存器对应的数值,除ICPrescaler外都在各自的TIM_XXX_Set中被赋以TIM_Base_InitTypeDef、TIM_OC_InitTypeDef、TIM_IC_InitTypeDef结构体中对应成员的数值,用户只需要设定这些成员的数值就可以改变寄存器值
/** * @brief TIM Time base Configuration Structure definition */ typedef struct { uint32_t Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock. This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */ uint32_t CounterMode; /*!< Specifies the counter mode. This parameter can be a value of @ref TIM_Counter_Mode */ uint32_t Period; /*!< Specifies the period value to be loaded into the active Auto-Reload Register at the next update event. This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. */ uint32_t ClockDivision; /*!< Specifies the clock division. This parameter can be a value of @ref TIM_ClockDivision */ uint32_t RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter reaches zero, an update event is generated and counting restarts from the RCR value (N). This means in PWM mode that (N+1) corresponds to: - the number of PWM periods in edge-aligned mode - the number of half PWM period in center-aligned mode GP timers: this parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF. Advanced timers: this parameter must be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. */ uint32_t AutoReloadPreload; /*!< Specifies the auto-reload preload. This parameter can be a value of @ref TIM_AutoReloadPreload */ } TIM_Base_InitTypeDef;
/** * @brief TIM Output Compare Configuration Structure definition */ typedef struct { uint32_t OCMode; /*!< Specifies the TIM mode. This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */ uint32_t Pulse; /*!< Specifies the pulse value to be loaded into the Capture Compare Register. This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */ uint32_t OCPolarity; /*!< Specifies the output polarity. This parameter can be a value of @ref TIM_Output_Compare_Polarity */ uint32_t OCNPolarity; /*!< Specifies the complementary output polarity. This parameter can be a value of @ref TIM_Output_Compare_N_Polarity @note This parameter is valid only for timer instances supporting break feature. */ uint32_t OCFastMode; /*!< Specifies the Fast mode state. This parameter can be a value of @ref TIM_Output_Fast_State @note This parameter is valid only in PWM1 and PWM2 mode. */ uint32_t OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. This parameter can be a value of @ref TIM_Output_Compare_Idle_State @note This parameter is valid only for timer instances supporting break feature. */ uint32_t OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State @note This parameter is valid only for timer instances supporting break feature. */ } TIM_OC_InitTypeDef;
/** * @brief TIM Input Capture Configuration Structure definition */ typedef struct { uint32_t ICPolarity; /*!< Specifies the active edge of the input signal. This parameter can be a value of @ref TIM_Input_Capture_Polarity */ uint32_t ICSelection; /*!< Specifies the input. This parameter can be a value of @ref TIM_Input_Capture_Selection */ uint32_t ICPrescaler; /*!< Specifies the Input Capture Prescaler. This parameter can be a value of @ref TIM_Input_Capture_Prescaler */ uint32_t ICFilter; /*!< Specifies the input capture filter. This parameter can be a number between Min_Data = 0x0 and Max_Data = 0xF */ } TIM_IC_InitTypeDef;
Init与Config层
这一层相当于一个过渡,目的是更方便地引出API
从官方差异化的命名可以看出,定时器的输出与输入捕获有别于定时器的基本功能——定时溢出,而是在基本功能实现的情况下去做一些附加的东西,这里从回调函数也可以看出来,并不复杂就不再细说,这些函数会调用对应的TIM_XXX_Set与MspInit
用户Init层
用户需要编写Init层,通过TypeDef上述句柄,修改结构体内容并传入Init与Config层达到配置TIM特性的目的,Init与Config层、寄存器层都是封装在HAL库里的,于是我们可以得到如下关系
一层层把包含特性配置信息的句柄传入,最后赋值给寄存器
以上就是定时器初始化的部分内容
要让定时器开始工作,中断使能必不可少
CRx:TIM control regx
控制寄存器,使能时需要置位寄存器使能计数器,具体操作可由函数__HAL_TIM_ENABLE(&htim)实现
DIER:TIM DMA/interrupt enable reg
中断允许寄存器,一般情况下可调用__HAL_TIM_ENABLE_IT(&htim,TIM_IT_UPDATE)置位对应寄存器
定时器使能完成后,用户最常访问的就是定时器的状态,要访问定时器的状态,只需要下面这个寄存器
SR:TIM state reg
__HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__)
__HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__)
其中,__HANDLE__为自定义的句柄&htim,__FLAG__为各flag
/** @brief Check whether the specified TIM interrupt flag is set or not. * @param __HANDLE__ specifies the TIM Handle. * @param __FLAG__ specifies the TIM interrupt flag to check. * This parameter can be one of the following values: * @arg TIM_FLAG_UPDATE: Update interrupt flag * @arg TIM_FLAG_CC1: Capture/Compare 1 interrupt flag * @arg TIM_FLAG_CC2: Capture/Compare 2 interrupt flag * @arg TIM_FLAG_CC3: Capture/Compare 3 interrupt flag * @arg TIM_FLAG_CC4: Capture/Compare 4 interrupt flag * @arg TIM_FLAG_COM: Commutation interrupt flag * @arg TIM_FLAG_TRIGGER: Trigger interrupt flag * @arg TIM_FLAG_BREAK: Break interrupt flag * @arg TIM_FLAG_CC1OF: Capture/Compare 1 overcapture flag * @arg TIM_FLAG_CC2OF: Capture/Compare 2 overcapture flag * @arg TIM_FLAG_CC3OF: Capture/Compare 3 overcapture flag * @arg TIM_FLAG_CC4OF: Capture/Compare 4 overcapture flag * @retval The new state of __FLAG__ (TRUE or FALSE). */ #define __HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->SR &(__FLAG__)) == (__FLAG__))
TIM Channels应用实例1:输出比较(PWM)
STM32可以由定时器产生PWM波,相较于TIM的一般应用,增加了对于通道及输出口的配置:
初始化:MX_TIM_Init()
1、配置结构体TIM_HandleTypeDef定义的htim成员
2、配置结构体TIM_OC_InitTypeDef定义的sConfigOC成员
3、配置结构体TIM_MasterConfigTypeDef与TIM_ClockConfigTypeDef定义的成员,这里按默认
4、配置输出GPIO复用参数,MX将其封装在一个MspPostInit里在MX_TIM_Init()调用
其中第二条是与一般应用的不同之处,用于初始化Output Compare的各项参数
输出允许:HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_x)
允许输出PWM,将在配置的GPIO口上输出PWM波,这一功能的配置相对简单,也可以看出,ST官方给出定时器的比较与捕获通道,具有很多用处,且避免了用户需要自己写逻辑来实现这些功能的麻烦
TIM Channels应用实例2:输入捕获
输入捕获,实际上就是在定时器的基础上加了对于特定引脚的捕获通道,使得循环计时的定时器能关联上外部引脚电平:
初始化:MX_TIM_Init()
1、配置结构体TIM_HandleTypeDef定义的htim成员
2、配置结构体TIM_IC_InitTypeDef定义的sConfigIC成员
3、配置结构体TIM_MasterConfigTypeDef与TIM_ClockConfigTypeDef定义的成员,这里按默认
4、配置输入GPIO复用参数,此处写在MspInit里
中断允许:HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE);
此处对CR进行了两次操作,后者将DIER置位为TIM_TI_UPDATE,在前者将DIER置位为TIM_IT_CC1,同时允许了CR中的计数器使能
中断服务:
基本的逻辑就是在检测到高电平时定时器清零,接着开始循环计时,同时更改触发电平为低电平触发,每溢出一次手动计数,这是在下次触发时,高电平事件就是ARR乘以溢出次数加上此次的CCRx
uint8_t TIM5CH1_CAPTURE_STA = 0; uint32_t TIM5CH1_CAPTURE_VAL = 0; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == (&htim5)) { if((TIM5CH1_CAPTURE_STA &0x80) == 0) { if(TIM5CH1_CAPTURE_STA &0x40) { if((TIM5CH1_CAPTURE_STA &0x30) == 0x3f) { TIM5CH1_CAPTURE_STA |= 0x80; TIM5CH1_CAPTURE_VAL = 0xffffffff; } else { TIM5CH1_CAPTURE_STA ++; } } } } } void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(htim == (&htim5)) { if((TIM5CH1_CAPTURE_STA &0x80) == 0) { if(TIM5CH1_CAPTURE_STA &0x40) { TIM5CH1_CAPTURE_STA |= 0x80; TIM5CH1_CAPTURE_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1); TIM_RESET_CAPTUREPOLARITY (&htim5, TIM_CHANNEL_1); TIM_SET_CAPTUREPOLARITY (&htim5, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING); } else { TIM5CH1_CAPTURE_STA = 0; TIM5CH1_CAPTURE_VAL = 0; TIM5CH1_CAPTURE_STA |= 0x40; __HAL_TIM_DISABLE (&htim5); //关闭定时器5 __HAL_TIM_SET_COUNTER (&htim5,0); TIM_RESET_CAPTUREPOLARITY (&htim5,TIM_CHANNEL_1); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY (&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//定时器5通道1设置为下降沿捕获 __HAL_TIM_ENABLE (&htim5);//使能定时器5 } } } }
if(TIM5CH1_CAPTURE_STA&0X80) //成功捕获到了一次高电平 { temp=TIM5CH1_CAPTURE_STA&0X3F; temp*=0XFFFFFFFF; //溢出时间总和 temp+=TIM5CH1_CAPTURE_VAL; //得到总的高电平时间 printf("HIGH:%lld us\r\n",temp);//打印总的高点平时间 TIM5CH1_CAPTURE_STA=0; //开启下一次捕获 }
此处引用正点原子的服务函数,自行理解