Stm32入门——时钟部分讲解

Stm32入门——时钟部分讲解

相信很多刚开始玩板子的同学对时钟的认识都比较模糊,那么这篇博客我打算从自己的学习过程谈谈对时钟的理解。
什么时钟?
我的理解是,时钟其实是一种“能量”。当开发板通电以后会有电能,电能通过振荡电路或其他物理设备会转化成“时钟能”,你可以发挥一下想象,“时钟能”就像是人的心电图,只不过这张“心电图”很平稳,因为它永远只有高低电平依次升降。
其实,从某种意义上来说,时钟就是开发板的心脏,只有时钟开启了,板子才能工作,就比如说一个上升沿触发的D触发器,如果没有时钟,那D触发器如何正常工作?
频率是描述时钟的重要概念,时钟频率就是每秒钟产生的周期个数,而一个高低电平的组合正好是一个周期,通俗地讲时钟频率就是板子在一秒钟内可以重复做多少次相同的事情。有电脑的同学都知道电脑也有时钟频率,时钟频率越高,你电脑的速度就越快,这是一样的道理。

开发板时钟源选择
以stm32f1系列的开发板为例,开发板的时钟来源主要有四个
HSI (high speed internal) 高速内部时钟源
HSE (hign speed external) 高速外部时钟源
LSI (low speed internal) 低速内部时钟源
LSE (low speed external) 低速外部时钟源
高速低速很好理解,我用的板子HSI是8MHz而HSE是4~16MHz(一般也是用8MHz);内部和外部也好理解,内部HSI时钟信号由内部8MHz的RC振荡器产生,但精度比较差所以不太用它,外部HSE可由外部晶体/陶瓷谐振器产生,精度较好,所以一般都用HSI作为系统时钟的来源。

时钟的倍频、分频
时钟的倍频就是将时钟频率放大,比如原来是36MHz,2倍频后可变为72MHz;分频就是频率缩小,比如72MHz的时钟,2分频后可变为36MHz。

系统时钟SYSCLK理解
这里先贴一张图
Stm32入门——时钟部分讲解
这是时钟树的部分截图,看这张图时可以把“SYSTICK”作为分界线,分界线左边是“时钟源”的选择,右边为“时钟的外设应用”。
先说时钟源选择,图中竖着放置的等腰梯形是一个“选择器”,“选择器”左边是多个选项,右边是一个输出;PLL是个倍频器,而AHB、APB1、APB2是分频器(具体的分频和倍频系数要看芯片的手册),由图中可以看出SYSTICK时钟源选择可以是HSI、HSE、HSI/2通过PLL倍频、HSE/2通过PLL倍频、或是HSE直接通过PLL倍频(常用8MHz的HSE直接通过9倍频得到72MHz的SYSTICK)。
再说说外设时钟应用,开发板上集成了很多外设,比如GPIO端口、定时器、串口等等,为了达到减少耗能的目的,这些外设只有在使用的时候才开启它的时钟,这就跟水龙头一样,你用水的时候才开着,不用时就把它关上。
外设的种类有很多,它们对时钟频率的需求也不尽相同,因此不同速度的外设会“挂”在不同的时钟上,比如APB1上挂了定时器2,APB2上则挂了GPIO端口。这就好比家里的卫生间和厨房都有水龙头,但用水的目的不同。
要想弄清楚具体哪个外设挂在哪个时钟上,还要参考手册才行。还要说明的是不同的外设对时钟的要求不同,因此很有可能会发生多次分频来获得合适的时钟。

SYSTICK初始化
SYSTICK初始化,主要完成的就是时钟源选择。

void Stm32_Clock_Init(u8 PLL)
{
	unsigned char temp=0;   
	MYRCC_DeInit();		  //复位并配置向量表
 	RCC->CR|=0x00010000;  //外部高速时钟使能HSEON
	while(!(RCC->CR>>17));//等待外部时钟就绪
	RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
	PLL-=2;				  //抵消2个单位(因为是从2开始的,设置0就是2)
	RCC->CFGR|=PLL<<18;   //设置PLL值 2~16
	RCC->CFGR|=1<<16;	  //PLLSRC ON 
	FLASH->ACR|=0x32;	  //FLASH 2个延时周期
	RCC->CR|=0x01000000;  //PLLON
	while(!(RCC->CR>>25));//等待PLL锁定
	RCC->CFGR|=0x00000002;//PLL作为系统时钟	 
	while(temp!=0x02)     //等待PLL作为系统时钟设置成功
	{   
		temp=RCC->CFGR>>2;
		temp&=0x03;
	}    
}		    

RCC->CFGR|=0x00000002;//PLL作为系统时钟
这是选择时钟,而传入的参数u8 PLL是倍频系数。
RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
这是给APB1、APB2、AHB设置分频系数。
更具体的操作步骤请参考手册,这里不再赘述。

虽然看手册比较麻烦而且通常看不太懂,但养成阅读手册的习惯是嵌入式开发人员的基本素质。