本次博客更新了HAL库的版本。以后的博客都会采用此HAL库版本。
HAL库版本:
本篇博客主要介绍基本定时器中的源码解析,会涉及以下三个部分:
需要注意的是:本文介绍的源代码使用的并非基本定时器TIM6或者TIM7,而是通用定时器TIM3。但是,他们程序上是兼容的,只需将TIM3当做基本定时器即可。在最后的自我分享代码中,会严格的使用TIM6.
由于基本定时器不会与外界有直接的硬件连接,本文就不介绍硬件情况。
/*** @brief TIM Time Base Handle Structure definition*/
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
typedef struct __TIM_HandleTypeDef
#else
typedef struct
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
{TIM_TypeDef *Instance; /*!< Register base address */TIM_Base_InitTypeDef Init; /*!< TIM Time Base required parameters */HAL_TIM_ActiveChannel Channel; /*!< Active channel */DMA_HandleTypeDef *hdma[7]; /*!< DMA Handlers arrayThis array is accessed by a @ref DMA_Handle_index */HAL_LockTypeDef Lock; /*!< Locking object */__IO HAL_TIM_StateTypeDef State; /*!< TIM operation state */#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)void (* Base_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Base Msp Init Callback */void (* Base_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Base Msp DeInit Callback */void (* IC_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM IC Msp Init Callback */void (* IC_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM IC Msp DeInit Callback */void (* OC_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM OC Msp Init Callback */void (* OC_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM OC Msp DeInit Callback */void (* PWM_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM PWM Msp Init Callback */void (* PWM_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM PWM Msp DeInit Callback */void (* OnePulse_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM One Pulse Msp Init Callback */void (* OnePulse_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM One Pulse Msp DeInit Callback */void (* Encoder_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Encoder Msp Init Callback */void (* Encoder_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Encoder Msp DeInit Callback */void (* HallSensor_MspInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Hall Sensor Msp Init Callback */void (* HallSensor_MspDeInitCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Hall Sensor Msp DeInit Callback */void (* PeriodElapsedCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Period Elapsed Callback */void (* PeriodElapsedHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Period Elapsed half complete Callback */void (* TriggerCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Trigger Callback */void (* TriggerHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Trigger half complete Callback */void (* IC_CaptureCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Input Capture Callback */void (* IC_CaptureHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Input Capture half complete Callback */void (* OC_DelayElapsedCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Output Compare Delay Elapsed Callback */void (* PWM_PulseFinishedCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM PWM Pulse Finished Callback */void (* PWM_PulseFinishedHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM PWM Pulse Finished half complete Callback */void (* ErrorCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Error Callback */void (* CommutationCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Commutation Callback */void (* CommutationHalfCpltCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Commutation half complete Callback */void (* BreakCallback)(struct __TIM_HandleTypeDef *htim); /*!< TIM Break Callback */
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
} TIM_HandleTypeDef;
相对于低版本的HAL库,此处最大的改动就是增加了宏USE_HAL_TIM_REGISTER_CALLBACKS
。若此宏有效,则表明每个句柄都有独立的中断回调函数,定义在结构体中。默认情况下,该宏为无效,所以为了方便,舍去无意义代码,变为:
/*** @brief TIM Time Base Handle Structure definition*/
typedef struct
{TIM_TypeDef *Instance; /*!< Register base address */TIM_Base_InitTypeDef Init; /*!< TIM Time Base required parameters */HAL_TIM_ActiveChannel Channel; /*!< Active channel */DMA_HandleTypeDef *hdma[7]; /*!< DMA Handlers arrayThis array is accessed by a @ref DMA_Handle_index */HAL_LockTypeDef Lock; /*!< Locking object */__IO HAL_TIM_StateTypeDef State; /*!< TIM operation state */
} TIM_HandleTypeDef;
此用于选择时钟源,可以选择的参数如下:
#define TIM1 ((TIM_TypeDef *) TIM1_BASE)
#define TIM2 ((TIM_TypeDef *) TIM2_BASE)
#define TIM3 ((TIM_TypeDef *) TIM3_BASE)
#define TIM4 ((TIM_TypeDef *) TIM4_BASE)
#define TIM5 ((TIM_TypeDef *) TIM5_BASE)
#define TIM6 ((TIM_TypeDef *) TIM6_BASE)
#define TIM7 ((TIM_TypeDef *) TIM7_BASE)
#define TIM8 ((TIM_TypeDef *) TIM8_BASE)
#define TIM9 ((TIM_TypeDef *) TIM9_BASE)
#define TIM10 ((TIM_TypeDef *) TIM10_BASE)
#define TIM11 ((TIM_TypeDef *) TIM11_BASE)
#define TIM12 ((TIM_TypeDef *) TIM12_BASE)
#define TIM13 ((TIM_TypeDef *) TIM13_BASE)
#define TIM14 ((TIM_TypeDef *) TIM14_BASE)
该结构体将在TIM_Base_InitTypeDef详细介绍,主要与初始化参数相关。
用于选择通道,具体的参数定义如下:
/*** @brief HAL Active channel structures definition*/
typedef enum
{HAL_TIM_ACTIVE_CHANNEL_1 = 0x01U, /*!< The active channel is 1 */HAL_TIM_ACTIVE_CHANNEL_2 = 0x02U, /*!< The active channel is 2 */HAL_TIM_ACTIVE_CHANNEL_3 = 0x04U, /*!< The active channel is 3 */HAL_TIM_ACTIVE_CHANNEL_4 = 0x08U, /*!< The active channel is 4 */HAL_TIM_ACTIVE_CHANNEL_CLEARED = 0x00U /*!< All active channels cleared */
} HAL_TIM_ActiveChannel;
DMA相关的句柄,此处不再详细讲解。
HAL库的锁,具体定义如下:
/** * @brief HAL Lock structures definition */
typedef enum
{HAL_UNLOCKED = 0x00U,HAL_LOCKED = 0x01U
} HAL_LockTypeDef;
时钟的状态,参数可以如下选择:
/*** @brief HAL State structures definition*/
typedef enum
{HAL_TIM_STATE_RESET = 0x00U, /*!< Peripheral not yet initialized or disabled */HAL_TIM_STATE_READY = 0x01U, /*!< Peripheral Initialized and ready for use */HAL_TIM_STATE_BUSY = 0x02U, /*!< An internal process is ongoing */HAL_TIM_STATE_TIMEOUT = 0x03U, /*!< Timeout state */HAL_TIM_STATE_ERROR = 0x04U /*!< Reception process is ongoing */
} HAL_TIM_StateTypeDef;
/*** @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 activeAuto-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 downcounterreaches zero, an update event is generated and counting restartsfrom 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 modeGP 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;
预分频的取值范围:0-65535。经过分频后的时钟
o u t p u t = i n p u t p r e s c a l e r + 1 output=frac{input}{prescaler+1} output=prescaler+1input
即分配系统为寄存器值+1.
计数模式可以从以下参数中选取:
/** @defgroup TIM_Counter_Mode TIM Counter Mode* @{*/
#define TIM_COUNTERMODE_UP 0x00000000U /*!< Counter used as up-counter */
#define TIM_COUNTERMODE_DOWN TIM_CR1_DIR /*!< Counter used as down-counter */
#define TIM_COUNTERMODE_CENTERALIGNED1 TIM_CR1_CMS_0 /*!< Center-aligned mode 1 */
#define TIM_COUNTERMODE_CENTERALIGNED2 TIM_CR1_CMS_1 /*!< Center-aligned mode 2 */
#define TIM_COUNTERMODE_CENTERALIGNED3 TIM_CR1_CMS /*!< Center-aligned mode 3 */
/*** @}*/
周期数的取值范围为0-65535。其作用形式等同于预分频,周期数为寄存器值家1.
参数选取为:
/** @defgroup TIM_ClockDivision TIM Clock Division* @{*/
#define TIM_CLOCKDIVISION_DIV1 0x00000000U /*!< Clock division: tDTS=tCK_INT */
#define TIM_CLOCKDIVISION_DIV2 TIM_CR1_CKD_0 /*!< Clock division: tDTS=2*tCK_INT */
#define TIM_CLOCKDIVISION_DIV4 TIM_CR1_CKD_1 /*!< Clock division: tDTS=4*tCK_INT */
/*** @}*/
该值只有高级时钟才会使用。
用于控制自动重载寄存器的影子寄存器是否使能。取值范围为:
/** @defgroup TIM_AutoReloadPreload TIM Auto-Reload Preload* @{*/
#define TIM_AUTORELOAD_PRELOAD_DISABLE 0x00000000U /*!< TIMx_ARR register is not buffered */
#define TIM_AUTORELOAD_PRELOAD_ENABLE TIM_CR1_ARPE /*!< TIMx_ARR register is buffered *//*** @}*/
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "timer.h"int main(void)
{HAL_Init(); //初始化HAL库 Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhzdelay_init(180); //初始化延时函数LED_Init(); //初始化LED TIM3_Init(5000-1,9000-1); //定时器3初始化,定时器时钟为90M,分频系数为9000-1,//所以定时器3的频率为90M/9000=10K,自动重装载为5000-1,那么定时器周期就是500mswhile(1){LED0=!LED0; //LED0翻转delay_ms(200); //延时200ms}
}
在主函数中,主要调用了TIM3_Init
来配置定时器TIM3。最红通过延时程序,在while循环中实现LED0的循环点亮。而与定时器相关的LED1则是通过定时器触发中断的方式来实现改变状态的。
/** * @brief 计时器TIM3配置* @note 无* @param {u16} arr 自动装载值* @param {u16} psc 预分频数* @retval 无*/
void TIM3_Init(u16 arr, u16 psc)
{/* 1.使能时钟 */__HAL_RCC_TIM3_CLK_ENABLE(); //使能TIM3时钟/* 2.初始化配置 */TIM3_Handler.Instance = TIM3; //通用定时器3TIM3_Handler.Init.Prescaler = psc; //分频系数TIM3_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数器TIM3_Handler.Init.Period = arr; //自动装载值TIM3_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; //时钟分频因子HAL_TIM_Base_Init(&TIM3_Handler);/* 3.启动时钟 */HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE
}
该段程序由正点原子实现的。主要分成三个部分:
其中,调用了库函数HAL_TIM_Base_Init
和HAL_TIM_Base_Start_IT
。下面将重点介绍着两个函数。
/*** @brief Initializes the TIM Time base Unit according to the specified* parameters in the TIM_HandleTypeDef and initialize the associated handle.* @note Switching from Center Aligned counter mode to Edge counter mode (or reverse)* requires a timer reset to avoid unexpected direction* due to DIR bit readonly in center aligned mode.* Ex: call @ref HAL_TIM_Base_DeInit() before HAL_TIM_Base_Init()* @param htim TIM Base handle* @retval HAL status*/
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
{/*********************1.参数检查********************************//* Check the TIM handle allocation */if (htim == NULL){return HAL_ERROR;}/* Check the parameters */assert_param(IS_TIM_INSTANCE(htim->Instance));assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload));/*********************2.配置底层信息********************************/if (htim->State == HAL_TIM_STATE_RESET){/* Allocate lock resource and initialize it */htim->Lock = HAL_UNLOCKED;#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)/* Reset interrupt callbacks to legacy weak callbacks */TIM_ResetCallback(htim);if (htim->Base_MspInitCallback == NULL){htim->Base_MspInitCallback = HAL_TIM_Base_MspInit;}/* Init the low level hardware : GPIO, CLOCK, NVIC */htim->Base_MspInitCallback(htim);
#else/* Init the low level hardware : GPIO, CLOCK, NVIC */HAL_TIM_Base_MspInit(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Set the TIM state */htim->State = HAL_TIM_STATE_BUSY;/*********************3.配置定时器基本信息********************************//* Set the Time Base configuration */TIM_Base_SetConfig(htim->Instance, &htim->Init);/* Initialize the TIM state*/htim->State = HAL_TIM_STATE_READY;return HAL_OK;
}
该函数分成以下几个步骤:
状态变化:
其中调用了两个函数:
/** * @brief 底层驱动* @note 无* @param {TIM_HandleTypeDef} *htim 计时器句柄* @retval 无*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM3){HAL_NVIC_SetPriority(TIM3_IRQn, 1, 3); //设置中断优先级,抢占优先级1,子优先级3HAL_NVIC_EnableIRQ(TIM3_IRQn); //开启ITM3中断}
}
该函数由自己实现,主要参考了正点原子的代码。实现的功能很简单,就是配置中断的优先级,使能中断。
/*** @brief Time Base configuration* @param TIMx TIM peripheral* @param Structure TIM Base configuration structure* @retval None*/
void TIM_Base_SetConfig(TIM_TypeDef *TIMx, TIM_Base_InitTypeDef *Structure)
{/*********************1.设置CR1寄存器********************************/uint32_t tmpcr1;tmpcr1 = TIMx->CR1;/* Set TIM Time Base Unit parameters ---------------------------------------*/if (IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx)) //1,2,3,4,5,8:可以选择计数器的方向{/* Select the Counter Mode */tmpcr1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);tmpcr1 |= Structure->CounterMode;}if (IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx)) //除了6,7:可以设置时钟分频{/* Set the clock division */tmpcr1 &= ~TIM_CR1_CKD;tmpcr1 |= (uint32_t)Structure->ClockDivision;}/* Set the auto-reload preload */MODIFY_REG(tmpcr1, TIM_CR1_ARPE, Structure->AutoReloadPreload); //设置自动加载寄存器的影子寄存器TIMx->CR1 = tmpcr1;/*********************2.设置ARR寄存器********************************//* Set the Autoreload value */TIMx->ARR = (uint32_t)Structure->Period; //设置时钟的周期/*********************3.设置PSC寄存器********************************//* Set the Prescaler value */TIMx->PSC = Structure->Prescaler; //设置时钟的预分频/*********************4.设置RCR 寄存器********************************/if (IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx)) //1,8:支持重复计数器,高级时钟{/* Set the Repetition Counter value */TIMx->RCR = Structure->RepetitionCounter;}/*********************5.设置EGR 寄存器********************************//* Generate an update event to reload the Prescalerand the repetition counter (only for advanced timer) value immediately */TIMx->EGR = TIM_EGR_UG;
}
在该函数中,总共设置5组寄存器。但需要注意的是,对于基本定时器而言,其实只有1,2,3,5步骤是有意义的。尤其需要注意的有两点:
/*** @brief Starts the TIM Base generation in interrupt mode.* @param htim TIM Base handle* @retval HAL status*/
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{uint32_t tmpsmcr;/*********************1.检测参数********************************//* Check the parameters */assert_param(IS_TIM_INSTANCE(htim->Instance));/*********************2.使能向上计数中断********************************//* Enable the TIM Update interrupt */__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);/*********************3.使能外设********************************//* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;/*********************4.使能计时器********************************/if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr)){__HAL_TIM_ENABLE(htim);}/* Return function status */return HAL_OK;
}
该函数大致分成4各部分:
其中,与基本定时器相关的为2与4步。他们的宏定义如下所示:
/** @brief Enable the specified TIM interrupt.* @param __HANDLE__ specifies the TIM Handle.* @param __INTERRUPT__ specifies the TIM interrupt source to enable.* This parameter can be one of the following values:* @arg TIM_IT_UPDATE: Update interrupt* @arg TIM_IT_CC1: Capture/Compare 1 interrupt* @arg TIM_IT_CC2: Capture/Compare 2 interrupt* @arg TIM_IT_CC3: Capture/Compare 3 interrupt* @arg TIM_IT_CC4: Capture/Compare 4 interrupt* @arg TIM_IT_COM: Commutation interrupt* @arg TIM_IT_TRIGGER: Trigger interrupt* @arg TIM_IT_BREAK: Break interrupt* @retval None*/
#define __HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DIER |= (__INTERRUPT__))
/*** @brief Enable the TIM peripheral.* @param __HANDLE__ TIM handle* @retval None*/
#define __HAL_TIM_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1|=(TIM_CR1_CEN))
都是通过直接设置寄存器实现。
/** * @brief TIM3中断响应函数* @note 自动被调用* @param {*}无* @retval 无*/
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&TIM3_Handler);
}
在中断响应中,直接调用HAL_TIM_IRQHandler()
来判断中断类型。
/*** @brief This function handles TIM interrupts requests.* @param htim TIM handle* @retval None*/
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{/* Capture compare 1 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) != RESET){{__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;/* Input capture event */if ((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}}/* Capture compare 2 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;/* Input capture event */if ((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* Capture compare 3 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;/* Input capture event */if ((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* Capture compare 4 event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;/* Input capture event */if ((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00U){
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->IC_CaptureCallback(htim);
#elseHAL_TIM_IC_CaptureCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}/* Output compare event */else{
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->OC_DelayElapsedCallback(htim);htim->PWM_PulseFinishedCallback(htim);
#elseHAL_TIM_OC_DelayElapsedCallback(htim);HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;}}/* TIM Update event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->PeriodElapsedCallback(htim);
#elseHAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM Break input event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->BreakCallback(htim);
#elseHAL_TIMEx_BreakCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM Trigger detection event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->TriggerCallback(htim);
#elseHAL_TIM_TriggerCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}/* TIM commutation event */if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->CommutationCallback(htim);
#elseHAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}
}
首先,通过中断标志位来判断响应的是哪一个中断。可以抽取该函数的骨架来看:
其中每个分支的实现方式大致相同,本文选基本定时器功能来讲解:
if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET){if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET){__HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)htim->PeriodElapsedCallback(htim);
#elseHAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}}
该函数主要实现功能:
以上步骤也是经典的HAL库对于中断的处理方法。
其中,判断中断位和判断中断源的宏定义为:
/** @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__))/*** @brief Check whether the specified TIM interrupt source is enabled or not.* @param __HANDLE__ TIM handle* @param __INTERRUPT__ specifies the TIM interrupt source to check.* This parameter can be one of the following values:* @arg TIM_IT_UPDATE: Update interrupt* @arg TIM_IT_CC1: Capture/Compare 1 interrupt* @arg TIM_IT_CC2: Capture/Compare 2 interrupt* @arg TIM_IT_CC3: Capture/Compare 3 interrupt* @arg TIM_IT_CC4: Capture/Compare 4 interrupt* @arg TIM_IT_COM: Commutation interrupt* @arg TIM_IT_TRIGGER: Trigger interrupt* @arg TIM_IT_BREAK: Break interrupt* @retval The state of TIM_IT (SET or RESET).*/
#define __HAL_TIM_GET_IT_SOURCE(__HANDLE__, __INTERRUPT__) ((((__HANDLE__)->Instance->DIER & (__INTERRUPT__)) == (__INTERRUPT__)) ? SET : RESET)
都是直接查询寄存器获得,此处不再详细分析。
中断回调函数由用户自己实现,正点原子的代码为:
/** * @brief 中断回调函数* @note 在HAL_TIM_IRQHandler函数中调用* @param {TIM_HandleTypeDef} *htim 中断句柄* @retval */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == (&TIM3_Handler)){LED1 = !LED1; //LED1反转}
}
该函数很简单,通过判断句柄来确定中断源,从而实现自己的功能。
参考博客<STM32CubeMX第四篇之基本定时器>
本文发布于:2024-02-04 10:20:58,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170704978354711.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |