当前位置: 首页 > news >正文

STM32F429第十九篇之基本定时器实验详解

文章目录

  • 前言
  • 结构体
    • TIM_HandleTypeDef
      • Instance(句柄对应时钟)
      • Init(初始化结构体)
      • Channel(通道)
      • hdma(DMA句柄)
      • Lock(锁)
      • State(状态)
    • TIM_Base_InitTypeDef
      • Prescaler(预分频)
      • CounterMode(计数模式)
      • Period(周期数)
      • ClockDivision(时钟分频)
      • RepetitionCounter(重复计数)
      • AutoReloadPreload(自动重载影子寄存器使能)
  • 源代码
    • 主函数
    • 配置
      • TIM3_Init
      • HAL_TIM_Base_Init
      • HAL_TIM_Base_MspInit
      • TIM_Base_SetConfig
      • HAL_TIM_Base_Start_IT
    • 中断响应
      • TIM3_IRQHandler
      • HAL_TIM_IRQHandler
      • HAL_TIM_PeriodElapsedCallback
  • 自我实现

前言

本次博客更新了HAL库的版本。以后的博客都会采用此HAL库版本。

HAL库版本:

  • STM32Cube_FW_F4_V1.25.0

本篇博客主要介绍基本定时器中的源码解析,会涉及以下三个部分:

  • 以整点原子定时器中断实验的程序为蓝本的程序解析
  • 重点的结构体介绍
  • 个人根据解析结果,最后分享自己的写的源代码

需要注意的是:本文介绍的源代码使用的并非基本定时器TIM6或者TIM7,而是通用定时器TIM3。但是,他们程序上是兼容的,只需将TIM3当做基本定时器即可。在最后的自我分享代码中,会严格的使用TIM6.

由于基本定时器不会与外界有直接的硬件连接,本文就不介绍硬件情况。

结构体

TIM_HandleTypeDef

/*** @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;

Instance(句柄对应时钟)

此用于选择时钟源,可以选择的参数如下:

#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)

Init(初始化结构体)

该结构体将在TIM_Base_InitTypeDef详细介绍,主要与初始化参数相关。

Channel(通道)

用于选择通道,具体的参数定义如下:

/*** @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;

hdma(DMA句柄)

DMA相关的句柄,此处不再详细讲解。

Lock(锁)

HAL库的锁,具体定义如下:

/** * @brief  HAL Lock structures definition  */
typedef enum 
{HAL_UNLOCKED = 0x00U,HAL_LOCKED   = 0x01U  
} HAL_LockTypeDef;

State(状态)

时钟的状态,参数可以如下选择:

/*** @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;

TIM_Base_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 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;

Prescaler(预分频)

预分频的取值范围: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.

CounterMode(计数模式)

计数模式可以从以下参数中选取:

/** @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        */
/*** @}*/

Period(周期数)

周期数的取值范围为0-65535。其作用形式等同于预分频,周期数为寄存器值家1.

ClockDivision(时钟分频)

参数选取为:

/** @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 */
/*** @}*/

在这里插入图片描述

RepetitionCounter(重复计数)

该值只有高级时钟才会使用。

AutoReloadPreload(自动重载影子寄存器使能)

用于控制自动重载寄存器的影子寄存器是否使能。取值范围为:

/** @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则是通过定时器触发中断的方式来实现改变状态的。

配置

TIM3_Init

/** * @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
}

该段程序由正点原子实现的。主要分成三个部分:

  1. 使能时钟
  2. 初始化定时器
  3. 启动时钟

其中,调用了库函数HAL_TIM_Base_InitHAL_TIM_Base_Start_IT。下面将重点介绍着两个函数。

HAL_TIM_Base_Init

/*** @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;
}

该函数分成以下几个步骤:

  1. 检查参数类型
  2. 底层初始化
  3. 计时器初始化

状态变化:

  1. HAL_TIM_STATE_RESET——初始状态,未初始化过
  2. HAL_TIM_STATE_BUSY——底层初始化之后,要进行计时器的配置
  3. HAL_TIM_STATE_READY——配置完成,计时器可以使用

其中调用了两个函数:

  • HAL_TIM_Base_MspInit——底层配置
  • TIM_Base_SetConfig——定时器配置

HAL_TIM_Base_MspInit

/** * @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中断}
}

该函数由自己实现,主要参考了正点原子的代码。实现的功能很简单,就是配置中断的优先级,使能中断。

TIM_Base_SetConfig

/*** @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步骤是有意义的。尤其需要注意的有两点:

  1. 在第1步中,唯一有意义的就是设置自动加载寄存器的影子寄存器。
  2. 在第5步中,通过设置UG,触发更新事件,将影子寄存器的值生效,也就是将刚刚写入的预分频寄存器的数据生效。

HAL_TIM_Base_Start_IT

/*** @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各部分:

  1. 检测参数
  2. 使能计数器中断
  3. 使能外设
  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))

都是通过直接设置寄存器实现。

中断响应

TIM3_IRQHandler

/** * @brief TIM3中断响应函数* @note   自动被调用* @param {*}无* @retval 无*/
void TIM3_IRQHandler(void)
{HAL_TIM_IRQHandler(&TIM3_Handler);
}

在中断响应中,直接调用HAL_TIM_IRQHandler()来判断中断类型。

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 */}}

该函数主要实现功能:

  1. 判断该中断标志位是否置1以及该中断是否使能,若两者皆是,则响应该中断。
  2. 清除中断标志位。
  3. 调用中断回调函数。

以上步骤也是经典的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)

都是直接查询寄存器获得,此处不再详细分析。

HAL_TIM_PeriodElapsedCallback

中断回调函数由用户自己实现,正点原子的代码为:

/** * @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第四篇之基本定时器>


http://www.taodudu.cc/news/show-8381739.html

相关文章:

  • GD32 RT-Thread PWM驱动函数
  • Linux指纹识别程序,安装和配置Fingerprint GUI以在Linux上启用指纹扫描程序支持
  • linux 深度扫描软件,Deepin 15.5 Linux操作系统首次采用HiDPI和Flatpak支持,指纹扫描...
  • Suprema RFID指纹扫描仪增加安卓设备支持
  • android 指纹存储密码,Android-使用指纹扫描仪和密码来加密和解密...
  • 35.CSS指纹扫描器动画效果
  • web指纹扫描器_欺骗手机的指纹扫描器很容易。 这是我们应解决的方法。
  • 小程序手机号注册php,微信小程序授权获取用户手机号码
  • 微信小程序怎么注册?
  • 09C++文件读取
  • 点成案例| BE-Gradient 微流控芯片用于胶质母细胞瘤的研究
  • 数字微流控生物芯片模拟界面
  • 微流控芯片建模分析技术与应用
  • 什么是微流控芯片?它是如何发展起来的?
  • 详述纸基微流控芯片的研究进展
  • 优可测推动微流控技术革新,精准助力生物医学等行业的发展
  • 简化SQL式计算之逆分组
  • PyConChina 2012 - 第二届中国Python开发者大会 上海.北京.西安.杭州.合肥.武汉.珠海 | 抢座网...
  • 高新园区云计算机大厦,合肥超猛!九区900大项目曝光,中央CBD、超算中心来了!滨湖、高新、新站彻底爆发!...
  • 【线下赛游记】2023 ICPC合肥区域赛 游记
  • 近2000万!鸿雁中标杭州地铁 9 号线一期工程公共区 LED 灯具项目
  • 用Python计算合肥地铁乘车最优乘车路线:暴力方式
  • Element UI中全部的图标以及组件
  • 小白必看的那些UI图标设计规范分享!
  • 区块链,会越来越无聊!
  • 小程序如何用data的数据控制页面展示_小程序实战之登录的原理和实现(内含福利)...
  • 边缘计算与物联网精华问答 | 边缘计算和物联网有什么关系?
  • 营养餐搭配小程序开发价值
  • 「安搭Share你问我答」你老了,如何养老?
  • 神奇瘦身食谱 调整你多余脂肪 - 生活至上,美容至尚!