【轉(zhuǎn)自互聯(lián)網(wǎng),如需引用請聯(lián)系原作者】
s3c2410提供了5個16位的Timer(Timer0~Timer4),其中Timer0~Timer3支持Pulse Width Modulation—— PWM(脈寬調(diào)制 )。Timer4是一個內(nèi)部定時器(internal timer),他沒有輸出引腳(output pins)。 下面是Timer的工作原理圖。 如上圖所示,PCLK是Timer的信號源,我們通過設(shè)置每個Timer相應(yīng)的Prescaler和Clock Divider把PCLK轉(zhuǎn)換成輸入時鐘信號傳送給各個Timer的邏輯控制單元(Control Logic),事實上每個Timer都有一個稱為輸入時鐘頻率(Timer input clock Frequency)的參數(shù),這個頻率就是通過PCLK,Prescaler和Clock Divider確定下來的,每個Timer 的邏輯控制單元就是以這個頻率在工作。下面給出輸入時鐘頻率的公式:
Timer input clock Frequency = PCLK / {prescaler value+1} / {clock divider } {prescaler value} = 0~255 { clock divider } = 2, 4, 8, 16
然而并不是每一個Timer都有對應(yīng)的Prescaler和Clock Divider,從上面的原理圖我們可以看到Timer0,Timer1共用一對Prescaler和Clock Divider,Timer2,Timer3,Timer4共用另一對Prescaler和Clock Divider,s3c2410的整個時鐘系統(tǒng)模塊只存在兩對Prescaler和Clock Divider。 我曾經(jīng)在討論watchdog的文章中提到,watchdog也是一種定時器,他的工作就是在一個單位時間內(nèi)對一個給定的數(shù)值進行遞減和比較的操作,而我們這篇文章討論的定時器他的工作內(nèi)容和watchdog在本質(zhì)上是一樣的。定時器在一個工作周期(Timer input clock cycle)內(nèi)的具體工作內(nèi)容主要有3個。分別是:
- 對一個數(shù)值進行遞減操作
- 把遞減后的數(shù)值和另一個數(shù)值進行比較操作
- 產(chǎn)生中斷或執(zhí)行DMA操作
在啟用Timer之前我們會對Timer進行一系列初始化操作,這些操作包括上面提到的設(shè)置Prescaler和Clock Divider,其中還有一個非常重要的就是要給Timer兩個數(shù)值,我們分別稱之為Counter(變量,用于遞減)和Comparer(定值,用于比較),Counter會被Timer 加載到COUNT BUFFER REGISTER(TCNTB),而Comparer會被Timer 加載到和COMPARE BUFFER REGISTER(TCMPB),每個Timer都有這樣兩個寄存器。當(dāng)我們設(shè)置完畢啟動Timer之后,Timer在一個工作周期內(nèi)所做的就是先把TCNTB中的數(shù)值(Counter)減1,之后把TCNTB中的數(shù)值和TCMPB中的數(shù)值(Comparer)進行對比,若Counter已經(jīng)被遞減到等于Comparer,發(fā)生計數(shù)超出,則Timer產(chǎn)生中斷信號(或是執(zhí)行DMA操作)并自動把Counter重新裝入TCNTB(刷新TCNTB以重新進行遞減)。以上就是Timer的工作原理。
下面我們結(jié)合代碼具體說明如何對Timer0進行初始化并開啟它。 首先我假設(shè)我的PCLK是50700000Hz
// define Timer register #define rTCFG0 (*(volatile unsigned int *)0x51000000) #define rTCFG1 (*(volatile unsigned int *)0x51000004) #define rTCON (*(volatile unsigned int *)0x51000008) #define rTCNTB0 (*(volatile unsigned int *)0x5100000C) #define rTCMPB0 (*(volatile unsigned int *)0x51000010) #define rTCNTO0 (*(volatile unsigned int *)0x51000014) #define rTCNTB1 (*(volatile unsigned int *)0x51000018) #define rTCMPB1 (*(volatile unsigned int *)0x5100001C) #define rTCNTO1 (*(volatile unsigned int *)0x51000020) #define rTCNTB2 (*(volatile unsigned int *)0x51000024) #define rTCMPB2 (*(volatile unsigned int *)0x51000028) #define rTCNTO2 (*(volatile unsigned int *)0x5100002C) #define rTCNTB3 (*(volatile unsigned int *)0x51000030) #define rTCMPB3 (*(volatile unsigned int *)0x51000034) #define rTCNTO3 (*(volatile unsigned int *)0x51000038) #define rTCNTB4 (*(volatile unsigned int *)0x5100003C) #define rTCNTO4 (*(volatile unsigned int *)0x51000040)
void timer0_config() { /* Timer0的prescaler由rTCFG0 的 0~7 bit決定 Prescaler=119 */ rTCFG0=119 /* Timer0的divider value由TCFG1的 0~3 bit決定,設(shè)置為3表示divider value = 1/16 rTCFG1的第20~23bit用于決定Timer計數(shù)超出后所采取的響應(yīng),我們使用了中斷模式(20~23bit全部為0), 即計數(shù)超出后產(chǎn)生中斷 */ rTCFG1=3; rTCNTB0=26406; rTCMPB0=0; } 由于我們的PCLK是50700000Hz, 根據(jù)Timer input clock Frequency的計算公式我們?nèi)缦掠嬎鉚imer0的時鐘輸入頻率:
prescaler value = 119 divider value = 1/16 PCLK= 50700000 Timer input clock Frequency =50700000/ (119+1)/(1/16)=26406
也就是說通過設(shè)置prescaler和divider value之后,Timer0的工作頻率為26406,也就是說一秒內(nèi)Timer0會進行26406次遞減和比較操作,假設(shè)我們現(xiàn)在是要讓Timer0每1秒產(chǎn)生一次中斷的話,我們應(yīng)該設(shè)置Counter=26406和Camparer=0,既:
rTCNTB0=26406; rTCMPB0=0;
如果我們要讓Timer0每0.5秒產(chǎn)生一次中斷,則我們應(yīng)該設(shè)置Counter=26406/2和Camparer=0,既:
rTCNTB0=13203; rTCMPB0=0;
如果我們要讓Timer0每0.25秒產(chǎn)生一次中斷,則我們應(yīng)該設(shè)置Counter=26406/4和Camparer=0,既:
rTCNTB0=6601; rTCMPB0=0;
初始化完Timer后我們要開啟它。
void timer0_start() { /* Update TCNTB0 & TCMPB0 rTCON寄存器的第1位是刷新Timer0的COUNT BUFFER REGISTER(TCNTB)和 COMPARE BUFFER REGISTER(TCMPB),由于是第一次加載Counter和Comparer, 所以我們需要手動刷新它們 */ rTCON|=1<<1; /* 置rTCON第0位為1,開啟Timer0 把rTCON第1位置為0,停止刷新TCNTB0 和 TCMPB0 置rTCON第3位為1,設(shè)置Counter的加載模式為自動加載(auto reload),這樣每當(dāng) Timer計數(shù)超出之后(此時TCNTB的值等于TCMPB的值),Timer會自動把原來我們給 定的Counter重新加載到TCNTB中 */ rTCON=0x09; }
要使你的Timer能夠正常的工作,除了調(diào)用timer0_config()和timer0_start()之外,我們還必須設(shè)置Timer的中斷服務(wù)例程并取消對Timer的中斷的屏蔽. |