STM32主要有5个时钟源:
HSI:内部高速时钟,8Mhz左右
HSE:外部高速时钟,即百为STM32开发板上的X1,8Mhz晶振
PLL:PLL时钟,可以是HSI或HSE的倍频,倍频后可达到72Mhz
LSI:内部低速时钟,40Khz左右
LSE:外部低速时钟,即百为STM32开发板上的X2,32.768Khz晶振,用来驱动RTC时钟
因为内部时钟不太准确,所以我们一般都是用外部时钟,系统时钟一般是通过HSE倍频后得到72Mhz。
选择哪个时钟,设置什么频率是由程序来决定的。
上面是STM32的时钟源框图,可以大致看出STM32各模块的时钟源
这个图其实就是STM32F10xxx参考手册CD00171190.pdf里第56页的图8 时钟树的简化版,如下图,图8描述得更详细一点,多了FSMC,SDIO,SPI/I2S等的时钟源。
上面的图8还不够仔细,因为还有APB1,APB2对应的其他外设还没列出来。
完整的APB1,APB2对应的外设模块在STM32F10xxx参考手册CD00171190.pdf的第二章 2.1 系统构架里有列了出来,如图1 系统结构:
STM32的各个模块都有对应的时钟源,当要使用模块时,要把对应的时钟打开。
上面的图一下子看觉得很复杂,没关系,暂时不需要全部了解的,等要学习其他模块的时候再回来看这些图,会有不同理解的。
我们现在的目的主要是把系统时钟设置为72Mhz。具体设置看下面程序和注释。
寄存器版本,仅作为学习理解用,一般编写程序是用后面的库函数版本:
/* main.c */
void delay(int time)
{
int i,j;
for(i=0; i<time; i++)
for(j=0; j<1000; j++);
}
int main()
{
int i;
RCC_CR |= (u32)0x00010000; //系统上电默认是用HSI内部高速时钟作为系统时钟,我们需要置位RCC控制寄存器的HSEON位打开HSE外部高速时钟
while((RCC_CR & ( 1<<17 )) == 0); //判断HSERDY位,若为1,表示HSE外部高速时钟已打开
FLASH_ACR |= 0x00000010; //使能预取指缓冲
FLASH_ACR = ( FLASH_ACR & ((u32)0xfffffff8) ) | 0x00000002; //设置FLASH为2个等待状态
RCC_CFGR &= (u32)0xFFFFFF0F; //设置HCLK时钟为SYSCLK
RCC_CFGR &= (u32)0xFFFFC7FF; //设置PCLK2时钟为HCLK
RCC_CFGR = ( RCC_CFGR & ((u32)0xFFFFF8FF) ) | (u32)0x00000400; //设置PCLK1时钟为HCLK/2
RCC_CFGR |= 0x00010000 | 0x001C0000; //设置PLL倍频为9,PLLCLK = 8MHz * 9 = 72 MHz
RCC_CR |= 1<<24; //打开PLL时钟
while((RCC_CR & (1<<25)) == 0); //等待PLL时钟打开
RCC_CFGR = ( RCC_CFGR & ((u32)0xFFFFFFFC) ) | 0x00000002; //设置PLL时钟作为系统时钟源,取代上面设置的HSE时钟。
while((RCC_CFGR & 0x0000000C) != 0x08); //等待PLL设置为系统时钟,此时系统已经成功跑在72MHz了
RCC_APB2ENR |= 1<<7; //打开GPIOF的时钟
GPIOF_CRL = ( GPIOF_CRL & 0x00ffffff ) | 0xcc000000; //配置PF6,PF7为通用推挽输出模式,最大速度50MH
GPIOF_CRH = ( GPIOF_CRH & 0xffffff00 ) | 0x000000cc; //配置PF8,PF9为通用推挽输出模式,最大速度50MH
while(1)
{
for(i=6;i<=9;i++)
{
GPIOF_ODR = ( GPIOF_ODR & 0xfffffc3f ) | ( 1<<i ); //在PF6~PF9引脚轮流输出高电平
delay(1000);
}
}
}
库函数版本:
/* main.c */
#include "stm32f10x_lib.h"
void Delay(vu32 nCount)
{
for(; nCount != 0; nCount--);
}
void RCC_Configuration(void)
{
RCC_DeInit(); //RCC系统复位,仅在调试时用(如JLINK调试)
RCC_HSEConfig(RCC_HSE_ON); //打开HSE外部8Mhz高速时钟
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE时钟打开
if(HSEStartUpStatus == SUCCESS) //若HSE时钟打开成功
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH缓冲
FLASH_SetLatency(FLASH_Latency_2); //设置FLASH为2个等待状态
RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置HCLK时钟为SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); //设置PCLK2时钟为HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); //设置PCLK1时钟为HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //设置PLL倍频为9,PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLCmd(ENABLE); //打开PLL时钟
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待PLL时钟打开
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //设置PLL时钟作为系统时钟源,取代上面设置的HSE时钟
while(RCC_GetSYSCLKSource() != 0x08) //等待PLL设置为系统时钟,此时系统已经成功跑在72MHz了
{
}
}
}
int main()
{
RCC_Configuration(); //配置系统时钟跑在72Mhz等
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); //打开LED时钟,即GPIOF时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF, &GPIO_InitStructure); //配置PF6~PF9为通用推挽输出模式,最大速度50MH
while (1)
{
GPIO_SetBits(GPIO_LED, GPIO_Pin_6); //点亮LED1
Delay(0xAFFFF);
GPIO_ResetBits(GPIO_LED, GPIO_Pin_6);//灭掉LED1
GPIO_SetBits(GPIO_LED, GPIO_Pin_7); //点亮LED2
Delay(0xAFFFF);
GPIO_ResetBits(GPIO_LED, GPIO_Pin_7);//灭掉LED2
GPIO_SetBits(GPIO_LED, GPIO_Pin_8); //点亮LED3
Delay(0xAFFFF);
GPIO_ResetBits(GPIO_LED, GPIO_Pin_8);//灭掉LED3
GPIO_SetBits(GPIO_LED, GPIO_Pin_9); //点亮LED4
Delay(0xAFFFF);
GPIO_ResetBits(GPIO_LED, GPIO_Pin_9);//灭掉LED4
}
}
|