天天看点

STM32的时钟简介和配置方法

STM32的时钟简介:

STM32中使用任何一个外设都必须打开相应的时钟。在STM32中有5个时钟源可供用户选择:

1.HSI高速内部时钟,RC震荡器,频率为8MHz。

2.HSE高速外部时钟,右英/陶瓷谐振器,或着外部时钟源,4MHz-16MHz.

3.LSI内部低速时钟,RC震荡器频率为40Hz。

4.LSE外部低速时钟,接频率为32.768KHz的石英晶体。

5.PLL锁相环频输出,时钟源可选为HIS/2、HSE或HSE/2。倍频可选2-16倍,但其输出频率最大不能超过72MHz。

系统时钟SYSCLK,它是供STM32中绝大部分器件工作的时钟源,系统时钟可选择为PLL输出、HSI或者HSE。系统时钟的做大频率为72MHz,它通过AHB分频器分频后送给个模块使用,AHB分频器可选择1、2...512分频。AHB分频器输出的时钟送给5大模块使用:

1.送给AHB总线、内核、内存、DMA使用的HCLK时钟。

2.通过8分频送给系统定时器的定时时钟(嘀嗒定时器)。

3.直接送给Cortex的空闲时钟PCLK。

4.送给APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36M)另一路送给定时器(Timer)2、3、4倍频器使用。该倍频器可选择1或着2倍频,时钟输出供定时器2、3、4使用。

5.送给APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72M)另一路送给定时器(Timer)1倍频器使用。该倍频器可选择1或着2倍频。时钟输出供定时器1使用。另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选 择为2、4、6、8分频。

连接在APB1(低速外设)上设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、TIMER2、TIMER3、TIMER4。

连接在APB2(高速外设)上设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口、第二功能IO口。

STM32的时钟简介和配置方法

涉及的寄存器:

RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x_map.h”中定义如下: 

typedef struct 

vu32 CR;                  //HSI,HSE,CSS,PLL等的使能 

vu32 CFGR;              //PLL等的时钟源选择以及分频系数设定

vu32 CIR;                // 清除/使能 时钟就绪中断

vu32 APB2RSTR;      //APB2线上外设复位寄存器

vu32 APB1RSTR;      //APB1线上外设复位寄存器

vu32 AHBENR;         //DMA,SDIO等时钟使能

vu32 APB2ENR;       //APB2线上外设时钟使能

vu32 APB1ENR;      //APB1线上外设时钟使能

vu32 BDCR;           //备份域控制寄存器

vu32 CSR;            

} RCC_TypeDef;

在ST公司的外设固件库的示例里,对于工程项目文件,ST并没有在启动函数main()里初始化PLL,因为其已经在硬件初始化阶段完成对系统时钟的配置。这样也就带了一个问题,ST库里的均使用了外设8MHz的晶振,而我们平时的项目就一定采用的是这个频率,实际配置的低于8MHz,MCU不能全速运行,高于8MHz,外设时钟即配置失败,甚至无法运行。那么如何重新配置时钟就需要我们重新设计了。

以下为使用库函数重新编写了STM32F系统时钟PLL初始化过程:

以下的函数需要添加#include "stm32f10x.h"的头文件来调用ST固件库。

static void SysClockInit(void)

{

RCC_DeInit();

RCC_HSEConfig(RCC_HSE_ON);

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if (HSEStartUpStatus == SUCCESS)

{

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

FLASH_SetLatency(FLASH_Latency_2);

RCC_HCLKConfig(RCC_SYSCLK_Div1);

RCC_PCLK2Config(RCC_HCLK_Div1);

RCC_PCLK1Config(RCC_HCLK_Div2);

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

RCC_PLLCmd(ENABLE);

while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

{

}

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

while(RCC_GetSYSCLKSource() != 0x08)

{

}

}

else

{

while (1)

{

}

}

}

继续阅读