STM32 时钟 定时器基础

本文详细介绍了STM32的时钟源,包括外部晶振和内部时钟,强调了外部时钟源的准确性。接着,讨论了定时器的工作原理,特别是基本定时器的计数方式和中断处理。还提到了通用定时器的外部时钟模式以及高级定时器的特性。此外,介绍了如何在CubeMX中配置时钟源和定时器。
AI助手已提取文章相关产品:
  • STM32 —— Clock Tree

    时钟源

    1. HSI:(High Speed Internal)内部的 RC 震荡电路产生时钟信号。
    2. HSE:(High Speed External) 外部晶振产生时钟信号。

    采用外部晶振信号原因在于:

    1. 晶振信号准确度更高
    2. 部分外设只能在晶振信号下工作
    1. LSE:(Low Speed External)外部晶振
    2. LSI:(Low Speed Internal)内部 RC

    在这里插入图片描述

    以上图为例:

    1. 低速时钟信号提供给 RTC (Real Time Clock)和 IWDG
    2. 高速时钟信号,经过时钟选择器(System Clock Mux),输出给 SYSCLKSYSCLK分频(AHB Prescaler )作为 AHB 时钟信号。AHB 信号经过分频作为 APB1APB2 时钟信号。

    CubeMX 设置

    RCC

    时钟源有两种提供方式:CrystalBYPASSCrystal 就是石英晶振,两条线接入 OSC_INOSC_OUT 。而 BYPASS (官方文档也称为 External Source ),则是只提供 OSC_INOSC_OUT 引脚悬空。

    RCC 下面的 Master Clock Output 则是可以让 RCC_MCO 输出时钟信号,给其它外设使用。

    如果用一块 STM32 给另一块板子提供时钟信号,那么从设备就应该选择 BYPASS

    SYS

    下面有 Timebase Source ,选择作为系统时钟的时钟源。系统时钟中断产生周期由一下语句确定

    HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq));
    

    SystemCoreClock 变量由 SystemCoreClockUpdate() 函数维护。每当 SysTick 提供时钟改变时,此变量也会相应改变。手动修改时注意

    定时器

    定时器是 MCU 中自主运行(free-running)的计数器。其时钟源可以来自以下三个方面:

    1. 内部时钟,也就是 Timer 所在的总线。
    2. 外部时钟源。
    3. 其余定时器作为时钟源。

    定时器分类

    更高级的定时器继承了低级定时器的所有功能。

    Basic Timers

    Basic Timers are 16-bit timers used as time base generator, and they do not have output/input pins. Basic timers can also be used as “master” for other timers.

    基本定时器从 0 计数到 Period 值,计数频率由挂载的是时钟总线决定,并可由 Prescalar 分频。当溢出时会产生 Update Event(UEV) 中断,并自动从初值(0)开始计数。

    基础定时器的主要结构由三个寄存器构成—— Counter Register (TIMx_CNT,当前计数值) / Prescaler Register (TIMx_PSC,预分频) / Auto-Reload Register (TIMx_ARR,溢出比较值)。当定时器使能后,每一个寄存器都可由软件读写。

    在这里插入图片描述

    PSC 的值存放在 Prescaler Control Register 里,当产生更新事件时,才会装载到 Prescaler Buffer 中,并在下一个计数周期内产生作用。

    更新事件 (Update Event,UEV)

    更新事件产生与否由 CR1 中 UDIS 位决定。当此位使能后,更新事件可由以下三种方式产生:

    1. 计数器上溢出或者下溢出。
    2. 设置 EGR 寄存器中的 UG 位。
    3. 从设备 (slove mode) 产生。

    当更新事件产生后,CNT 清 0 ,自动装载影子寄存器由 ARR 装载,预分频缓存由预分频寄存器装载。设置中断标志位(如果 SR 寄存器的 UIF 使能)

    EGR 寄存器 (Event Generation Register) 可由软件设置,由硬件自动清除。如果用软件将其末位置 1,会重置这个定时器并产生更新事件。(预分频计数器也会被重置)

    CubeMX 配置

    在这里插入图片描述

    • Prescalar :将总线的时钟频率分频后作为定时器的时钟频率。
    • Period : 定时器的计数上限。

UpdateEvent=Timerclock(Prescalar+1)(Period+1)Hz UpdateEvent = \frac{Timer_{clock}}{(Prescalar+1)(Period+1)} Hz UpdateEvent=(Prescalar+1)(Period+1)TimerclockHz

  • CounterMode: 指定计数方式。上升、下降、中间对齐。
  • auto-reload preloadAPRE 位;是否预先装载。ARR 实际上有两个寄存器,一个是可以直接操作,另一个无法直接操作的。根据 TIMx_CR1 寄存 器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 APRE=1 时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。
使用
  • 中断方法

作为基本定时器,每隔一段时间产生一次中断。中断产生频率由 PeriodPrescalar 确定。HAL_TIM_Start_IT 开始中断传输;定时器溢出(计数到 Period)后,产生UIF中断(或者由 __HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET 判断)。

采用 STM32 HAL 库编程时,中断处理有对应的回调函数。在回调函数中判断传入的设备号后执行相应的代码。

中断处理结束后,记得清楚其标志位。 __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE)

  • Polling 方法

轮询时,使用大于等于判断;这主要是由于 CPU 执行需要消耗时间,很难精确读到某个值。采用函数读取 __HAL_TIM_GET_COUNTER(&tim) 计数器的值。

  • DMA Mode

采用 DMA,能释放 CPU 更多资源(CPU 不用去处理定时器频繁的中断)。应用于诸如 PWM 场景。

定时器 DMA 请求设定是 __HAL_TIM_ENABLE_DMA 。是设置定时器寄存器 DIER 寄存器相应位,开启 DMA 请求。与中断类似,在定时器计数溢出时,会发出 DMA 请求,DMA 依据配置执行数据传送。

HAL 库中无法使能基本定时器,给控制寄存器赋值后没有反应。

General Purpose Timers

通用定时器可以采用外部时钟源作为定时器的计数信号。

外部时钟源
  • External Clock Mode2 (ETR2)

在这里插入图片描述

当选择 Clock Source 为 ETR2 时,定时器采用外部时钟源。额外多出下面三个参数:

  • Clock Filter 设置的是 SMCR 寄存器的 ETF 位,具体见参考手册。默认置 0 即可。
  • Clock Polarity 信号源是否反转,设置的是 SMCR 寄存器的 ETP 位。
  • Clock Prescaler 输入时钟信号的预分频。

也可以采用内部其它定时器提供的信号作为另一个定时器的时钟源

  • External Clock Mode1 (ETR1)

在 ETR1 模式下的定时器能够接受内部 ITR0 ~ ITR3 的信号与 TI1FP1 与 TI2FP2 外部信号源。参数配置与 ETR2 相同。如果选择内部线的话,需要配置主定时器,会用到 Trigger Event Selection

  • Trigger Event Selection:主从设备设置时使用,本质上设置的是 CR2 寄存器。选择 Reset,是将主定时器 EGR 寄存器的 UG 位作为触发信号,也就是主定时器重置时,从定时器触发一次。Update Event,主定时器的更新事件作为触发信号,当主定时器溢出时触发从定时器。Enable,主定时器的使能位作为触发信号,主定时器使能触发从定时器更新。

从定时器被触发时可以使能相应的中断,可以编写 HAL_TIM_TriggerCallback 中断函数处理。

  • 软件强制生成事件

设置定时器的 EGR 寄存器可以强制其生成事件。 HAL 库提供 HAL_TIM_GenerateEvent。强制生成事件可以:

  1. 若生成更新事件,可以让 ARR 寄存器值装载到影子寄存器中。可以让主寄存器触发从寄存器。

Advanced Timers

typedef struct { 
    uint32_t Prescaler; /* Specifies the prescaler value used to divide the TIM clock. */ 
    uint32_t CounterMode; /* Specifies the counter mode.*/ 
    uint32_t Period; /* Specifies the period value to be loaded into the active Auto-Reload Register at the next update event.*/ 
    uint32_t ClockDivision; /* Specifies the clock division.*/ 
    uint32_t RepetitionCounter; /* Specifies the repetition counter value.*/ 
} TIM_Base_InitTypeDef; 

typedef struct { 
    TIM_TypeDef* Instance; /* Pointer to timer descriptor */ 
    TIM_Base_InitTypeDef Init;/* TIM Time Base required parameters */ 
    HAL_TIM_ActiveChannel Channel; /* Active channel*/ 
    DMA_HandleTypeDef* hdma[7]; /* DMA Handlers array*/ 
    HAL_LockTypeDefLock;/* Locking object*/ 
    __IO HAL_TIM_StateTypeDef State; /* TIM operation state*/ 
} TIM_HandleTypeDef; 
  • ClockDivision: 外部输入时钟信号与内部计数时钟信号之间的分频系数。

HAL_TIM_IRQHandler 可以适当剪裁,其功能有些多余。

  • hdma :计数器有七种 DMA 请求,与这个数组一一对应。

中断处理

在这里插入图片描述

HAL 采用统一的定时器中断处理函数,按如下划分中断事件。每个 IF 语句中有回调函数,只需要定义回调函数处理对应中断事件即可。

您可能感兴趣的与本文相关内容

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值