文章标题

来源:互联网 发布:python入门要多久 编辑:程序博客网 时间:2024/05/17 22:04
又过了一天,寒假临近尾声了。话说STM32的时钟系统果然复杂,研究了一天才大概了解。发现当启动单片机不做任何设置时,默认的SYSTEMCLOCK是等于HSI的,这也难怪延时不准确(延时间被拉长了,显然HSI的频率比延时函数默认的频率低很多)。因为有纷繁复杂的寄存器名称,每个寄存器的32个位的作用……所以有些地方还是没玩透的。大致总结一下STM32的时钟系统。

图片
(字有点小,见谅。大概能看清楚就行了哈。高清图请翻技术文档)
首先有两个外部振荡器作为时钟。OSC32提供一个LSE(低速外部时钟),频率为32.768kHz;OSC提供一个4~26MHz的HSE(高速外部时钟) ,通常用8MHz晶振,也就是HSE为8MHz。然后LSE可以作为RTC(实时时钟)的时钟,当然在没有LSE的情况下,LSI(低速内部时钟)也可以作为时钟,但是其频率是32kHz,且是RC振荡器产生的,所以精度不高(即使能通过程序校准)。LSI也可以为IWDG(独立看门狗)提供时钟。RTC的时钟来源可以有三个,除了上述的LSI和LSE,还可以是HSE分频得到(2到31分频,得到32kHz时钟)。
HSE经过锁相环,得到PLL时钟。其计算公式是f/M*N/P,其中f代表输入锁相环的频率,可以是HSI也可以是HSE,通常用HSE。P可以用Q或N替代,从而给不同的外设提供时钟。当然这些计算要通过配置相应寄存器实现。我用的是STM32F407VGT6,为了达到最高速运行(168MHz),只需配置RCC_PLLCFGR寄存器的相应位来设置系数的值,通常可以令M=8,N=336,P=2,这样分频恰好得到168MHz时钟。PLL可以提供给系统时钟SYSCLK,当然SYSCLK的来源也可以是HSI或HSE,配置寄存器来选择。HSE还可以分频得到PLL i2SCLK,专门给声卡提供时钟。
由PLL得到SYSCLK后,经过AHB和APBx的预分频,得到预分频时钟,然后提供给各GPIO等外设。至于PHY以太网、USB2.0 PHY,以后再研究吧。
最后附上根据这些时钟和技术文档对寄存器的描述写的代码(参考了固件库的程序啦),时钟初始化和设置的函数。

#include "stm32f4xx.h"u8 SysClock_Set(u32 plln,u32 pllm,u32 pllp,u32 pllq){    u16 retry  = 0;    u8  status = 1;    RCC->CR |= RCC_CR_HSEON; //使能HSE    while( ((RCC->CR & RCC_CR_HSERDY) ==0) && (retry<0x1FFF) ) //检查HSERDY位是否为1    retry++;//重新检查    if(retry >= 0x1FFF)//若HSERDY始终为0,即使能HSE失败    {    status=0;    }    if(status == 1) //若HSE使能成功    {        RCC->APB1ENR |= RCC_APB1ENR_PWREN;//复位电源接口        PWR->CR |= PWR_CR_VOS_0; //VOS位置1       15位保留位更改会怎么样呢?似乎没有什么影响。        RCC->CFGR |= (RCC_CFGR_HPRE_DIV1//AHB预分频器 系统时钟不分频                            |RCC_CFGR_PPRE1_DIV4//AHB低速预分频器 AHB时钟4分频                            |RCC_CFGR_PPRE2_DIV2 //AHB高速预分频器 AHB时钟2分频                               );        RCC->CR &= ~RCC_CR_PLLON;//禁能PLL        RCC->PLLCFGR = ( pllm                                |(plln<<6)                                |(((pllp>>1)-1)<<16)                                |(pllq<<24)                                |RCC_PLLCFGR_PLLSRC_HSE  //选择HSE时钟作为PLL和PLLI2S时钟输入                                );        RCC->CR |= RCC_CR_PLLON;//使能PLL        while( (RCC->CR&RCC_CR_PLLRDY) == 0 );  //检查PLLRDY位,直到PLL时钟就绪        FLASH->ACR |= FLASH_ACR_PRFTEN;//使能预取        FLASH->ACR |= FLASH_ACR_ICEN;//使能指令缓存        FLASH->ACR |= FLASH_ACR_DCEN;//使能数据缓存        FLASH->ACR |= FLASH_ACR_LATENCY_5WS;//5个CPU等待周期        RCC->CFGR  &= ~RCC_CFGR_SW;//复位系统时钟选择        RCC->CFGR  |=  RCC_CFGR_SW_1;//选择PLL作为系统时钟         while((RCC->CFGR&RCC_CFGR_SWS)!= RCC_CFGR_SWS_PLL);  //等待PLL时钟就绪     }     else    {        /*若HSE使能失败,程序员可以在此处添加代码,        处理错误*/    }    return status;    }    void SysClock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)    {    RCC->CR   |= RCC_CR_HSION;//使能HSI    RCC->CFGR  =0x00000000;//初始化所有时钟的分频    RCC->CR   &= ~(RCC_CR_HSEON//禁能HSE、CSS、PLL                         |RCC_CR_CSSON                          |RCC_CR_PLLON                         );    RCC->PLLCFGR = 0x24003010;//初始化PLLCFGR    RCC->CR  &= ~RCC_CR_HSEBYP;//禁能HSEBYP    RCC->CIR  = 0x00000000;//初始化CIR    SysClock_Set(plln,pllm,pllp,pllq);//设置系统时钟} 
0 0
原创粉丝点击