南昌網(wǎng)站建設(shè)設(shè)計廣告營銷案例分析
?前言:
?????????比起之前用過的三星的獵戶座4412芯片,STM32F4的系統(tǒng)時鐘可以說是小巫見大巫,首先我們需要清晰時鐘產(chǎn)生的原理:幾乎大多數(shù)的芯片都是由晶振產(chǎn)生一個比較低頻的頻率,然后通過若干個PLL得到單片機(jī)能承受的頻率(作為主頻),再通過其他手段將PLL出來的頻率降頻分給其他外設(shè)使用。一個時鐘樹一般先對復(fù)雜,我們先調(diào)出主頻(及編程好時鐘源、PLL倍頻這一部分)其他的之后再說,如此編程才不會太復(fù)雜。
????????實際上這個一般廠家會給一個配置文件的,但是如果要自己做些超頻之類的操作,就要徹底掌握時鐘樹的配置了,見人見智,追求技術(shù)的這個內(nèi)容是逃不掉的。
????????編程思路:1.PLL倍頻因子配置 2..PLL時鐘源激活和切換(上電后單片機(jī)會選擇一個默認(rèn)的時鐘源,可能是晶振也可能是內(nèi)部RC電路產(chǎn)生的頻率) 3.切換系統(tǒng)時鐘
時鐘資源概覽:
????????下面先看一下我們這個F4的系統(tǒng)時鐘資源,查看手冊可知系統(tǒng)復(fù)位后是默認(rèn)選擇HSI這個內(nèi)部RC電路產(chǎn)生的時鐘作為這個單片機(jī)的系統(tǒng)時鐘,但是我們要的是PLL產(chǎn)生的時鐘。
????????下面看手冊PLL配置的說明(可以把時鐘樹截圖出來作參考,不過主要編程還是靠手冊的文字描述),可知RCC_PLLCFGR 可以用來配置PLL (PLLI2S可以先不管,先搞出主頻再說),那就配置它吧。寄存器就不放出來了,自己看手冊,這里給出寄存器各個位的配置值及解釋
RCC_PLLCFGR寄存器配置
RCC->PLLCFGR =?0x24003010 ;//復(fù)位值
RCC->PLLCFGR = 0x7<<24 | 1<<22 | 0<<16 |?336<<6 |?0x8<<0 ;
RCC_CR寄存器配置

RCC->CR | =?1<<16;
u16 retry=0;//這個只是提供短暫延時的變量
while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循環(huán)后說明HSE ok了
if(retry==0X1FFF)status=1;?? ?//當(dāng)然如果超過了一定時間也會跳出,表示HSE無法就緒
2.打開PLL并等待其穩(wěn)定
RCC->CR|=1<<24; //打開主PLL
while((RCC->CR&(1<<25))==0);//等待PLL準(zhǔn)備好
使PLL倍頻出很高的頻率
有了上面的東西,我們就可以使PLL倍頻出很高的頻率了,結(jié)合上面兩個寄存器:
RCC->PLLCFGR = 0x7<<24 | 1<<22 |?0<<16 |?336<<6 |?0x8<<0 ;//配置PLL倍頻因子RCC->CR | =?1<<16;//激活HSE晶振
u16 retry=0;//這個只是提供短暫延時的變量
while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循環(huán)后說明HSE ok了
if(retry==0X1FFF)status=1;?else{//激活HSE完成了RCC->CR|=1<<24; //打開主PLLwhile((RCC->CR&(1<<25))==0);//PLL穩(wěn)定}
現(xiàn)在PLL理論上已經(jīng)有了晶振倍頻后的頻率了,下面切換PLL作為系統(tǒng)時鐘:
切換PLL作為系統(tǒng)時鐘
查看手冊,知道RCC_CFGR是管這個事的:再一波嘎嘎配置
bit[1:0]:0x2<<0? ? ? ? 切換PLL作為系統(tǒng)時鐘
bit[3:2]:這兩個位可以讀出是否切換完成,如果讀出來是0x2就是切換成PLL成功
bit[7:4]:這四個位是配置AHB分頻的,我記得是不分頻的,設(shè)為0000 即0x0<<4
bit[12:10]:?這三個位是配置APB1分頻的 設(shè)為4分頻,即0x5<<10
bit[15:13]:這三個位是配置APB2分頻的 設(shè)為2分頻,即0x4<<13
bit[20:16]:這五個位是配置RTC分頻的 可以先隨便設(shè)一個設(shè)為HSE/2,即0x2<<16
其他不用管
即
?
RCC_CFGR = 0;//清零RCC_CFGR =?0x2<<16 |?0x4<<13 | 0x5<<10 | 0x0<<4 |?0x2<<0 ;//切換PLL為系統(tǒng)時鐘并且設(shè)置其他分頻while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作為系統(tǒng)時鐘成功.?
這樣,綜合上面所有的代碼就是:
u16 retry=0;//這個只是提供短暫延時的變量u8 status=0; //按照上面的分析思路,編程流程就是://1.配置PLL倍頻因子RCC->PLLCFGR = 0x7<<24 | 1<<22 |0<<16 |336<<6 |0x8<<0 ;//2.激活HSE晶振RCC->CR |= 1<<16;while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循環(huán)后說明HSE ok了if(retry==0X1FFF)status=1;else{//激活HSE完成了//3.打開PLL等待PLL輸出穩(wěn)定RCC->CR|=1<<24; while((RCC->CR&(1<<25))==0);//4.切換PLL輸出為系統(tǒng)時鐘RCC->CFGR = 0;//清零RCC->CFGR =0x2<<16 |0x4<<13 | 0x5<<10 | 0x0<<4 |0x2<<0;//切換PLL為系統(tǒng)時鐘并且設(shè)置其他分頻while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作為系統(tǒng)時鐘成功.現(xiàn)在主頻是168M了}
驗證測試:
下面可以用串口來打印,驗證是不是設(shè)置完成。
可見是ok了的~說明上面的系統(tǒng)時鐘配置沒問題。main函數(shù)
疑難雜癥:
如果你的整個main函數(shù)是這樣的:是配置完時鐘后也是沒法正常工作的
#include "sys.h"
#include "usart.h"
#include "delay.h" u16 myconut;
//systick中斷服務(wù)函數(shù),使用OS時用到
void SysTick_Handler(void)
{ myconut++;if(myconut>=1000){myconut=0;printf("hello\r\n");}}int main(void)
{ u8 t=0;u16 retry=0;//這個只是提供短暫延時的變量u8 status=0;//按照上面的分析思路,編程流程就是://1.配置PLL倍頻因子RCC->PLLCFGR = 0x7<<24 | 1<<22 |0<<16 |336<<6 |0x8<<0 ;//2.激活HSE晶振RCC->CR |= 1<<16;while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循環(huán)后說明HSE ok了if(retry==0X1FFF)status=1;else{//激活HSE完成了//3.打開PLL等待PLL輸出穩(wěn)定RCC->CR|=1<<24; while((RCC->CR&(1<<25))==0);//4.切換PLL輸出為系統(tǒng)時鐘RCC->CFGR = 0;//清零RCC->CFGR =0x2<<16 |0x4<<13 | 0x5<<10 | 0x0<<4 |0x2<<0;//切換PLL為系統(tǒng)時鐘并且設(shè)置其他分頻while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作為系統(tǒng)時鐘成功.現(xiàn)在主頻是168M了}delay_init(168); //初始化延時函數(shù)NVIC_SetPriorityGrouping(2);SysTick_Config(168000);//1ms中斷一次NVIC_EnableIRQ(SysTick_IRQn);uart_init(84,115200); //串口初始化為115200while(1){}
}
原因是缺少了這樣幾行關(guān)于CPU的代碼:將它加在時鐘配置代碼的上方即可正常運行了
FLASH->ACR|=1<<8; //指令預(yù)取使能.FLASH->ACR|=1<<9; //指令cache使能.FLASH->ACR|=1<<10; //數(shù)據(jù)cache使能.FLASH->ACR|=5<<0; //5個CPU等待周期.
????????正點原子是把它放在時鐘配置里的,我也不知道為啥,但是我覺得它和時鐘配置是沒什么關(guān)系的,應(yīng)該是另一部分的知識。正點原子時鐘配置中還有這樣兩句關(guān)于電源的代碼,我實測去掉也是可以的,不過應(yīng)該還是加上比較好,但是時鐘配置的部分手冊沒有提到,我也就沒有在上面說,以免它出現(xiàn)的很突兀。同樣要加的話加在時鐘配置代碼之前即可。
RCC->APB1ENR|=1<<28; //電源接口時鐘使能PWR->CR|=3<<14; //高性能模式,時鐘可到168Mhz
完事了~系統(tǒng)時鐘就是這樣配置啦,這個算是簡單的,像能跑linux的那種芯片,就得依靠廠家給的來寫或者修改了,自己寫的總有不到位的地方~
整個main.c代碼如下:
#include "sys.h"
#include "usart.h"
#include "delay.h"
//ALIENTEK 探索者STM32F407開發(fā)板 實驗0
//新建工程實驗
//技術(shù)支持:www.openedv.com
//廣州市星翼電子科技有限公司
u16 myconut;
//systick中斷服務(wù)函數(shù),使用OS時用到
void SysTick_Handler(void)
{ myconut++;if(myconut>=1000){myconut=0;printf("hello\r\n");}}int main(void)
{ u8 t=0;//plln,pllm,pllp,pllq//Stm32_Clock_Init(336,8,2,7);//設(shè)置時鐘,168Mhzu16 retry=0;//這個只是提供短暫延時的變量u8 status=0;//CPU相關(guān)的初始化FLASH->ACR|=1<<8; //指令預(yù)取使能.FLASH->ACR|=1<<9; //指令cache使能.FLASH->ACR|=1<<10; //數(shù)據(jù)cache使能.FLASH->ACR|=5<<0; //5個CPU等待周期. //電源相關(guān)的初始化RCC->APB1ENR|=1<<28; //電源接口時鐘使能PWR->CR|=3<<14; //高性能模式,時鐘可到168Mhz//按照博客的分析思路,系統(tǒng)時鐘配置的編程流程就是://1.配置PLL倍頻因子RCC->PLLCFGR = 0x7<<24 | 1<<22 |0<<16 |336<<6 |0x8<<0 ;//2.激活HSE晶振RCC->CR |= 1<<16;while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//跳出循環(huán)后說明HSE ok了if(retry==0X1FFF)status=1;else{//激活HSE完成了//3.打開PLL等待PLL輸出穩(wěn)定RCC->CR|=1<<24; while((RCC->CR&(1<<25))==0);//4.切換PLL輸出為系統(tǒng)時鐘RCC->CFGR = 0;//清零RCC->CFGR =0x2<<16 |0x4<<13 | 0x5<<10 | 0x0<<4 |0x2<<0;//切換PLL為系統(tǒng)時鐘并且設(shè)置其他分頻while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作為系統(tǒng)時鐘成功.現(xiàn)在主頻是168M了}delay_init(168); //初始化延時函數(shù)NVIC_SetPriorityGrouping(2);SysTick_Config(168000);//1ms中斷一次NVIC_EnableIRQ(SysTick_IRQn);uart_init(84,115200); //串口初始化為115200while(1){}
}