打印

百为STM32开发板教程之二——RCC时钟系统

[复制链接]
2610|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xi_liang|  楼主 | 2013-7-19 14:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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
        }
}
沙发
小李白| | 2013-9-23 11:01 | 只看该作者
多谢楼主了

使用特权

评论回复
板凳
zeluo| | 2013-9-23 18:59 | 只看该作者
好详细的学习资料啊   楼主   感觉很给力   很不错   需要花时间好好琢磨琢磨   很不错

使用特权

评论回复
地板
xi_liang|  楼主 | 2014-5-15 23:28 | 只看该作者
zeluo 发表于 2013-9-23 18:59
好详细的学习资料啊   楼主   感觉很给力   很不错   需要花时间好好琢磨琢磨   很不错  ...

谢谢支持,买开发板还有更给力的资料

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:http://baiweijishu.taobao.com/ 百为STM32开发板 兼容官方STM3210E-EVAL开发板 WM-G-MR-09 WIFI开发板

41

主题

285

帖子

10

粉丝