查看: 8991|回复: 4

强仔教你玩stm32f401 Nucleo之系统时钟的配置

[复制链接]
  • TA的每日心情
    奋斗
    2015-10-5 14:38
  • 签到天数: 175 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2014-8-23 09:58:00 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 强仔00001 于 2015-8-6 23:02 编辑

             STM32中,有五个时钟源,为HSIHSELSILSEPLL 其实是四个时钟源,如下图所示(红色方框),PLL是由锁相环电路倍频得到PLL时钟。
    如下图:
    时钟源选择.png
      ①、HSI是高速内部时钟,RC振荡器,频率为16MHz
      ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~26MHz
      ③、LSI是低速内部时钟,RC振荡器,频率为32kHz
      ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
      ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSIHSE。理论倍频,一般不要输出频率最大不要超过84MHz,本人测试可以将内核时钟频率超到144M,建议大家不要超得太大,否则锁相环倍频的过程会失败的,而且超过84M可能出现运行不稳定的情况,建议大家还是最大输出到84M,如果大家的项目对单片机的处理速度要求较高的,可以超频。但不要超得太高。
    STM32F401的时钟系统结构图
    时钟源选择1.png 时钟源选择2.png
     系统时钟SYSCLK,它是供STM32中绝大部分部件工作的时钟源。系统时钟可选择为PLL输出、HSI或者HSE。系统时钟最大频率为84MHz,它通过AHB分频器分频后送给各模块使用,AHB分频器可选择12481664128256512分频。其中AHB分频器输出的时钟送给5大模块使用:
      ①、送给AHB总线、内核、内存和DMA使用的HCLK时钟。
      ②、通过8分频后送给Cortex的系统定时器时钟。
      ③、直接送给Cortex的空闲运行时钟FCLK
      ④、送给APB1分频器。APB1分频器可选择124816分频,其输出一路供APB1外设使用(PCLK1,最大频率42MHz),另一路送给定时器(Timer)2345倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2345使用。
        ⑤、送给APB2分频器。APB2分频器可选择124816分频,其输出一路供APB2外设使用(PCLK2,最大频率84MHz),另一路送给定时器(Timer)191011倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器1,9,10,11使用。另外,APB2分频器还有一路输出供ADC分频器使用,分频后送给ADC模块使用。ADC分频器可选择为2468分频。
             在以上的时钟输出中,有很多是带使能控制的,例如AHB总线时钟、内核时钟、各种APB1外设、APB2外设等等。当需要使用某模块时,记得一定要先使能对应的时钟。
      需要注意的是定时器的倍频器,当APB的分频为1时,它的倍频值为1,否则它的倍频值就为2
        连接在AHB1上的设备有所有普通IO(PA~PE)。这个跟stm32f10xx系列不同。
      连接在APB1(低速外设)上的设备有:电源接口、备份接口、CANUSBI2C1I2C2UART2UART3SPI2、窗口看门狗、Timer2Timer3Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。
      连接在APB2(高速外设)上的设备有:UART1SPI1Timer1ADC1ADC2、第二功能IO口。
             另外STM32F401提供了两个32位的定时器,分别是timer2timer3,这个在定时器设为编码器模式时很有用,因为传统的16定时器计数的范围是216次方,也就是1~65535,而32位的定时器计数范围显然比16位定时器多得多,这里我就不作过多的介绍了,我会在以后的章节中详细说明。

             另外,STM32还可以选择一个时钟信号输出到MCO1(PA8)MCO2(PC9)上,可以选择为PLL输出的1~5分频、HSIHSE、或者系统时钟。

    stm32f401Nucleo板是默认没有焊接上外部晶振的,所以如果大家如果要使用外部晶振,就要自行焊接接上晶振了,在焊接晶振是要注意几点:
    板子外部晶振的连接处默认是打断的,如下图画着红色方框的地方:
    不提供晶振.png 外部晶振的位置.png
    所以大家如果要用上外部高速晶体时,就要焊接上两个电容和两个0欧姆电阻。具体的位置如下图画着红色方框的地方,c33c34的地方是焊接电容的:
    外部晶振怎样焊接.png
        这里需要提醒一下电容的选择,电容最好选择20pf33pf,最好选择大一些的吧,以免在初始化时钟时外部晶振起不了振。这里我选择了电容是30pf,而那两个0欧姆的地方,我直接用焊锡连上了,大家懒的话就可以直接焊锡,因为这些电容,电阻的封装是0603的,这个比较难焊接,由于没有0603封装的电容,我这里就用了0805的来焊接。在晶振的地方,我焊接了圆孔的圆排母,这是为了以后方便更换晶振。下图就是我焊接好外部晶振的图:
    外部晶振焊接.png
        下面我就开始来介绍用st公司的库函数来配置时钟吧,我是用外部晶振通过PLL模块把时钟倍频到自己所需的频率。然后通过PA8输出外部晶振的频率,PC9输出系统时钟频率的二分频来验证时钟设置是否正确。
    时钟配置的步骤:
    voidClock_Config(void)
    {

         uint32_t           PLL_M;      
         uint32_t           PLL_N;
         uint32_t           PLL_P;
         uint32_t           PLL_Q;

        /*配置前将所有RCC重置为初始值*/
         RCC_DeInit();

         /*这里选择 外部晶振(HSE)作为 时钟源,因此首先打开外部晶振*/
         RCC_HSEConfig(RCC_HSE_ON);
         /*等待外部晶振进入稳定状态*/
         while( RCC_WaitForHSEStartUp() != SUCCESS);

         /*
         **我们要选择PLL时钟作为系统时钟,因此这里先要对PLL时钟进行配置
         */

         /*选择外部晶振作为PLL的时钟源*/

         /* 到这一步为止,已有 HSE_VALUE = 12 MHz.
            PLL_VCO input clock = (HSE_VALUE orHSI_VALUE / PLL_M)
            根据文档,这个值被建议在 1~2MHz,因此我们令 PLL_M = 6
             PLL_VCO input clock = 1MHz */
         PLL_M         =   6;  

         /* 到这一步为止,已有 PLL_VCO input clock = 2 MHz.
            PLL_VCO output clock = (PLL_VCO inputclock) * PLL_N,
            这个值要用来计算系统时钟,我们 PLL_N = 336,
             PLL_VCO output clock = 336 MHz.*/      
         PLL_N        =   168;

         /* 到这一步为止,已有 PLL_VCO output clock = 336 MHz.
            System Clock = (PLL_VCO outputclock)/PLL_P ,
            因为我们要 SystemClock = 84 Mhz,因此令 PLL_P = 4.
           */
         PLL_P         =   4;

         /*这个系数用来配置SD卡读写,USB等功能,暂时不用,根据文档,暂时先设为7*/
         PLL_Q         =   7;

         /* 配置PLL并将其使能,获得 84Mhz System Clock 时钟*/
         RCC_PLLConfig(RCC_PLLSource_HSE, PLL_M,PLL_N, PLL_P, PLL_Q);
         RCC_PLLCmd(ENABLE);

         /*到了这一步,我们已经配置好了PLL时钟。下面我们配置Syetem Clock*/
         /*选择PLL时钟作为系统时钟源*/
         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);




    /*到了这一步,我们已经配置好了系统时钟,频率为 84MHz. 下面我们可以对 AHBAPB,外设等的 时钟进行配置*/
         /*时钟的结构请参考用户手册*/

         /*首先配置 AHB时钟(HCLK. 为了获得较高的频率,我们对 SYSCLK 1分频,得到HCLK*/
         RCC_HCLKConfig(RCC_HCLK_Div1);

         /*APBx时钟(PCLK)由AHB时钟(HCLK)分频得到,下面我们配置 PCLK*/

         /*APB1时钟配置. 1分频,即 PCLK1 = 84 MHz*/
         RCC_PCLK1Config(RCC_HCLK_Div1);

         /*APB2时钟配置. 1分频,即 PCLK2 = 84 MHz*/
         RCC_PCLK2Config(RCC_HCLK_Div1);

    /*****函数结束******/

    /*以上函数可以大体上说明这些库函数的作用*/
    关于时钟的计算,如下图:
    系统时钟的计算.png



    }在这里有点需要提醒大家的是,如果你接上晶振时,需要修改一下头文件stm32f4xx.h里的HSE_VALUE的值,我这里的晶振接的是12M的,所以这个数值我改成了12000000,以此来告诉编译器我选的晶振是12M的。
    修改晶振的值.png
         如果大家遇到不能修改的情况,是因为文件是设置为只读,因为官方都把文件设置位只读的,就是怕我们不小心删掉了文件中的内容而导致整个工程编译失败。可以观察到可修改的文件和不可修改(只读文件)在KEIL 5的区别如下图:
    红色方框里的文件是只读文件的,而蓝色方框里的文件是可修改的文件,区别就是只读的文件左侧多了个像钥匙的图标。
    文件被锁了.png
    这是我们需要把文件修改为可读可写的。我这里就以修改stm32f4xx_gpio.c的文件给大家演示下,具体步骤如下:
    双击你需要改的文件,然后再右击,最后点击Open Containing FolderOpen Containing Folder这个命令是查找这个文件所在的路径。
    文件解锁1.png 文件解锁2.png
    找到文件后,然后再右击,点击属性,把属性->只读这个方框里的勾打掉。
    文件解锁3.png 文件解锁4.png
    然后回到编译器,这时就可以发现原来文件左侧的钥匙的小图标已经不见了。
    文件解锁5.png
    当我们做好以上步骤时,就可以配置PA8PC9输出时钟了。
    这里我们用到里库函数里的RCC_MCO1Config(uint32_t RCC_MCO1Source,uint32_t RCC_MCO1Div);RCC_MCO2Config(uint32_t RCC_MCO2Source, uint32_t RCC_MCO2Div);
    这个函数在stm32f4xx_rcc.c文件里,大家要详细了解可以自行去看看。
    下面就贴上我已经注释的代码:
    voidSystem_Clk_Output_Init()
    {
         GPIO_InitTypeDefGPIO_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);//使能GPIOC的时钟

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //选择管脚号
        GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz; //设置管脚的速度
        GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF; //设置管脚位复用功能
        GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;//设置管脚位推完输出
        GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化管脚

        GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_MCO);//打开GPIOC_Pin_9MCO功能
        RCC_MCO2Config(RCC_MCO2Source_SYSCLK,RCC_MCO2Div_2);//设置GPIOC_Pin_9输出系统时钟频率的二分频
    }        

    voidHSE_Clk_Output_Init()
    {
         GPIO_InitTypeDefGPIO_InitStructure;

         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA的时钟

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //选择管脚号
        GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;// 设置管脚的速度为100M
        GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF; //设置管脚位复用功能
        GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;//设置管脚位推完输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化管脚

        GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_MCO);//打开GPIOA_Pin_9MCO功能
        RCC_MCO1Config(RCC_MCO1Source_HSE,RCC_MCO2Div_1);//设置GPIOA_Pin_8输出外部高速晶振HSE的频率

    }        

    以上这两个函数是配置PA8PC9管脚为MCO模块。
    在主函数中直接调用函数就可以了。
    intmain()
    {
             //System_HSE_Init();
             Clock_Config();
             SystemCoreClockUpdate();
             System_Clk_Output_Init();
             HSE_Clk_Output_Init();
             while(1)
             {

             }
    }
    以下就是我仿真时通过SystemCoreClockUpdate();(刷新系统时钟的函数),可以看到时钟已经设置为84M
    仿真的时钟值.png
    以下就是我用PA8输出HSE的频率和PC9输出系统时钟频率的二分频,用示波器观察频率如下图:
    stm32f401Necleo的管脚分布图
    管脚图.png
    HSE输出.jpg
    84M一半输出.jpg
    这个图是系统时钟频率超频到120M,然后用PC9输出系统时钟频率的二分频,用示波器观察:
    超频到120一半输出.jpg

    强仔教你玩stm32f401 Nucleo之系统时钟的配置库函数版.zip (76.48 KB, 下载次数: 109)
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2020-11-24 19:39
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2015-9-7 18:53:17 | 显示全部楼层
    感谢分享~
    相当详细!!!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2023-7-25 22:49
  • 签到天数: 385 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-9-8 13:44:39 | 显示全部楼层
    感谢分享~
    相当详细!!!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-2-4 11:43:42 | 显示全部楼层
    感谢分享。要是能把库需要修改的地方,弄个具体说明在哪里就好了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2015-7-14 10:15
  • 签到天数: 4 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2016-2-24 09:47:00 | 显示全部楼层
    很好的帖子,收藏
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-25 09:59 , Processed in 0.163006 second(s), 24 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.