这篇文章介绍了32的时钟,所谓时钟就是32的各种片上外设功能的频率,配置频率可以说是各种外设初始化的第一步
STM32时钟系统
- STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。
①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时 钟源,频率范围为4MHz~16MHz。
③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。WDG
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC
⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。 - 系统时钟SYSCLK可来源于三个时钟源:
- ①、HSI振荡器时钟
②、HSE振荡器时钟
③、PLL时钟 - STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。
- 任何一个外设在使用之前,必须首先使能其相应的时钟。
重要的时钟有:
- SYSCLK(系统时钟)
- AHB总线时钟
- APB1总线时钟(低速): 速度最高36MHz
- APB2总线时钟(高速): 速度最高72MHz
- PLL时钟
时钟配置文件
头文件: stm32f10x_rcc.h 和 源文件:stm32f10x_rcc.c
时钟系统初始化函数
函数
SystemInit
在系统启动之后会在汇编代码中自动调用,启动文件中的汇编代码指定了系统启动的初始地址
该函数定义在startup_stm32f10x_xx.s文件中,
函数定义了以下时钟的频率,初始化后的状态如图:
初始化之前首先通过宏定义定义系统时钟频率:
#define SYSCLK_FREQ_72MHz 72000000
初始化之后可以通过变量SystemCoreClock获取系统变量。如果SYSCLK=72MHz,那么变量SystemCoreClock=72000000。
滴答定时器
-
Systick定时器,是一个简单的定时器,Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。
-
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
-
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。Systick中断的优先级也可以设置。
4个有关Systick的寄存器
CTRL | SysTick 控制和状态寄存器 |
---|---|
LOAD | SysTick 自动重装载除值寄存器 |
VAL | SysTick 当前值寄存器 |
CALIB | SysTick 校准值寄存器 |
配置CLKSOURCE时,外部时钟源是 HCLK(AHB总线时钟)的1/8,内核时钟是 等于HCLK时钟的
配置函数SysTick_CLKSourceConfig(),在misc.c文件中
Systick相关函数:
// 在misc.c文件中
//Systick时钟源选择
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;
}
}
//在core_cm3.h/core_cm4.h文件中
//初始化systick,时钟为HCLK,LOAD,VAL,CTRL并开启中断
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
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 */
}
Systick中断服务函数
用中断的方式实现延时,此方法浪费资源
//默认在stm32f10x.c中
static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
void SysTick_Handler(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
int main(void)
{ …
if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK,中断时间间隔1ms
{
while (1);
}
while(1)
{ Delay(200);//2ms
…
}
}
采用查询方式实现延时,看正点原子代码
void delay_init()
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为M
reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
#endif
}