在GPIO控制篇中的延時閃爍LED只用了簡單的for循環,為了精確的計時本篇介紹使用SysTick定時器每1ms產生中斷,從而實現精確定時的目的。要使用系統節拍定時器主要進行兩個部分的配置。1:系統時鍾控制。2系統節拍定時器的控制。
一,系統時鍾控制
LPC1788有3個獨立的振盪器。他們是主振盪器,內部RC振盪器,RTC振盪器。復位后,LPC1788將用內部的RC振盪器運行,直到被軟件切換。這樣就能在沒有任何外部晶振的情況下運行。LPC1788的時鍾控制如圖1所示

在開發板上使用12M的晶振作為主振盪器,它通過鎖相環PLL0來提高頻率提供CPU。由於芯片總是從內部的RC振盪器開始工作,因此主振盪器只會應軟件的請求而啟動。實現方法是設定SCS寄存器中的OSCEN位使能。主振盪器提供一個狀態標志SCS寄存器的OSCSTAT位,這樣軟件就可以確定何時主振盪器在運行穩定。此時,軟件可以控制切換到主振盪器,使其作為時鍾源。在啟動以前,必須通過SCS的OSCRANGE位,選擇一個頻率范圍。在確定了主振盪器之后,需要進行鎖相環的配置。1,配置CLKSRCSEL選擇正確的時鍾源。2,將正確的PLL設置值寫入PLLCFG寄存器並且在PLLCON中使能PLL。3,向PLLFEED寄存器中寫入饋送序列0xAA,0x55。4,設置所需的時鍾分配器如CCLKSEL,PCLSEL,EMCCLKSEL,以及USBCLKSEL寄存器。5,查詢PLLSTAT寄存器等待PLL鎖定。
二,系統節拍定時器的控制
LPC1788的系統節拍定時器是一個24位的定時器,當數值達到0時產生中斷。系統節拍定時器的時鍾信號可以由CPU時鍾提供(即圖1中的cclk)。想要在規定的時間間隔循環的產生中斷,必須將指定的正確時間間隔值裝入STRELOAD寄存器進行初始化。假如我們選擇cclk作為系統節拍的時鍾信號,並且根據開發板將系統時鍾設置成12MHZ,為了循環1ms產生一次中斷,我們寫入STRELOAD的值為cclk/1000 - 1 。
程序的代碼如下,使LED燈每500ms閃爍。SystemInit函數在啟動文件中被調用。
- #define rFIO1DIR (*(volatile unsigned*)0x20098020)
- #define rFIO1MASK (*(volatile unsigned*)0x20098030)
- #define rFIO1PIN (*(volatile unsigned*)0x20098034)
- #define rFIO1SET (*(volatile unsigned*)0x20098038)
- #define rFIO1CLR (*(volatile unsigned*)0x2009803c)
- #define rCLKSRCSEL (*(unsigned *)(0x400FC10C)) //時鍾源選擇寄存器
- #define rPLL0CON (*(unsigned *)(0x400FC080)) //PLL0控制寄存器
- #define rPLL0CFG (*(unsigned *)(0x400FC084)) //PLL0配置寄存器
- #define rPLL0STAT (*(unsigned *)(0x400FC088)) //PLL0狀態寄存器
- #define rPLL0FEED (*(unsigned *)(0x400FC08C)) //PLL0饋送寄存器
- #define rPLL1CON (*(unsigned *)(0x400FC0A0))
- #define rPLL1CFG (*(unsigned *)(0x400FC0A4))
- #define rPLL1STAT (*(unsigned *)(0x400FC0A8))
- #define rPLL1FEED (*(unsigned *)(0x400FC0AC))
- #define rCCLKSEL (*(unsigned *)(0x400FC104)) //CPU時鍾選擇寄存器
- #define rUSBCLKSEL (*(unsigned *)(0x400FC108)) //USB時鍾選擇寄存器
- #define rPCLKSEL (*(unsigned *)(0x400FC1A8)) //外設時鍾寄存器
- #define rPCON (*(unsigned *)(0x400FC0C0))
- #define rPXCONP (*(unsigned *)(0x400FC0C4))
- #define rSCS (*(unsigned *)(0x400FC1A0)) //系統控制和狀態寄存器
- #define rCLKOUTCFG (*(unsigned *)(0x400FC1C8))
- #define rSTCTRL (*(unsigned *)(0xE000E010))
- #define rSTRELOAD (*(unsigned *)(0xE000E014))
- #define rSTCURR (*(unsigned *)(0xE000E018))
- #define rSTALIB (*(unsigned *)(0xE000E01C))
- #define CCLK 120000000
- volatile unsigned long SysTickCnt;
- /*
- 系統時鍾初始化
- */
- void SystemInit()
- {
- rSCS &= ~(0x1<<4); //頻率12M
- rSCS |= (0x1<<5); //使能主振盪器
- while(0 == (rSCS & (0x1<<6)));//等待主振盪器穩定
- rCLKSRCSEL = 0x1;
- rPLL0CFG = 0x9; //配置CCLK = 120M
- rPLL0CON = 0x01;
- rPLL0FEED = 0xAA;
- rPLL0FEED =0x55;
- while( 0 == (rPLL0STAT & (0x1<<10)));
- rCCLKSEL = (0x1 | (0x1<<8));
- rPCLKSEL = 0x2; //配置PCLK = 60M
- rCLKOUTCFG = 0x0 | (0xb<<4) | (0x1<<8);
- }
- /*
- 系統節拍定時器初始化
- */
- unsigned char SysTick_Config(unsigned int ticks)
- {
- if(ticks > 0xFFFFFFUL)
- return 0;
- rSTRELOAD = ticks;
- rSTCURR = 0x0;
- rSTCTRL = (0x1) | (0x1<<1) | (0x1<<2);
- return 1;
- }
- /*
- 系統節拍定時器中斷處理函數
- */
- void SysTick_Handler (void)
- {
- SysTickCnt++;
- }
- int main()
- {
- unsigned char value = 1;
- SysTick_Config(CCLK/1000-1); //每1ms產生一次SysTick系統異常
- rFIO1DIR |= (1<<18); //GPIO1.18 -> OUTPUT
- while(1)
- {
- if(SysTickCnt >= 500)
- {
- SysTickCnt = 0;
- value = !value;
- }
- if(0 == value)
- {
- rFIO1PIN &= ~(1<<18);
- }
- elseif(1 == value)
- {
- rFIO1PIN |= (1<<18);
- }
- }
- }
