学习系统时钟以前先问你们一个问题? 这是一个跑马灯的程序,为何咱们没有在主函数中配置系统时钟,却能够正常的执行流水灯代码呢? 我想大多数人都会说,已经配置了系统时钟,不须要在主函数中调用了。若是你回答不上来或者不清楚系统时钟是怎样配置的就好好看下文了。至此引出系统时钟的概念。安全
全部数字计算机系统都是由某种形式的震荡时钟电路驱动的。这种电路被称为系统的“脉搏”,是系统正确运行的关键。若是振荡器失灵,系统将彻底没法运行,若是振荡器运行不规律,系统执行的全部时间有关的计算都会有偏差。 全部微控制器的启动流程都不通用。因为硬件的复杂性,必须运行一段由厂家定义的短小的“复位程序”来使硬件处于一种正确的状态,而后再开始执行用户程序。运行这个复位程序须要时间而且要求微控制器的振荡器已经运行。 当系统由可靠的电源供电时,一旦通电,电源迅速地达到额定输出电压,一旦关电,电源迅速地降低到 0V,而且在接通的时候,电压不会下降。这时可以可靠地使用基于一个电容和一个电阻的低成本硬件复位。这种形式的复位电路称为阻容复位。若是电源不够可靠,而涉及安全性,这种简单的阻容解决方案就不合适了。markdown
我这里以STM32F429为例,其余的芯片的原理都是同样的。函数
时钟树单纯讲理论的话会比较枯燥,若是选取一条主线,并辅以代码,先主后次讲解的话会很容易,并且记忆还更深入。咱们这里选取库函数时钟系统时钟函数:SetSysClock();这个函数在system_stm32f4xx.c中,以这个函数的编写流程来说解时钟树,这个函数也是咱们用库的时候默认的系统时钟设置函数。该函数的功能是利用HSE把时钟设置为: 系统时钟 SYSCLK =PLLCLK= 168MHz AHB总线时钟HCLK = SYSCLK=168MHz APB1外设时钟PCLK1 = HCLK /4=42MHz APB2外设时钟PCLK2 = HCLK /2=84MHz 有人会问F4不是主频180MHZ,APB1=90MHZ,APB2=180MHZ吗?确实你看到的大部分程序中F4都是这样配置的,可是并不表明必须这样配置,你能够想配置多少就是多少。只要不超多系统最高时钟的限制180MHZ。固然又会有人说了,不是能够超频吗?是能够超频可是99%都不会超频。性能
下面咱们来看时钟树: 在 STM32F429 中,有 5 个最重要的时钟源,按照上图的顺序为LSI、LSE、 HSE、HSL、PLL。H开头的是高速时钟、L开头的是低速时钟。其中 PLL分为三个时钟源,分别为主 PLL 和 I2S 部分专用 PLLI2S 和 SAI 部分专用 PLLSAI。其中 HSE 和 LSE 是外部时钟源就是从外部经过接晶振的方式获取时钟源(就是须要外界晶振),其余的是内部时钟源(不须要外接晶振)。下面咱们看看 STM32F429 的这 5 个时钟源,咱们讲解顺序是按图中红圈标示的顺序:学习
主 PLL 时钟的时钟源要先通过一个分频系数为 M 的分频器,而后通过倍频系数为 N 的倍频器出来以后还须要通过一个分频系数为 P(第一个输出 PLLP)或者 Q(第二个输出 PLLQ)的分频器分频以后,最后才生成最终的主 PLL 时钟。例如咱们的外部晶振选择 8MHz。同时咱们设置相应的分频器 M=8,倍频器倍频系数 N=336,分频器分频系数 P=2,那么主 PLL 生成的第一个输出高速时钟 PLLP 为:8MHZ/8*336/2=168ui
PLL=8MHz * N/ (M*P)=8MHz* 336 /(8*2) = 168MHz
复制代码
若是咱们选择HSE为PLL时钟源,同时SYSCLK时钟源为PLL,那么SYSCLK时钟为 168MHz。 看下面的程序也是这样的,说明计算无误。
spa
助记:由于2大于1,随因此APB2外设时钟也必定要大于APB2外设时钟。code
具体的实现请看下图: 单纯地讲解系统的时钟框图的,请看具体的数据手册,咱们这里只是简单的介绍这个系统时钟是怎么来的。好比告诉你,我如今的外接晶振是25M。可是我想要配置成系统时钟是180MHZ的你会吗?你会本身去配置吗? 看到这里我想你已经会配置了。好比我这设置
PLL_M=25,PLL_N=360,PLL_P=2
。那么个人系统时钟SYSCLK就是:orm
PLL=25MHz * N/ (M*P)=25MHz* 330 /(25*2) = 180MHz。
复制代码
若是咱们选择HSE为PLL时钟源,同时SYSCLK时钟源为PLL,那么SYSCLK时钟为 180MHz。图片
至此咱们已经大概的了解到了系统时钟是怎么一回事。如今咱们来分析具体的代码。否则值分析没代码,学起来效果很差。 还记得我在前面我提到的问题吗? 其实在按下单片机上面的复位按键以后。根据我么上一篇文章说的。系统会这些首先执行启动代码的里面的程序。 咱们打开
startup_stm32f429_439xx.s
文件。固然我这里以F4为例,其余的也都是同样的。会看到在系统复位时候在执行main函数
以前先执行了SystemInit
函数。那咱们如今看看SystemInit
函数中都有啥。鼠标放在SystemInit函数上面右键选择Go To Defintion of SystemInit
就会跳转到
system_stm32f4xx.c
文件中的SystemInit函数上来了。下面来一行一行分析: 第592行:
RCC->CR |= (uint32_t)0x00000001;
配置RCC寄存器的时钟控制RCC_CR寄存器第0位为1。打开HSI振荡器。 第595行:
RCC->CFGR = 0x00000000;
复位RCC寄存器的时钟配置CFGR寄存器,全为0。 第598行:
RCC->CR &= (uint32_t)0xFEF6FFFF;;
复位RCC寄存器的时钟控制CR寄存器的HSEON、CSSON、PLLON为0。 第601行:
RCC->PLLCFGR = 0x24003010;
复位RCC寄存器的配置PLLCFGR寄存器。具体的操做能够看下面对应的寄存器位值。 第604行:
RCC->CR &= (uint32_t)0xFFFBFFFF;
复位RCC寄存器的CR寄存器。 第604行:RCC->CIR = 0x00000000;
失能RCC寄存器的CIR寄存器,关闭全部中断。这两行就不一一列举了。 第615行:SetSysClock()
这个函数主要是配置AHB、AHB一、AHB2的时钟频率。 到这里系统时钟就所有配置完成了。在这两个函数中有不少的宏定义,在看代码的时候必定要注意是操做了哪一位,在对应为去找STM32fx的中文参考手册就容易理解多了。
要会看宏定义: #define RCC_CR_HSEON ((uint32_t)0x00010000) 0x0001 0000。 就是把RCC寄存器的CR寄存器的HSEON置位1。根据 0x0001 0000能够知道HSEON处于CR寄存器的第16位,这一点很重要。
最后来一个总结,在咱们按下开发板上面的复位按键以后,系统从启动文件中先执行SystemInit函数,在SystemInit函数中配置了PLL锁相环的各个分频因子,获得了系统时钟。在SystemInit函数中又调用了SetSysClock()函数,来配置AHB、AHB一、AHB2的时钟频率。
如今咱们系统时钟配置你会了吗?须要注意的是,咱们写在程序的时候通常不须要配置时钟,由于咱们通常用的是被人写好的工程模板,直接拿来用就能够了。可是仍是须要了解,时钟树的知识比较难以理解,相信你们看上面的内容都会配置了吧!