今天學習一下正點原子的工程System文件夾delay.c sys.c usart.c源文件實現的原理
1.delay.c
delay_init()函數
1 //初始化延遲函數 2 //當使用OS的時候,此函數會初始化OS的時鍾節拍 3 //SYSTICK的時鍾固定為AHB時鍾的1/8 4 //SYSCLK:系統時鍾頻率 5 void delay_init(u8 SYSCLK) 6 { 7 #if SYSTEM_SUPPORT_OS //如果需要支持OS. 8 u32 reload; 9 #endif 10 SysTick->CTRL&=~(1<<2); //SYSTICK使用外部時鍾源 11 fac_us=SYSCLK/8; //不論是否使用OS,fac_us都需要使用 12 #if SYSTEM_SUPPORT_OS //如果需要支持OS. 13 reload=SYSCLK/8; //每秒鍾的計數次數 單位為M 14 reload*=1000000/delay_ostickspersec; //根據delay_ostickspersec設定溢出時間 15 //reload為24位寄存器,最大值:16777216,在168M下,約合0.7989s左右 16 fac_ms=1000/delay_ostickspersec; //代表OS可以延時的最少單位 17 SysTick->CTRL|=1<<1; //開啟SYSTICK中斷 18 SysTick->LOAD=reload; //每1/delay_ostickspersec秒中斷一次 19 SysTick->CTRL|=1<<0; //開啟SYSTICK 20 #else 21 fac_ms=(u16)fac_us*1000; //非OS下,代表每個ms需要的systick時鍾數 22 #endif 23 }
使用了條件編譯的方法,在不支持OS的條件下,函數主要干了這幾件事:設置了Sysstick的時鍾源為外部時鍾源
因為systick的固定時鍾為AHB時鍾的1/8,所以每個fac_us可以看成每個us時鍾需要滴答的節拍數。
同理fac_ms = fac_us*1000也是一樣的道理;
關於systick的學習:
通過代碼跟蹤:
1 #define SysTick ((SysTick_Type *) SysTick_BASE )
2
3 #define SysTick_BASE (SCS_BASE + 0x0010UL)
4
5 #define SCS_BASE (0xE000E000UL)
通過翻閱《Cortex-M3與M4權威指南》一書P135頁 Memory Map 0xE0000000 - 0xFFFFFFFF 為system的Private Peripherqal Bus 中間有那么一段地址空間(0XE000E000-0XE000EFFF),4KB的空間是System Control Space(SCS)的地址范圍。
截取部分文檔所說:The NVIC and SCB are located inside the System Control Space (SCS) address range from 0xE000E000, with a size of 4KB. The SCS also contains registers for the SysTick timer, Memory Protection Unit (MPU), debug registers, etc. Almost all of the registers in this address range can only be accessed by code running in privileged access level. The only exception is a register called the Software Trigge -r Interrupt Register (STIR), which can be set up to be accessible in unprivileged mode.
紅色的字體表示 也就是4KB的空間包括了systick timer寄存器配置。進一步查找 SCS_BASE + 0X0010 = 0XE000E010
在P350頁中也有說明 該地址是systick->CTRL寄存器的地址
1 //延時nus 2 //nus為要延時的us數. 3 //注意:nus的值,不要大於798915us(最大值即2^24/fac_us@fac_us=21)
4 void delay_us(u32 nus) 5 { 6 u32 temp; 7 SysTick->LOAD=nus*fac_us; //時間加載
8 SysTick->VAL=0x00; //清空計數器
9 SysTick->CTRL=0x01 ; //開始倒數
10 do
11 { 12 temp=SysTick->CTRL; 13 }while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達
14 SysTick->CTRL=0x00; //關閉計數器
15 SysTick->VAL =0X00; //清空計數器
16 }
簡單的定時器使用,這里簡要說明一下。
LOAD寄存器裝載的是需要定時的節拍數。
VAL寄存器裝載的是當前定時器內容的值,所以需要清零。
CTRL寄存器的第0位是定時器的使能位 第15位為定時器定時時間到的標志位 置一。
delay_ms的實現和delay_us的實現相似,但是需要注意的是定時的Ms必須小於798ms
Stm32_Clock_Set()函數
1 //時鍾設置函數 2 //Fvco=Fs*(plln/pllm); 3 //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp)); 4 //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq)); 5
6 //Fvco:VCO頻率 7 //Fsys:系統時鍾頻率 8 //Fusb:USB,SDIO,RNG等的時鍾頻率 9 //Fs:PLL輸入時鍾頻率,可以是HSI,HSE等. 10 //plln:主PLL倍頻系數(PLL倍頻),取值范圍:64~432. 11 //pllm:主PLL和音頻PLL分頻系數(PLL之前的分頻),取值范圍:2~63. 12 //pllp:系統時鍾的主PLL分頻系數(PLL之后的分頻),取值范圍:2,4,6,8.(僅限這4個值!) 13 //pllq:USB/SDIO/隨機數產生器等的主PLL分頻系數(PLL之后的分頻),取值范圍:2~15. 14
15 //外部晶振為8M的時候,推薦值:plln=336,pllm=8,pllp=2,pllq=7. 16 //得到:Fvco=8*(336/8)=336Mhz 17 // Fsys=336/2=168Mhz 18 // Fusb=336/7=48Mhz 19 //返回值:0,成功;1,失敗。
20 u8 Sys_Clock_Set(u32 plln,u32 pllm,u32 pllp,u32 pllq) 21 { 22 u16 retry=0; 23 u8 status=0; 24 RCC->CR|=1<<16; //HSE 開啟
25 while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//等待HSE RDY
26 if(retry==0X1FFF)status=1; //HSE無法就緒
27 else
28 { 29 RCC->APB1ENR|=1<<28; //電源接口時鍾使能
30 PWR->CR|=3<<14; //高性能模式,時鍾可到168Mhz
31 RCC->CFGR|=(0<<4)|(5<<10)|(4<<13);//HCLK 不分頻;APB1 4分頻;APB2 2分頻.
32 RCC->CR&=~(1<<24); //關閉主PLL
33 RCC->PLLCFGR=pllm|(plln<<6)|(((pllp>>1)-1)<<16)|(pllq<<24)|(1<<22);//配置主PLL,PLL時鍾源來自HSE
34 RCC->CR|=1<<24; //打開主PLL
35 while((RCC->CR&(1<<25))==0);//等待PLL准備好
36 FLASH->ACR|=1<<8; //指令預取使能.
37 FLASH->ACR|=1<<9; //指令cache使能.
38 FLASH->ACR|=1<<10; //數據cache使能.
39 FLASH->ACR|=5<<0; //5個CPU等待周期.
40 RCC->CFGR&=~(3<<0); //清零
41 RCC->CFGR|=2<<0; //選擇主PLL作為系統時鍾
42 while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作為系統時鍾成功.
43 } 44 return status; 45 }
Stm32_Clock_Init()函數
STM32F4時鍾介紹:(參考STM32F4英文參考手冊)
SYSCLK的時鍾來源:
HSI oscillator clock High Speed Internal clock
HSE oscillator clock High Speed External clock
PLL clock 鎖相環時鍾電路
第二時鍾源: 用途
LSI(32KHZ) Low Speed Internal clock watchdog RTC used for Auto Wakeup
LSE(32.768KHZ) Low Speed External clock drivers RTC(RTCCLK)