对单片机中时钟的理解:

2019-04-15 17:09发布

1.概述 简单的说,时钟是单片机的脉搏,是单片机的驱动源,使用任何一个外设都必须打开相应的时钟。这样的好处是,如果不使用一个外设的时候,就把它的时钟关掉,从而可以降低系统的功耗,达到节能,实现低功耗的效果。每个时钟tick,系统都会处理一步数据,这样才能让工作不出现紊乱。 2.原理 首先,任何外设都需要时钟,51单片机,stm32,430等等,因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。
51单片机不需要配置时钟,是因为一个时钟开了之后所有的功能都可以用了,而这个时钟是默认开启的,比如有一个水库,水库有很多个门,这些门默认是开启的,所以每个门都会出水,我们需要哪个门的水的时候可以直接用,但是也存在一个问题,其他没用到的门也在出水,即也在耗能。这里水库可以认为是能源,门可以认为是每个外设的使用状态,时钟可以认为是门的开关。stm32之所以是低功耗,他将所有的门都默认设置为disable,在你需要用哪个门的时候,开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,其他的没用到的可以还是disable,这样耗能就会减少。
在51单片机中一个时钟把所有的都包了,而stm32的时钟是有分工的,并且每类时钟的频率不一样,因为没必要所有的时钟都是最高频率,只要够用就行,好比一个门出来水流大小,我只要洗脸,但是出来的是和洪水一样涌出来的水,那就gg了,消耗能源也多,所以不同的时钟也会有频率差别,或者在配置的时候可以配置时钟分频。
拓展:为何要先配置时钟,再配置GPIO(功能模块) 所有寄存器都需要时钟才能配置,寄存器是由D触发器组成的,只有送来了时钟,触发器才能被改写值。
任何MCU的任何外设都需要有时钟,8051也是如此;STM32为了让用户更好地掌握功耗,对每个外设的时钟都设置了开关,让用户可以精确地控制,关闭不需要的设备,达到节省供电的目的。
51单片机不用配置IO时钟,只是因为默认使用同一个时钟,这样是方便,但是这样的话功耗就降低不了。
例如,某个功能不需要,但是它还是一直运行。
stm32需要配置时钟,就可以把不需要那些功能的功耗去掉。
当你想关闭某个IO的时候,关闭它相对应的时钟使能就是了,不过在51里面,在使用IO的时候是没有设置IO的时钟的,还有在STM32中,有外部和内部时钟之分,关于时钟等好好研究
ARM的芯片都是这样,外设通常都是给了时钟后,才能设置它的寄存器(即才能使用这个外设)。STM32、LPC1XXX等等都是这样。
这么做的目的是为了省电,使用了所谓时钟门控的技术。
这也属于电路里同步电路的范畴:同步电路总是需要1个时钟。
3.分类 时钟发生器用于产生时钟,并提供给CPU和外部硬件设备。 有如下三种系统时钟。 (1)主系统时钟 ①通过连接一个振荡器到X1和X2,该振荡电路产生fx=1到20MHZ的时钟; ②使用内部高速振荡器产生fRH=8MHZ的时钟。 (2)副系统时钟 ①通过在XT1和XT2之间连接一个fXT=32.768KHZ的振荡器; ②通过XT2引脚提供一个外部副系统时钟fexclks=32.768KHZ。 (3)内部低速振荡时钟(看门狗定时器时钟) ①内部低速振荡器,以fRL=240KHZ的时钟振荡。该时钟不能作为CPU时钟。 4.配置 一、在STM32中,有五个时钟源,为HSIHSELSILSEPLL HSI是高速内部时钟,RC振荡器,频率为8MHz。 HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。 LSI是低速内部时钟,RC振荡器,频率为40kHz。 LSE是低速外部时钟,接频率为32.768kHz的石英晶体。 PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。 二、在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法:如果使用内部RC振荡器而不使用外部晶振,请按照下面方法处理: ①对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT应悬空。
②对于少于100脚的产品,有2种接法:第1种:OSC_IN和OSC_OUT分别通过10K电阻接地。此方法可提高EMC性能;第2种:分别重映射OSC_IN和OSC_OUT至PD0和PD1,再配置PD0和PD1为推挽输出并输出'0'。此方法可以减小功耗并(相对上面)节省2个外部电阻。
三、用HSE时钟,程序设置时钟参数流程
01、将RCC寄存器重新设置为默认值   RCC_DeInit;
02、打开外部高速时钟晶振HSE    RCC_HSEConfig(RCC_HSE_ON);
03、等待外部高速时钟晶振工作    HSEStartUpStatus = RCC_WaitForHSEStartUp();
04、设置AHB时钟         RCC_HCLKConfig;
05、设置高速AHB时钟     RCC_PCLK2Config;
06、设置低速速AHB时钟   RCC_PCLK1Config;
07、设置PLL              RCC_PLLConfig;
08、打开PLL              RCC_PLLCmd(ENABLE);
09、等待PLL工作   while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
10、设置系统时钟        RCC_SYSCLKConfig;
11、判断是否PLL是系统时钟     while(RCC_GetSYSCLKSource() != 0x08)
12、打开要使用的外设时钟    RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()
四、下面是STM32软件固件库的程序中对RCC的配置函数(使用外部8MHz晶振) /******************************************************************************* * Function Name  : RCC_Configuration  * Description    :  RCC配置(使用外部8MHz晶振) * Input            : 无 * Output         : 无 * Return         : 无 *******************************************************************************/ void RCC_Configuration(void) {   /*将外设RCC寄存器重设为缺省值*/   RCC_DeInit();   /*设置外部高速晶振(HSE)*/   RCC_HSEConfig(RCC_HSE_ON);   //RCC_HSE_ON——HSE晶振打开(ON)   /*等待HSE起振*/   HSEStartUpStatus = RCC_WaitForHSEStartUp();   if(HSEStartUpStatus == SUCCESS)        //SUCCESS:HSE晶振稳定且就绪   {     /*设置AHB时钟(HCLK)*/      RCC_HCLKConfig(RCC_SYSCLK_Div1);  //RCC_SYSCLK_Div1——AHB时钟= 系统时钟     /* 设置高速AHB时钟(PCLK2)*/      RCC_PCLK2Config(RCC_HCLK_Div1);   //RCC_HCLK_Div1——APB2时钟= HCLK     /*设置低速AHB时钟(PCLK1)*/     RCC_PCLK1Config(RCC_HCLK_Div2);   //RCC_HCLK_Div2——APB1时钟= HCLK / 2     /*设置FLASH存储器延时时钟周期数*/     FLASH_SetLatency(FLASH_Latency_2);    //FLASH_Latency_2  2延时周期  /*选择FLASH预取指缓存的模式*/       FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);       // 预取指缓存使能     /*设置PLL时钟源及倍频系数*/      RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);      // PLL的输入时钟= HSE时钟频率;RCC_PLLMul_9——PLL输入时钟x 9   /*使能PLL */     RCC_PLLCmd(ENABLE);     /*检查指定的RCC标志位(PLL准备好标志)设置与否*/        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)              {        }       /*设置系统时钟(SYSCLK)*/      RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  //RCC_SYSCLKSource_PLLCLK——选择PLL作为系统时钟       /* PLL返回用作系统时钟的时钟源*/     while(RCC_GetSYSCLKSource() != 0x08)        //0x08:PLL作为系统时钟        {         }  /*使能或者失能APB2外设时钟*/       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |  RCC_APB2Periph_GPIOC , ENABLE);  //RCC_APB2Periph_GPIOA    GPIOA时钟 //RCC_APB2Periph_GPIOB    GPIOB时钟 //RCC_APB2Periph_GPIOC    GPIOC时钟 //RCC_APB2Periph_GPIOD    GPIOD时钟 } 五、时钟频率 STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M。目前TI的M3系列芯片最高频率可以达到80M。 在stm32固件库3.0中对时钟频率的选择进行了大大的简化,原先的一大堆操作都在后台进行。系统给出的函数为SystemInit()。但在调用前还需要进行一些宏定义的设置,具体的设置在system_stm32f10x.c文件中。 文件开头就有一个这样的定义: 
//#define SYSCLK_FREQ_HSE    HSE_Value 
//#define SYSCLK_FREQ_20MHz 20000000 
//#define SYSCLK_FREQ_36MHz 36000000 
//#define SYSCLK_FREQ_48MHz 48000000 
//#define SYSCLK_FREQ_56MHz 56000000 
#define SYSCLK_FREQ_72MHz 72000000
ST 官方推荐的外接晶振是 8M,所以库函数的设置都是假定你的硬件已经接了 8M 晶振来运算的.以上东西就是默认晶振 8M 的时候,推荐的 CPU 频率选择.在这里选择了:
#define SYSCLK_FREQ_72MHz 72000000 
也就是103系列能跑到的最大值72M
然后这个 C文件继续往下看 
#elif defined SYSCLK_FREQ_72MHz 
const uint32_t SystemFrequency         = SYSCLK_FREQ_72MHz;    
const uint32_t SystemFrequency_SysClk = SYSCLK_FREQ_72MHz;    
const uint32_t SystemFrequency_AHBClk = SYSCLK_FREQ_72MHz;    
const uint32_t SystemFrequency_APB1Clk = (SYSCLK_FREQ_72MHz/2);
const uint32_t SystemFrequency_APB2Clk = SYSCLK_FREQ_72MHz;
这就是在定义了CPU跑72M的时候,各个系统的速度了.他们分别是:硬件频率,系统时钟,AHB总线频率,APB1总线频率,APB2总线频率.再往下看,看到这个了: 
#elif defined SYSCLK_FREQ_72MHz 
static void SetSysClockTo72(void);
这就是定义 72M 的时候,设置时钟的函数.这个函数被 SetSysClock ()函数调用,而
SetSysClock ()函数则是被 SystemInit()函数调用.最后 SystemInit()函数,就是被你调用的了
所以设置系统时钟的流程就是: 
首先用户程序调用 SystemInit()函数,这是一个库函数,然后 SystemInit()函数里面,进行了一些寄存器必要的初始化后,就调用 SetSysClock()函数. SetSysClock()函数根据那个#define SYSCLK_FREQ_72MHz 72000000 的宏定义,知道了要调用SetSysClockTo72()这个函数,于是,就一堆麻烦而复杂的设置
~!@#$%^然后,CPU跑起来了,而且速度是 72M. 虽然说的有点累赘,但大家只需要知道,用户要设置频率,程序中就做的就两个事情: 第一个: system_stm32f10x.c 中 #define SYSCLK_FREQ_72MHz 72000000  第二个:调用SystemInit()