STM32F10x芯片时钟控制总结

发布者:GoldenSunrise最新更新时间:2016-08-03 来源: eefocus关键字:STM32F10x  时钟控制 手机看文章 扫描二维码
随时随地手机看文章

1、介绍

       STM32F10x芯片的时钟控制主要包括以下几个方面知识:时钟源的选择(HSE、HIS、PLL)、系统时钟频率的配置、总线(AHB、APB2、APB1)时钟的配置、总线(AHB、APB2、APB1)设备时钟的使能/除能、总线(AHB、APB2、APB1)设备的复位。

2、系统时钟框图

STM32F10x可以用三种不同的时钟源来驱动系统时钟(SYSCLK):HSI振荡器时钟;HSE外部时钟和PLL时钟。他们之间的关系如附件所示(时钟树)。

从时钟树中可以看出一下几点:

l         系统时钟的来源可以是HSI振荡器时钟、PLL时钟、或者HSE时钟;且系统总线时钟最大值为72MHz,AHB和APB2总线最大频率也是72MHz,APB1总线最大允许频率是36MHz;而Cortex-M3核的自由运行时钟是FCLK(来源于AHB总线);

l         stm32f10x芯片总共有四个时钟源:HSE、LSE(外部时钟信号);HIS、LSI(内部时钟信号),芯片内的其他所有时钟都是通过如上四个时钟源分频得来;

l         RTC的时钟来源可以是HSE外部时钟128分频之后的时钟、或者LSE外部时钟(32.768kHz)或者内部LSI振荡器时钟;

l         IWDG的时钟来源必须是内部LSI振荡器时钟;

l         MCO引脚的时钟输出源的来源有:PLL时钟的2分频、内部HIS时钟、外部HSE时钟以及系统时钟。

l         PLL时钟的来源可以是HIS振荡器时钟或者HSE外部提供的时钟;

l         USB外设是直接使用PLL输出时钟(如果使用USB外设,HSE和PLL时钟都必须使能,且系统时钟必须是48MHz或者72MHz);AHB总线的时钟输入源的是系统时钟;APB1和APB2的时钟来源是AHB;

l         始终安全系统(CSS)必须由HSE提供时钟源;若CSS激活且HSE时钟出现故障,则引发CSS中断,同时产生NMI(NMI中断是不可屏蔽的),NMI将被不断执行,知道CSS中断挂起位被清除;

l         定时器时钟要么等于总线时钟,要么等于总线时钟频率的两倍,这取决于总线分频系数的值是否为1;

l         当HIS被用于作为PLL时钟输入时,系统时钟能得到的最大频率是64MHz;

l         Cortex-M3内核的自由运行时间是FCLK。

3、时钟寄存器描述

l         时钟控制寄存器:RCC_CR

l         时钟配置寄存器:RCC_CFGR

l         时钟中断寄存器:RCC_CIR

l         APB2外设复位寄存器:RCC_APB2RSTR

l         APB1外设复位寄存器:RCC_APB1RSTR

l         AHB外设时钟使能寄存器:RCC_AHBENR

l         APB2外设时钟使能寄存器:RCC_APB2ENR

l         APB1外设时钟使能寄存器:RCC_APB1ENR

l         备份域控制寄存器:RCC_BDCR

l         控制/状态寄存器:RCC_CSR

 

 

4、时钟控制主要按照以下五步进行控制

l         系统复位后,HSI振荡器被选为系统时钟;

l         调用RCC_DeInit()函数将外设RCC寄存器重置为缺省值;

l         选择系统时钟:

?         若选择HSE做系统时钟:先调用RCC_HSEConfig()使能HSE,然后调用RCC_WaitForHSEStartUp()函数等待HSE起震,最后调用RCC_GetFlagStatus()函数获取HSE晶振状态,查看HIE晶振是否就绪;;

?         若选择HSI做系统时钟:首先调用RCC_AdjustHSICalibrationValue()函数调整内部高速晶振校准值(也可以不用,使用系统预留值),然后调用RCC_HSICmd()函数使能HSI,最后调用RCC_GetFlagStatus()函数获取HSI晶振状态,查看HIS晶振是否就绪;

?         若要使用PLL做系统时钟,如前面两步将HSE和HIS设定好之后,调用RCC_PLLConig()选择PLL时钟源并设定倍频系数,最后调用RCC_PLLCmd()使能PLL,最后调用RCC_GetFlagStatus()函数获取PLL晶振状态,查看PLL是否就绪;。

l         最后,在以上时钟配置就绪之后,调用RCC_SYSCLKConfig()函数选择系统时钟输入源:HSE/HIS/PLL。

至此,系统时钟设定完成,可以调用RCC_GetSYSCLKSource()函数来获取当前系统时钟是使用的哪个时钟(检测设置是否成功):0x010:HIS;x040:HSE;x08:PLL。

l         然后是总线时钟设置:设置AHB总线时钟:调用RCC_HCLKConfig()函数;设置APB1总线时钟:调用RCC_PCLK1Config()函数;设置APB2总线时钟:调用RCC_PCLK2Config()函数。其中AHB总线时钟来源于SYSCLK总线时钟,APB1和APB2总线时钟来源于AHB总线时钟。注意:这三个时钟的设置可以在系统时钟、PLL、HSE、HIS启动之前设置,也可以在他们之后设置,但习惯在PLL配置之前。

l         最后是根据应用需要配置各总线上的外围设备,启动/停用外围设备的函数有:RCC_AHBPeriphClockCmd();RCC_APB2PeriphClockCmd();RCC_APB1PeriphClockCmd();复位总线上的设备函数:RCC_APB2PeriphResetCmd();RCC_APB1PeriphResetCmd();具体可以查看RCC固件库。

注意:使能外设时钟的函数必须在调用外设初始化函数XXX_Init()函数之前,否则可能会导致对应外设初始化失败,编译器却不会因此报错。

5、时钟控制例子

void SetSysClockToHSE(void)

{

     ErrorStatus HSEStartUpStatus;

     RCC_DeInit();

     RCC_HSEConfig(RCC_HSE_ON);

     HSEStartUpStatus = RCC_WaitForHSEStartUp();

     if(SUCCESS == HSEStartUpStatus)

     {

         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

 

         FLASH_SetLatency(FLASH_Latency_0);  

         RCC_HCLKConfig(RCC_SYSCLK_Div1);

         RCC_PCLK2Config(RCC_HCLK_Div1);

         RCC_PCLK1Config(RCC_HCLK_Div1);

         RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);

         while(0x04 != RCC_GetSYSCLKSource())

         {

         }

     }

     else

     {

     }

}

void SetSysClockTo20(void)

{

     ErrorStatus HSEStartUpStatus;

     RCC_DeInit();

     RCC_HSEConfig(RCC_HSE_ON);

     HSEStartUpStatus = RCC_WaitForHSEStartUp();

     if(SUCCESS == HSEStartUpStatus)

     {

         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

         FLASH_SetLatency(FLASH_Latency_0);

         RCC_HCLKConfig(RCC_SYSCLK_Div1);

         RCC_PCLK2Config(RCC_HCLK_Div1);

         RCC_PCLK1Config(RCC_HCLK_Div1);

         RCC_PLLConfig(RCC_PLLSource_HSE_Div2,RCC_PLLMul_5);

         RCC_PLLCmd(ENABLE);

         while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

         {

         }

         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

         while(0x08 != RCC_GetSYSCLKSource())

         {

         }

     }

     else

     {

     }

}

void SetSysClockTo36(void)

{

     ErrorStatus HSEStartUpStatus;   

     RCC_DeInit();

     RCC_HSEConfig(RCC_HSE_ON);

     HSEStartUpStatus = RCC_WaitForHSEStartUp();

     if(SUCCESS == HSEStartUpStatus)

     {

         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

         FLASH_SetLatency(FLASH_Latency_1);

         RCC_HCLKConfig(RCC_SYSCLK_Div1);

         RCC_PCLK2Config(RCC_HCLK_Div1);

         RCC_PCLK1Config(RCC_HCLK_Div1);

         RCC_PLLConfig(RCC_PLLSource_HSE_Div2,RCC_PLLMul_9);

         RCC_PLLCmd(ENABLE);

         while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

         {

         }

         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

         while(0x08 != RCC_GetSYSCLKSource())

         {

         }

     }

     else

     {

     }

}

void SetSysClockTo48(void)

{

     ErrorStatus HSEStartUpStatus;   

     RCC_DeInit();

     RCC_HSEConfig(RCC_HSE_ON);

     HSEStartUpStatus = RCC_WaitForHSEStartUp();

     if(SUCCESS == HSEStartUpStatus)

     {

         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

         FLASH_SetLatency(FLASH_Latency_1);

         RCC_HCLKConfig(RCC_SYSCLK_Div1);

         RCC_PCLK2Config(RCC_HCLK_Div1);

         RCC_PCLK1Config(RCC_HCLK_Div2);

         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_6);

         RCC_PLLCmd(ENABLE);

         while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

         {

         }

         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

         while(0x08 != RCC_GetSYSCLKSource())

         {

         }

     }

     else

     {

     }

}

void SetSysClockTo72(void)

{

     ErrorStatus HSEStartUpStatus;

     RCC_DeInit();

     RCC_HSEConfig(RCC_HSE_ON);

     HSEStartUpStatus = RCC_WaitForHSEStartUp();

     if(SUCCESS == HSEStartUpStatus)

     {

         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

         FLASH_SetLatency(FLASH_Latency_2);

         RCC_HCLKConfig(RCC_SYSCLK_Div1);

         RCC_PCLK2Config(RCC_HCLK_Div1);

         RCC_PCLK1Config(RCC_HCLK_Div2);

         RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);

         RCC_PLLCmd(ENABLE);

         while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY))

         {

         }

         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

         while(0x08 != RCC_GetSYSCLKSource())

         {

         }

     }

     else

     {

     }

}     

 

6、系统时钟安全系统CSS

       在实际应用中,经常出现由于晶体振荡器在运行中失去作用,造成微处理器的时钟源丢失,从而出现死机的现象,导致系统出错。为避免发声这种严重错误,STM32F10X系列芯片提供了一个时钟安全系统CCS机制。如下图:

 

       时钟安全系统被激活后,时钟监控器将实时监控外部高速振荡器;如果HSE时钟发生故障,外部振荡器自动被关闭,产生时钟安全中断,此中断被连接到Cortex-M3的NVIC中断;与此同时CSS将内部RC振荡器(HSI)切换为STM32的系统时钟源。

       注意:一旦CSS被激活,当HSE时钟出现故障产生CSS中断,同时自动产生NMI,NMI将不断执行,直到CSS中断挂起位被清除。因此在NMI的处理程序中,必须通过设置时钟中断寄存器RCC_CIR中的CSSC位(软件置1清除)来清除CSS中断。(其实RCC的其他各时钟源的就绪中断标志,也都需要通过软件置1来清除,只是CSS是NMI中断(不可屏蔽中断),其他中断需要设置相应位允许中断,并要在NVIC中打开RCC的中断通道)

7、系统时钟安全系统CSS应用

       启动时钟安全系统CCS:

RCC_ClockSecuritySystemCmd(ENABLE);

       编写NMI中断处理函数:

void NMI_Handler(void)

{

       if(RESET != RCC_GetITStatus(RCC_IT_CSS))

       {             /* HSE、PLL已经被禁止,但PLL设置未变 */

              ……/* 客户添加相应的系统保护代码处理 */

              /* 下面添加HSE恢复后的预设代码 */

              RCC_HSEConfig(RCC_HSE_ON);

              RCC_ITConfig(RCC_IT_HSERDY,ENABLE);

              RCC_ITConfig(RCC_IT_PLLRDY,ENABLE);

              RCC_ClearITPendingBit(RCC_IT_CSS);

       /* 至此一旦HSE时钟恢复,将发生HSERDY中断,在RCC中断处理程序中,可以将系统时钟设置到以前的状态 */

}

}

       编写RCC中断处理函数:

void RCC_IRQHandler(void)

{

if(RESET != RCC_GetITStatus(RCC_IT_HSERDY))

{

/* 添加相应处理 */

       RCC_ClearITPendingBit(RCC_IT_HSERDY);

}

if(RESET != RCC_GetITStatus(RCC_IT_PLLRDY))

{

/* 添加相应处理 */

       RCC_ClearITPendingBit(RCC_IT_PLLRDY);

}

}

8、输出芯片内部时钟

       STM32F10x芯片支持将内部时钟通过PA.8输出,但是必须注意GPIO输出管脚最大响应频率为50MHz,如果超过这个频率,输出的波形将会失真。应用实例如下:

首先配置端口PA.8

GPIO_InitTypeDef GPIO_InitStructure;     

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&GPIO_InitStructure);

然后调用函数RCC_MCOConfig(RCC_MCO)选择要输出的内部时钟:RCC_MCO可以是:

RCC_MCO_NoClock——无时钟输出

RCC_MCO_SYSCLK——输出系统时钟

RCC_MCO_HSI——输出内部高速8MHz的RC振荡器时钟

RCC_MCO_HSE——输出外部时钟信号

RCC_MCO_PLLCLK_Div2——输出PLL倍频后的二分频时钟

关键字:STM32F10x  时钟控制 引用地址:STM32F10x芯片时钟控制总结

上一篇:STM32F10x芯片GPIO/AFIO端口配置总结
下一篇:arm开发板实现U盘自动挂载和卸载

推荐阅读最新更新时间:2024-03-16 15:03

STM32F10x处理器在应用中编程的实现方法
引 言 Cortex-M3是首款基于ARMv7-M体系结构的32位标准处理器,RISC结构,包含高效灵活的Thumb-2指令集,拥有杰出的低功耗特性,为微控制器系统、汽车车身控制系统、工业控制系统和无线网络等嵌入式应用量身设计。ST公司推出基于Cortex-M3内核的STM32系列处理器,凭借其出众的性能、创新的外设、优越的功耗控制,得到众多工程师的青睐。 针对嵌入式应用的特点,STM32处理器提供功能强大的硬件调试接口——JTAG接口和串行接口,极大方便了设计,缩短了产品的开发周期。不仅如此,STM32处理器内嵌的闪存存储器允许在电路编程(In-Circuit Pro-gramming,ICP)和在应用中编程(In-Ap
[单片机]
<font color='red'>STM32F10x</font>处理器在应用中编程的实现方法
STM32F10x 学习笔记7独立看门狗IWDG 模块
按照STM32参考手册的说法: 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。 简单的说,STM32 中的IWDG 其核心就是一个12bits的向下递减的计数器,当计数器计数到零时就会触发系统复位。因此,要在每次计数到零之前将其复位到一个初始值。这个初始值就在重装载寄存器(IWDG_RLR)中存放,其默认值为0xFFF,我们也可以将其改为其他值。 计数器的时钟由LSI时钟经过分频后提供,预分频因子由预分频寄存器(IWDG
[单片机]
<font color='red'>STM32F10x</font> 学习笔记7独立看门狗IWDG 模块
STM32F10x 学习笔记之USART实现串口通讯 DMA 方式
STM32F10x 的USART 支持DMA 方式,并且在DMA完成后可以产生中断。这对于需要接收或发送大量数据的应用情景是很有帮助的。 在普通的8位或16位单片机中很少有包含DMA控制器的,所以可能许多嵌入式程序员对DMA方式并不熟悉。简单的说,直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。由于无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。 STM32F10x 上具有两个DMA控制器,共有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。
[单片机]
<font color='red'>STM32F10x</font> 学习笔记之USART实现串口通讯 DMA 方式
STM32F10X USART 中断接受+发送,测试无误
硬件平台:STM32F10X USART模块 + JLink+USB转TTL小板 软件平台:Keil 4 前一个程序只是作为下位机的MCU将数据发送给串口助手,也就是上位机,相当于单工通信,对于一个完整的通信来说只是完成了一半的功能。 这是一个完整的通信例程,作为下位机的单片机可以将数据发送给上位机,也可以检测上位机是否发了数据回来。中断方式检测,如果接收到数据,则将数据发送给上位机,相当于半双工模式。 其实与基础的51串口通信无实质区别,只是STM32相关寄存器配置稍微复杂些而已。相比于前一个发送程序,只是在中断检测和主函数里做了相应的修改而已,RCC模块、USART模块与GPIO模块配置基本没变。 二、发送程序例程 程序涉及
[单片机]
STM32F10X软加密方法及实例代码
  ///////////tst//STM32F10X软加密方法及实例代码//////////////////////////////   #define ID_ENCRYPT_EOR_RESULT_ADDRESS (0x0800F000)   #define ID_ENCRYPT_ADD_RESULT_ADDRESS (0x0800F004)   volatile uint32 gU32IdAdressVar;//这里一定要定义此变量,否则会被优化器优化掉   void Stm32F10xEncryptDemo(void)   {   uint32 *u32IdAddress;   uint32 u32EorRslt, u3
[单片机]
基于正点原子建立STM32F10x库函数版本的工程自己例程
步骤: 1、建立工程文件夹test 2、按下列复制文件夹到test工程文件夹: 1)复制例程的下列4个文件夹到工程目录: HARDWARE SYSTEM CORE STM32F10X_FWLIB 2)在工程目录建立一个user文件夹,并复制例程文件下列文件: 复制2文件:stm32f10x_it.c,stm32f10x_it.h 复制2文件:system_stm32f10x.c,system_stm32f10x.h 3、在user下新建工程test.uvproj 4、在user下新建代码文件test.c,内容如下: #include led.h #include delay.h #i
[单片机]
自学STM32F10x单片机需要注意的地方
由于之前一直使用PIC和51的芯片,从没接触过STM32系列的芯片,近期着手学习STM32F10x的芯片,通过学习后发现STM32的中断系统比较特殊(与PIC和51相比较........),有着不同的响应方式,看了几遍相关的手册和视频资料,还是有些稀里糊涂,通过实际写代码配置芯片后,逐渐有点眉目了,因此想记录下来,算是总结笔记。当然文章中有存在描述错误和不足的地方,还请大家指正。(可能有些地方理解的方式存在问题,望指教。) STM32采用了ARM Cortex_M3内核,而Cortex_M3内核具有256个中断源,其中内核自己的有16个中断源和外部设备的(最多)240个中断源,每个中断源都具有自己独立的中断优先级控制寄存器,该
[单片机]
自学<font color='red'>STM32F10x</font>单片机需要注意的地方
STM32F103的复位及时钟控制模块头文件
在处理器正常工作前,肯定要做一些初始化工作,其中最主要的一个就是初始化各种时钟。通过对STM32F103的复位及时钟控制(RCC)模块分析之后,自己写了一个RCC的头文件,这样使用起来更方便。头文件中首先定义了最基本的几个寄存器,然后再对每个寄存器中的域使用结构体做了定义,可以直接使用寄存器中的位来操作。注意设置系统时钟时要先设置好FLASH的等待周期,不然程序就可能会跑飞。 该测试工程是在以前的GPIO实验的基础上增加系统时钟初始化代码,设置系统时钟为72M。通过流水灯可以看到,比未配置系统时钟之前(8M)流水灯的速度快了很多。 从这里下载完整的测试工程: 系统时钟初始化的代码如下: //以下时钟配置为最高性能 void
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved