LPC1114系統(tǒng)定時器(SysTick)
系統(tǒng)定時器也位于“私有外設(shè)總線”(Private peripheral bus)內(nèi),其地址為0xE000E010~0xE000E01F。下面先來看一下SysTick的內(nèi)部結(jié)構(gòu),如下圖所示。
本文引用地址:http://m.butianyuan.cn/article/201611/316325.htm從上圖中可以看出,SysTick定時器的位長度是24位,即最長的計數(shù)次數(shù)為16777216次,且計數(shù)為倒數(shù)計數(shù)形式,遞減到0時產(chǎn)生中斷請求。計數(shù)的脈沖可直接取系統(tǒng)時鐘,也可取半系統(tǒng)時鐘。下表給出了和SysTick相關(guān)的寄存器。
{
__IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
SysTick定時器組的基址為0xE000E000,所以要將基址指針強制轉(zhuǎn)換為上述結(jié)構(gòu)體,還要加上下面的定義。
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
{
系統(tǒng)定時中斷服務(wù)程序部分
}
接下來討論一下系統(tǒng)定時器的初始值設(shè)置,因為定時的時長由系統(tǒng)時鐘頻率、系統(tǒng)時鐘選擇和載入的初始值共同決定。假設(shè)系統(tǒng)時鐘為48MHz,默認情況下SysTick的CLKSOURCE值為0,即選擇半系統(tǒng)時鐘頻率。這樣,輸入給定時器計數(shù)的時鐘就是48/2=24MHz,計數(shù)周期為1/(24MHz)=1/24us,則計24次就是1us的定時,但實際上SysTick采用的是倒數(shù)計數(shù)方式,即從最大值依次遞減計數(shù)直到0產(chǎn)生溢出信號。所以24次計數(shù)實際上是0~23次,即最大值要減1,即24-1=23。同時要注意,由于計數(shù)位寬是24位,所以最大計數(shù)值不能超過2的24次方(即16777216),由此,可得出微秒級的初始值計算公式,如下:
LOAD=((24*us)-1),其中us取值范圍1~699000
同理可得出毫秒級的初始值計算公式:
LOAD=((24000*ms)-1),其中ms取值范圍1~699
上升到一般情況,定時初始值可用下面的公式來計算:
上式中,系統(tǒng)時鐘SysClk的單位是MHz,CLKSOURCE的值是0或1,得到的是微秒級別的定時,要注意LOAD的值不能大于16777216。
下面來看一下前面第一個演示示例中的延時部分,代碼如下:
static volatile uint32_t TimeTick = 0; //設(shè)置全局變量
void SysTick_Handler(void)
{
TimeTick++; //系統(tǒng)定時中斷中,全局變量加1
}
void delay_ms(uint32_t ms)
{
SysTick->LOAD = (((24000)*ms)-1); //載入初始值
SysTick->VAL = 0;//寫當(dāng)前值寄存器使其清零
SysTick->CTRL |= ((1<<1)|(1<<0)); //打開中斷,啟動定時器,選擇關(guān)系統(tǒng)時鐘
while(!TimeTick);
TimeTick = 0; //當(dāng)定時時間到時,全局變量清零
SysTick->CTRL =0;//關(guān)閉定時器
}
可見上述定時是毫秒級別的,最長可定時699ms。
至此,第一個演示示例中的全部內(nèi)容就都討論完了,可見在LPC1114中要實現(xiàn)一個簡單的十二個LED交替閃爍,涉及到的內(nèi)容還是很多的。下面再來看一個流水燈的例子,要求實現(xiàn)一個12位的流水燈,時間間隔為100ms。假設(shè)LED采用共陽接法接在GPIO2端口,參考代碼如下:
#include
//===================系統(tǒng)定時器中斷服務(wù)程序============================
void SysTick_Handler(void)
{
uint32_t temp;//定義臨時中間變量
temp = LPC_GPIO2->DATA;//讀取當(dāng)前端口2的值
temp = ~temp; //把中間變量進行取反
temp<<=1; //把中間變量進行左移一位
temp = ~temp; //再次把中間變量進行取反
LPC_GPIO2->DATA = temp; //把左移后的量賦給端口2
if(temp==0xFFF) //如果左移到頭,則從頭開始
{
LPC_GPIO2->DATA = 0xFFE;
}
}
//========================系統(tǒng)定時器初始化=============================
void SysTick_init(void)
{
SysTick->LOAD = (((24000)*100)-1);//設(shè)置100ms的定時
SysTick->VAL = 0; //計數(shù)清零
SysTick->CTRL |= ((1<<1)|(1<<0)); //允許中斷,選擇半系統(tǒng)時鐘,啟動定時器
}
//============================主函數(shù)==================================
int main(void)
{
LPC_GPIO2->DIR = 0xFFF; //設(shè)置端口2為輸出方向
LPC_GPIO2->DATA = 0xFFE;//端口2最低位輸出0,點亮最末一個LED
SysTick_init();//調(diào)用系統(tǒng)定時器
while(1)
{
;//空循環(huán)
}
}
把程序編譯后下載到LPC1114中,給系統(tǒng)上電,可看到接到端口2上的12個LED在閃爍流動。
評論