STM32定时器的基本知识

文章目录

    • 定时器
    • 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 */

主函数的代码中

  HAL_Init();//启动HAL库

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

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

  /* USER CODE BEGIN 2 */
  /* USER CODE END 2 */ //之间进行初始化代码的编写

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

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

其中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;

可以把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 */
//函数作用就是每100ms闪灯一次
//HAL_TIM_PeriodElapsedCallback是定时器的回调函数(必须与hal库中的一致)
//该回调函数的参数一定是指针

中断优先级

  • 中断具有优先级,用于处理中断服务程序运行过程中产生的中断
    • 高优先级的中断能打断低优先级的中断服务程序
    • 低优先级的中断不能打断高优先级的中断,只能等待高优先级中断处理完毕之后再进行处理
  • 中断优先级分为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 */
}
htim->Instance == TIM7//代表传入参数的寄存器(Instance)是TIM7
//如果传入参数的寄存器(Instance)是TIM7,那么会执行HAL_IncTick()函数

但是由于我们在上面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 */
}

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

参考资料

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

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
STM32定时器是一种硬件模块,用于生成精确的时间延迟、测量时间间隔和产生定时中断等功能。在STM32微控制器中,定时器可以用来实现各种时间相关的应用,如PWM生成、输入捕获、输出比较和定时中断等。 对于从0到1的完整知识,我理解您是指从定时器计数值从0增加到1的过程。下面我将为您解释一下: 1. 选择合适的定时器STM32微控制器通常具有多个定时器,您需要选择适合您需求的定时器。每个定时器都有不同的特性和功能,例如16位或32位计数器、时钟源选择和预分频等。 2. 配置定时器模式:根据您的需求,选择定时器模式。常见的模式有定时器模式、输入捕获模式和输出比较模式等。对于从0到1的完整知识,您可以选择定时器模式。 3. 配置定时器参数:设置定时器的参数,例如计数器的初始值、自动重载值和预分频系数等。对于您的需求,将计数器的初始值设置为0,并将自动重载值设置为1。 4. 启动定时器:通过设置相关位来启动定时器。这将开始定时器的计数过程。 5. 等待定时器计数:您需要等待定时器的计数值增加到1。根据定时器的频率和预分频系数,以及其他相关因素,定时器的计数速度可能不同。 6. 检测定时器溢出:一旦定时器的计数值增加到1,它将自动重载为初始值并触发定时器溢出中断。您可以通过检测定时器溢出中断来判断计数值是否已经达到1。 以上是从0到1的完整知识的基本步骤。请注意,具体的配置和操作步骤可能因不同的STM32系列和芯片而有所差异。因此,在实际开发中,请参考相关的STM32芯片手册和资料来了解具体的细节和配置方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

书阁下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值