当前位置:网站首页>剖析STM32F103时钟系统

剖析STM32F103时钟系统

2022-08-09 10:56:00 zhaodong_jack

本文所有代码全部使用寄存器方式实现,因为直接操作寄存器更清晰。测试使用的芯片是STM32F103ZET6,硬件LED接在PB5管脚上,芯片外接晶振为8M晶振。

1.STM32F103时钟树,想要了解时钟系统必须看懂时钟树。如下图

 

PLLSRC:PLL(锁相环)时钟源选择有两个。

1.选择内部RC振荡器2分频输出;

2.选择外部晶振时钟;当选择外部晶振时钟时,通过配置PLLXPTRE 可以是外部晶振不分频直接输出到PLL时钟源,也可以是外部晶振2分频输出到PLL时钟源。

PLLMUL:PLL的倍频系数。

SW:SYSCLK时钟源选择有3种。

1.内部8M的RC振荡器输出到SYSCLK。

2.锁相环输出到SYSCLK。

3.外部晶振输出到SYSCLK。

SYSCLK时钟经过AHP分频器输出到AHB。AHB总线挂有SDIO,FSMC,内核,内存,DMA等高速设备,

AHB时钟经过APB1分频器输出到APB1。APB1总线挂接的都是低速设备,比如TIMER2,3,4,5,6,7。

AHB时钟经过APB2分频器输出到APB2。APB2总线挂接的是高速设备,比如TIMER1,8

SYSCLK输出到AHB,AHB输出到APB1和APB2.

 

CSS:CSS是时钟安全系统。如果使能了CSS,并且外部高速时钟发生故障,那么系统时钟会自动切换到内部RC振荡器。

代码

#include "stm32f10x.h"
/****STM32时钟初始化****/
void clock_init(void)
{
    RCC->CR |= RCC_CR_HSEON;//使能外部高速时钟
    while((RCC->CR & RCC_CR_HSERDY) == 0);//等待外部时钟就绪
    RCC->CR &= ~RCC_CR_PLLON;//关闭锁相环  进行锁相环相关的配置必须先关闭锁相环
    
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    


    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//AHB的时钟(HCLK)等于系统时钟(SYSCLK)
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//APB2的时钟(PCLK2)等于系统时钟(SYSCLK)
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//APB1的时钟(PCLK1)等于系统时钟/2(SYSCLK/2)
    
    RCC->CFGR |= RCC_CFGR_PLLXTPRE_HSE;//HSE的时钟不分频
    RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;//锁相环时钟源选择HSE
    RCC->CFGR |= RCC_CFGR_PLLMULL9;//8*9 = 72M 锁相环输出72M
    
    RCC->CR |= RCC_CR_PLLON;//配置完成以后使能锁相环
    while((RCC->CR & RCC_CR_PLLRDY) == 0);//等待锁相环时钟稳定
    
    RCC->CFGR &= ~RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;//系统时钟选择锁相环时钟  SYSCLK = PLL = 72M 
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08);//等待时钟切换完成
    
    SCB->VTOR = FLASH_BASE;
    
    RCC->CFGR |= RCC_CFGR_MCO_SYSCLK;//MCO输出SYSCLK的时钟
    
}
/****滴答定时器初始化****/
void systick_init(void)
{
    SysTick->LOAD = 0;//滴答定时器重载值为
    SysTick->VAL = 0;
    SysTick->CTRL |= 0x04;//滴答定时器时钟源选择HCLK
    SysTick->CTRL &= ~0x01;//禁止计数 
}
/****延时函数****/
void systick_delay(uint32_t counter)
{
    SysTick->LOAD = counter;
    SysTick->VAL = 0;
    SysTick->CTRL |= 0x01;//使能计数 
    while(((SysTick->CTRL)&(0x10000)) == 0);//等待计数完成
}
/****MCO管脚初始化****/
void mco_pin_init(void)
{
    //MCO的时钟使用PA8管脚输出
    RCC->APB2ENR |= 0x00000004;//使能GPIOA的时钟
    GPIOA->CRH |= GPIO_CRH_MODE8_0 |GPIO_CRH_MODE8_1;//50M输出速度
    
    GPIOA->CRH &= ~GPIO_CRH_CNF8_0;//复用推挽输出
    GPIOA->CRH |= GPIO_CRH_CNF8_1;
}
void led_init(void)
{
    RCC->APB2ENR |= 0x00000008;//使能GPIOB的时钟
    GPIOB->CRL &= ~ 0x00f00000;
    GPIOB->CRL |= 0x00300000;
}
/****点亮LED(低电平)****/
void led_on(void)
{
    GPIOB->ODR &= ~0x00000020;
}
/****关闭LED(高电平)****/
void led_off(void)
{
    GPIOB->ODR |= 0x00000020;
}

int main()
{
    clock_init();
    mco_pin_init();
    systick_init();
    led_init();
    
    while(1)
    {
        led_on();
        systick_delay(72000);
        led_off();
        systick_delay(72000);
    }
    return 0;
}
 

通过配置寄存器,测试各个时钟,可以通过MCO管脚输出(MCO管脚最高输出50MHZ)。、

我这里是配置PLLXTPRE不分频(8M),PLLSRC选择外部晶振时钟源(8M),PLLMUL选择9倍频(72M),系统时钟选择PLL时钟。那么就是8M*9=72M。

滴答定时器选择HCLK(AHB时钟)。此时HCLK = SYSCLK = PLL = HSE * 9 = 72M

上边程序延时1ms,经过测试没有问题。

为什么倍频偏偏选择9倍频呢?因为ST官方说PLL时钟输出不能超过72M。我们不是乖孩子,我们要超频。配置16倍频,HSE*16 = 128M。超频跑一下,看会怎么样呢,同样用滴答定时器检验。

    RCC->CFGR |= RCC_CFGR_PLLMULL16;//8*16 = 128M 锁相环输出128M

    systick_delay(128000);

经过测试超频跑也是杠杠滴。

我手上的板子外接晶振是8M,8*16 = 128,最大速度跑到128M。如果外接16M晶振,配置16倍频,能不能跑到256M呢?这个我暂时没法测试(手上没有16M晶振)。

 

 

 

 

原网站

版权声明
本文为[zhaodong_jack]所创,转载请带上原文链接,感谢
https://blog.csdn.net/zhaodong1102/article/details/105032927