-
STM32 —— Clock Tree
时钟源
- HSI:(High Speed Internal)内部的 RC 震荡电路产生时钟信号。
- HSE:(High Speed External) 外部晶振产生时钟信号。
采用外部晶振信号原因在于:
- 晶振信号准确度更高
- 部分外设只能在晶振信号下工作
- LSE:(Low Speed External)外部晶振
- LSI:(Low Speed Internal)内部 RC

以上图为例:
- 低速时钟信号提供给
RTC(Real Time Clock)和IWDG - 高速时钟信号,经过时钟选择器(System Clock Mux),输出给
SYSCLK。SYSCLK分频(AHB Prescaler)作为AHB时钟信号。AHB信号经过分频作为APB1与APB2时钟信号。
CubeMX 设置
RCC
时钟源有两种提供方式:
Crystal和BYPASS。Crystal就是石英晶振,两条线接入OSC_IN和OSC_OUT。而BYPASS(官方文档也称为External Source),则是只提供OSC_IN和OSC_OUT引脚悬空。RCC下面的Master Clock Output则是可以让RCC_MCO输出时钟信号,给其它外设使用。如果用一块 STM32 给另一块板子提供时钟信号,那么从设备就应该选择
BYPASS。SYS
下面有
Timebase Source,选择作为系统时钟的时钟源。系统时钟中断产生周期由一下语句确定HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq));SystemCoreClock变量由SystemCoreClockUpdate()函数维护。每当 SysTick 提供时钟改变时,此变量也会相应改变。手动修改时注意。定时器
定时器是 MCU 中自主运行(
free-running)的计数器。其时钟源可以来自以下三个方面:- 内部时钟,也就是 Timer 所在的总线。
- 外部时钟源。
- 其余定时器作为时钟源。
定时器分类
更高级的定时器继承了低级定时器的所有功能。
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 位决定。当此位使能后,更新事件可由以下三种方式产生:
- 计数器上溢出或者下溢出。
- 设置 EGR 寄存器中的 UG 位。
- 从设备 (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 preload:APRE位;是否预先装载。ARR 实际上有两个寄存器,一个是可以直接操作,另一个无法直接操作的。根据 TIMx_CR1 寄存 器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2 者是连通的;而 APRE=1 时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。
使用
- 中断方法
作为基本定时器,每隔一段时间产生一次中断。中断产生频率由 Period 和 Prescalar 确定。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。强制生成事件可以:
- 若生成更新事件,可以让 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 语句中有回调函数,只需要定义回调函数处理对应中断事件即可。
本文详细介绍了STM32的时钟源,包括外部晶振和内部时钟,强调了外部时钟源的准确性。接着,讨论了定时器的工作原理,特别是基本定时器的计数方式和中断处理。还提到了通用定时器的外部时钟模式以及高级定时器的特性。此外,介绍了如何在CubeMX中配置时钟源和定时器。
425

被折叠的 条评论
为什么被折叠?



