-
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
: 定时器的计数上限。
U
p
d
a
t
e
E
v
e
n
t
=
T
i
m
e
r
c
l
o
c
k
(
P
r
e
s
c
a
l
a
r
+
1
)
(
P
e
r
i
o
d
+
1
)
H
z
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)
。
轮询时,使用大于等于判断;这主要是由于 CPU 执行需要消耗时间,很难精确读到某个值。采用函数读取 __HAL_TIM_GET_COUNTER(&tim)
计数器的值。
采用 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;
uint32_t CounterMode;
uint32_t Period;
uint32_t ClockDivision;
uint32_t RepetitionCounter;
} TIM_Base_InitTypeDef;
typedef struct {
TIM_TypeDef* Instance;
TIM_Base_InitTypeDef Init;
HAL_TIM_ActiveChannel Channel;
DMA_HandleTypeDef* hdma[7];
HAL_LockTypeDefLock;
__IO HAL_TIM_StateTypeDef State;
} TIM_HandleTypeDef;
ClockDivision
: 外部输入时钟信号与内部计数时钟信号之间的分频系数。
HAL_TIM_IRQHandler
可以适当剪裁,其功能有些多余。
hdma
:计数器有七种 DMA
请求,与这个数组一一对应。
中断处理
HAL 采用统一的定时器中断处理函数,按如下划分中断事件。每个 IF 语句中有回调函数,只需要定义回调函数处理对应中断事件即可。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)