文章标题
来源:互联网 发布: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);//设置系统时钟}
- 文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题 文章标题 文章标题 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- 文章标题
- Hibernate持久化对象的状态
- linux下如何用GDB调试c++程序
- 【VB.NET】实现动态托盘图标
- Android View体系(一)视图坐标系
- Android开发环境搭建(二)——基于Eclipse的开发环境搭建
- 文章标题
- Android JSON解析
- AngularJs——双向数据绑定示例
- xnl 之 处理指令
- one class SVM
- Android中用GifView显示Gif动画
- Android使用MAT分析内存泄露
- LeetCode 292. Nim Game
- ElasticSearch--AdMaster使用案例