1. STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。
①、HSI是高速内部时钟,RC振荡器,频率为16MHz,精度不高。可以直接作为系统时钟或者用作PLL时钟输入。
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz。
③、LSI是低速内部时钟,RC振荡器,频率为32kHz,提供低功耗时钟。主要供独立看门狗和自动唤醒单元使用。
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC
⑤、PLL为锁相环倍频输出。STM32F4有两个PLL: (主PLL(PLL)由HSE或者HSI提供时钟信号,并具有两个不同的输出时钟。)
第一个输出PLLP用于生成高速的系统时钟(最高168MHz)
第二个输出PLLQ用于生成USB OTG FS的时钟(48MHz),随机数发生器的时钟和SDIO时钟。
2. 系统时钟SYSCLK可来源于三个时钟源:
①、HSI振荡器时钟
②、HSE振荡器时钟
③、PLL时钟
3.STM32F4时钟信号输出MCO1(PA8)和MCO2(PC9)。
MCO1:用户可以配置预分频器(1~5)向MCO1引脚PA8输出4个不同的时钟源:HIS,LSE,HSE,PLL
MCO2:用户可以配置预分频器(1~5)向MCO2引脚PC9输出4个不同的时钟源:HSE,PLL,SYSCLK,PLLI2S
MCO最大输出时钟不超过100MHz
4.任何一个外设在使用之前,必须首先使能其相应的时钟。
SystemInit函数:
系统时钟初始化函数:SystemInit();
使用库函数的时候,在系统启动之后会自动调用:startup_stm32f40_41xxx.s文件中:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
首先如果使用外部时钟源HSE,要配置外部晶振频率:
stm32f4xx.h
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
初始化之前首先通过宏定义定义下面变量来定义系统时钟频率:
#define PLL_M 8
#define PLL_Q 7
#define PLL_N 336
#define PLL_P 2
PLL=8MHz * N/ (M*P)=8MHz* 336 /(8*2) = 168MHz
初始化之后的状态:
SYSCLK(系统时钟) =168MHz
AHB总线时钟(HCLK=SYSCLK) =168MHz
APB1总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL主时钟 =168MHz
初始化之后可以通过变量SystemCoreClock获取系统变量。
如果SYSCLK=168MHz,那么变量SystemCoreClock=168000000。
Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器。 Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
4个Systick寄存器:
CTRL SysTick 控制和状态寄存器 LOAD
SysTick 自动重装载除值寄存器 VAL
SysTick 当前值寄存器 CALIB
SysTick 校准值寄存器
SysTick 控制和状态寄存器- CTRL
对于STM32,外部时钟源是 HCLK(AHB总线时钟)的1/8内核时钟是 HCLK时钟 配置函数:SysTick_CLKSourceConfig();
SysTick 重装载数值寄存器- LOAD
SysTick 当前值寄存器- VAL
SysTick_CLKSourceConfig函数:
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{
/* Check the parameters */
assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
{
SysTick->CTRL |= SysTick_CLKSource_HCLK;
}
else
{
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
}
}
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
/* set reload register */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
/* set Priority for Cortex-M0 System Interrupts */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}