当前位置:   article > 正文

STM32定时器的基本知识_tim_handletypedef

tim_handletypedef

文章目录

    • 定时器
    • stm32的定时器
    • 基础定时器
    • 定时器输出频率计算
    • 使用定时器中断点亮LED并计数
    • 编写代码
    • 中断优先级
    • 配置中断优先级
    • HAL时基
    • 更改HAL时基并使用定时器中断
    • 代码编写
    • 参考资料

定时器

定时器是一种可以计数内部/外部时钟的外设

经过处理后的内部/外部时钟每产生一个方波,定时器内部的寄存器+1

当定时器计数到程序设定值后清零,同时产生中断

定时器可以将时钟分频,并产生中断或驱动其他外设

stm32的定时器

  • 基础定时器:TIM6,TIM7
  • 通用定时器:
    • 32位定时器:TIM2,TIM5
    • 16位4通道定时器:TIM3,TIM4
    • 其他通用定时器:TIM9~TIM17
  • 高级定时器:TIM1,TIM8,TIM20
  • 系统定时器:SYSTICK(在芯片内核)
  • 低功耗定时器:LPTIM
  • 高精度定时器:HRTIM(基础时钟可达5.44GHz)

功能:基础定时器<通用定时器<高级定时器

基础定时器

  • 定时器输入时钟一般与芯片主频相同
    • STM32系列需要注意仅高级定时器时钟与主频相同,其他定时器时钟是主频的一半
  • 输入时钟经过预分频(PSC)后被定时器计数(CNT)
  • 当CNT计数值达到ARR里的设定值后,计数清零并产生中断

在这里插入图片描述

定时器输出频率计算

在这里插入图片描述

例如:

  • 输入时钟84MHz,PSC寄存器为0,ARR寄存器为83,则输出为1MHz
  • 输入时钟84MHz,PSC寄存器为83,ARR寄存器为999,则输出1KHz

使用定时器中断点亮LED并计数

先打开Cube进行外设以及时钟树的配置

把红灯的引脚PH12打开

然后可以在旁边外设列表的Timers设置定时器

先激活TIM6,根据公式设置TIM6的PSC(Prescaler)和ARR(Counter Period)

PSC设为84-1(即基础定时器只有主频168MHz一半(即84MHz)的输入)

ARR设为1000-1

最终输出1kHz

然后在TIM6的NVIC Settings中将TIM6的中断启动

然后GENERATE CODE生成代码

编写代码

先在主函数循环里面加入HAL_Delay,防止程序卡死

/* USER CODE BEGIN 3 */
		HAL_Delay(100);
  /* USER CODE END 3 */
  • 1
  • 2
  • 3

主函数的代码中

  HAL_Init();//启动HAL库

  SystemClock_Config();//启动高速时钟
					   //程序执行完这个函数后芯片工作频率便可达到168MHz
					   //在此之前只有16MHz

  MX_GPIO_Init();
  MX_TIM6_Init();//初始化Cube初始化外设

  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */ //之间进行初始化代码的编写
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后我们需要先启动定时器在USER CODE BEGIN 2/END 2之间编写,即:

  /* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6);//启动TIM6,并使能它的中断
  /* USER CODE END 2 */
  • 1
  • 2
  • 3

其中htim6的类型是TIM_HandleTypeDef

TIM_HandleTypeDef是结构体,它的定义如下

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 array
                                                             This array is accessed by a @ref DMA_Handle_index */
  HAL_LockTypeDef                    Lock;              /*!< Locking object                                    */
  __IO HAL_TIM_StateTypeDef          State;             /*!< TIM operation state                               */
  __IO HAL_TIM_ChannelStateTypeDef   ChannelState[4];   /*!< TIM channel operation state                       */
  __IO HAL_TIM_ChannelStateTypeDef   ChannelNState[4];  /*!< TIM complementary channel operation state         */
  __IO HAL_TIM_DMABurstStateTypeDef  DMABurstState;     /*!< DMA burst 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

可以把htim6简单理解为tim6抽象化的外设

由于该结构体参数都是结构体指针

因此我们得取输入参数的地址

然后在USER CODE BEGIN 4/END 4之间写回调函数

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint8_t counter = 0;//额外数数的变量,在函数中只初始化一次
	counter++;//进行计数
	if(counter==100)//即每100ms将counter清零
	{
		counter =0;
		HAL_GPIO_TogglePin(GPIOH,GPIO_PIN_12);//翻转PH12的电平
	}
};
/* USER CODE END 4 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
//函数作用就是每100ms闪灯一次
//HAL_TIM_PeriodElapsedCallback是定时器的回调函数(必须与hal库中的一致)
//该回调函数的参数一定是指针
  • 1
  • 2
  • 3

中断优先级

  • 中断具有优先级,用于处理中断服务程序运行过程中产生的中断
    • 高优先级的中断能打断低优先级的中断服务程序
    • 低优先级的中断不能打断高优先级的中断,只能等待高优先级中断处理完毕之后再进行处理
  • 中断优先级分为3级:
    • 抢占优先级(主优先级)
    • 次要优先级(某些芯片可能不支持)
    • 中断向量顺序
  • 优先级数字越小,优先级越高

配置中断优先级

默认情况下,Cube外设配置栏里的NVIC按照中断向量的先后顺序排序中断

靠上的中断具有更小的中断向量,即更高的中断向量优先级

抢占优先级和次要优先级可以自行设置

Priority Group可以设置两种优先级位数,默认没有次要优先级,4位抢占优先级

位数越大,能设置的级别越多

两种优先级共享4位

HAL时基

HAL内部使用kHz的时钟,很多库函数都会用到这个时钟

该时钟可由系统定时器SYSTICK或者其他定时器产生

一般都不使用系统定时器SYSTICK产生HAL时基

(SYSTICK是内核定时器,一般用于操作系统)

HAL时基由定时器中断产生

更改HAL时基并使用定时器中断

回到Cube,在sys中把Timebase Source从SYSTICK改为TIM7(改为以TIM7为时基)

然后在NVIC中配置中断优先级,无论什么时候HAL时基都必须被配置为最低优先级

设置好后生成代码

代码编写

在main.c中自动生成一个回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM7) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
htim->Instance == TIM7//代表传入参数的寄存器(Instance)是TIM7
  • 1
//如果传入参数的寄存器(Instance)是TIM7,那么会执行HAL_IncTick()函数
  • 1

但是由于我们在上面USER CODE BEGIN 4/ END 4之间重新定义了一个同名的回调函数

因此程序在这里会报错

所以我们需要把上面定义的函数剪切到系统生成的回调函数中的

/* USER CODE BEGIN Callback 1 */

/* USER CODE END Callback 1 */之间

并且判断一下是否为TIM6产生的中断

修改后代码如下

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM7) //判断是否为TIM7产生的中断
  {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */
  if (htim->Instance == TIM6) //判断是否为TIM6产生的中断
  {
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  	{
	  static uint8_t counter = 0;
	    counter++;
	  if(counter==100)
      {
      	counter =0;
	    HAL_GPIO_TogglePin(GPIOH,GPIO_PIN_12);
      }
  	 };
   }

  /* USER CODE END Callback 1 */
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

编译烧录后现象跟之前一样。

参考资料

CH2.1 TIM 第1讲 基础定时器【南工骁鹰嵌入式软件培训】

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/285300
推荐阅读
相关标签
  

闽ICP备14008679号