STM32F103学习 - 系统框架和时钟树
前言
看懂MCU系统框架和时钟树,是使用任何一款单片机的基础,尤其是时钟树部分,涉及到后续各个外设的工作频率以及systick滴答定时器的定时周期。
一、STM32F1系统架构
STM32F1包含4个主动单元和4个被动单元
4个主动单元:
M3内核DCode总线(D-bus)、M3内核系统总线(S-bus)、通用DMA1、通用DMA2
4个被动单元:
内部SRAM、内部Flash、FSMC、AHB到APB的桥(它连接所有的APB外设)
其中,AHB称为高级高性能总线,APB成为高级外围总线。
M3内核的最大时钟频率为72Mhz,而AHB总线最大时钟频率为72Mhz,APB1总线最大时钟频率为36Mhz,APB2总线最大时钟频率为72Mhz。
由于不同外设的工作时钟频率需求不同,所以分了两条外设总线来满足不同外设。
二、系统架构图

如何查看系统框架图:
1、首先找到总线矩阵
2、以总线矩阵为中心,找到4个主动单元
3、找到4个被动单元
三、认识时钟树
首先,什么是时钟?
时钟是具有周期性的脉冲信号,最常用的是占空比50%的方波。它如同人体的心脏,为单片机片上外设运行提供基本节拍。这种周期性信号为CPU执行指令、存储器访问、外设操作等提供了时间基准。
时钟树是单片机时钟系统的核心架构,它如同精密的"血液循环系统",将时钟信号从源头分配到芯片的各个外设单元。时钟树的设计直接影响系统的稳定性、功耗和性能,是单片机架构中最关键的部分之一。
1.时钟源
时钟树的四个主要时钟源:包括LSI(内部低速时钟)、LSE(外部低速时钟)、HSI(内部高速时钟)和HSE(外部高速时钟)。其中LS代表低速,HS代表高速;"i"表示内部(internal),"e"表示外部(external)。
外部晶体振荡器的稳定性和准确性较好,但需要增加成本;内部RC振荡器不需要额外增加成本,但稳定性一般。通常项目开发对成本控制要求较为严格时,优先考虑内部RC振荡器,尤其是针对家用产品。
2.时钟树简图
高速时钟:
注意,当使用内部高速时钟(HSI)作为时钟源时,系统时钟sysclk最大时钟频率为8Mhz/2*16 = 64Mhz。
低速时钟:
低速内部时钟LSI通常作为独立看门狗IWDG的时钟源
3.时钟树原图
打开参考手册6.2节
4.SYSTICK滴答定时器
SysTick,即滴答定时器,包含在Cortex内核里面,核心是一个24位的递减计数器。
通过对AHB总线(HCLK)8分频后作为SysTick滴答定时器的时钟源,或者将HCLK不分频、直接作为SysTick滴答定时器的时钟源。可通过SysTick_CLKSourceConfig函数配置时钟源,并通过SysTick_Config函数配置定时器周期。
通常将SysTick滴答定时器配置为毫秒级,并将项目中的状态机部分会放到滴答定时器中断内执行。
四、手把手配置时钟(以标准库为例)
1、从STM32启动文件(startup_stm32f10x_hd_vl.s)可以看出芯片复位后进入了SystemInit函数。
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
2、通过一层层检索,找到SetSysClock函数(system_stm32f1xx.c),需要注意的是,在官方例程里,默认时钟源为外部高速时钟HSE,若板子上不带外部晶振,直接烧录该程序是导致执行异常。这里将时钟源配置为内部高速时钟HSI,并将HCLK配置为64Mhz
/**
* @brief Configures the System clock frequency, AHB/APBx prescalers and Flash
* settings.
* @note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
*/
static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSIStatus = 0;
/* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
/* Enable HSI */
RCC->CR |= ((uint32_t)RCC_CR_HSION);//使能内部高速时钟HSI
/* Wait till HSI is ready and if Time out is reached exit */
do
{
HSIStatus = RCC->CR & RCC_CR_HSIRDY;
StartUpCounter++;
} while((HSIStatus == 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT));//等待HSI稳定
if ((RCC->CR & RCC_CR_HSIRDY) != RESET)
{
HSIStatus = (uint32_t)0x01;
}
else
{
HSIStatus = (uint32_t)0x00;
}
if (HSIStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//AHB总线1分频
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV2;//低速APB1总线2分频,64 /2 = 32Mhz
/* PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL));//复位时钟配置
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_DIV2 | RCC_CFGR_PLLMULL16); //8Mhz /2 *16 = 64Mhz
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;//使能PLL时钟
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)//等待PLL时钟稳定
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //选择PLL时钟作为HCLK
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
3、配置SYSTICK滴答定时器,这部分在main函数里
uint32_t SystemCoreClock = 64000000;
/* Setup SysTick Timer for 1 msec interrupts.
------------------------------------------
1. The SysTick_Config() function is a CMSIS function which configure:
- The SysTick Reload register with value passed as function parameter.
- Configure the SysTick IRQ priority to the lowest value (0x0F).
- Reset the SysTick Counter register.
- Configure the SysTick Counter clock source to be Core Clock Source (HCLK).
- Enable the SysTick Interrupt.
- Start the SysTick Counter.
2. You can change the SysTick Clock source to be HCLK_Div8 by calling the
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8) just after the
SysTick_Config() function call. The SysTick_CLKSourceConfig() is defined
inside the misc.c file.
3. You can change the SysTick IRQ priority by calling the
NVIC_SetPriority(SysTick_IRQn,...) just after the SysTick_Config() function
call. The NVIC_SetPriority() is defined inside the core_cm0.h file.
4. To adjust the SysTick time base, use the following formula:
Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s)
- Reload Value is the parameter to be passed for SysTick_Config() function
- Reload Value should not exceed 0xFFFFFF
*/
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//配置HCLK作为作为滴答定时器的时钟源
if (SysTick_Config(SystemCoreClock / 1000))//配置滴答定时器的定时周期,并打开滴答定时器中断
{
/* Capture error */
while (1);
}
总结
理解系统框架和时钟树是STM32开发的基础,尤其时钟配置直接影响外设工作频率和功耗。实际项目中需权衡成本与稳定性选择合适的时钟源,并合理配置SYSTICK定时器。
更多推荐

所有评论(0)