天天看點

S3C2440 的定時器的設定(轉)(筆記)

在前面的幾篇文章中,每當程式需要延時時,我們是利用循環語句來實作。這種方法的延時簡單,但不是很精确,就是說不能得到确切的一段時間的延時。是以當需要精确延時時,就不能采用這種方法了。一般是利用定時器來實作。在這裡,我們就介紹一下s3c2440定時器的使用方法。

在講解之前,先介紹一下s3c2440時鐘系統。一般來說,MCU的主時鐘源主要是外部晶振或外部時鐘,而用的最多的是外部晶振。在正确情況下,系統内所使用的時鐘都是外部時鐘源經過一定的處理得到的。由于外部時鐘源的頻率一般不能滿足系統所需要的高頻條件,是以往往需要PLL(鎖相環)進行倍頻處理。在s3c2440中,有2個不同的PLL,一個是MPLL,另一個是UPLL。UPLL是給USB提供48MHz。在這裡,我們主要介紹MPLL。外部時鐘源經過MPLL處理後能夠得到三個不同的系統時鐘:FCLK、HCLK和PCLK。FCLK是主頻時鐘,用于ARM920T核心;HCLK用于AHB總線裝置,如ARM920T,記憶體控制,中斷控制,LCD控制,DMA以及USB主子產品;PCLK用于APB總線裝置,如外圍裝置的看門狗,IIS,I2C,PWM,MMC接口,ADC,UART,GPIO,RTC以及SPI。這三個系統時鐘(FCLK、HCLK和PCLK)是有一定的比例關系,這種關系是通過寄存器CLKDIVN中的HDIVN位和PDIVN位來控制的,是以我們隻要知道了FCLK,再通過這兩位的控制,就能确定HCLK和PCLK。而FCLK是如何得到的呢?它是通過輸入時鐘(即外部時鐘源)的頻率,經過一個計算公式(具體公式請查閱資料手冊)得到的,這個計算公式還需要三個參數(MDIV、PDIV、SDIV),而這三個參數是經過寄存器MPLLCON配置得到的。最後,我們用最清晰的線路來繪制一下時鐘的産生過程:外部時鐘源→通過寄存器MPLLCON得到FCLK→再通過寄存器CLKDIVN得到HCLK和PCLK。這個配置過程在啟動檔案中就已完成。在本開發闆上,外部晶振為12MHz,進過MPLL倍頻以後得到400MHz的FCLK,而FCLK、HCLK、PCLK之間的比例關系為1:4:8,是以HCLK為100MHz,PCLK為50MHz。

s3c2440的時鐘系統就介紹到這裡,我們再回到定時器的配置上來。如何才能得到精确的定時呢?那就要靠TCFG0和TCFG1這兩個寄存器來配置定時器的頻率,即要确定TCNTOn每遞減一個數所需要的時間,它們之間是倒數的關系。具體的計算公式為:

定時器輸出時鐘頻率=PCLK ÷ (prescaler+1) ÷ divider

其中prescaler值由TCFG0決定,divider值由TCFG1決定,而prescaler隻能取0~255之間的整數,divider隻能取2、4、8和16。比如已知PCLK為50MHz,而我們想得到某一定時器的輸出時鐘頻率為25kHz,則依據公式可以使prescaler等于249,divider等于8。有了這個輸出時鐘頻率,理論上我們通過設定寄存器TCNTBn就可以得到任意與0.04毫秒(1÷25000×1000)成整數倍關系的時間間隔了。例如我們想要得到1秒鐘的延時,則使TCNTBn為25000(1000÷0.04)即可。

下面我們通過一段程式來示範利用定時器得到精确延時。這裡我們用到的是定時器4。這段程式的作用是讓蜂鳴器每隔2秒鐘響一次,持續時間為0.5秒,蜂鳴器響的同時伴随着LED亮。

#define _ISR_STARTADDRESS 0x33ffff00

#define U32 unsigned int

#define

pISR_TIMER4         (*(unsigned

*)(_ISR_STARTADDRESS+0x58))

#define rSRCPND     (*(volatile unsigned

*)0x4a000000)     //Interrupt request status

#define rINTMSK     (*(volatile unsigned

*)0x4a000008)      //Interrupt mask control

#define rINTPND     (*(volatile unsigned

*)0x4a000010)      //Interrupt request status

#define rGPBCON    (*(volatile unsigned

*)0x56000010)      //Port B control

#define rGPBDAT    (*(volatile unsigned

*)0x56000014)       //Port B data

#define rGPBUP     (*(volatile unsigned

*)0x56000018) //Pull-up control B

#define rTCFG0  (*(volatile unsigned

*)0x51000000)      //Timer 0 configuration

#define rTCFG1  (*(volatile unsigned

*)0x51000004)      //Timer 1 configuration

#define rTCON   (*(volatile unsigned

*)0x51000008)      //Timer control

#define rTCNTB4 (*(volatile unsigned

*)0x5100003c)       //Timer count buffer

4

void __irq Timer4_ISR(void)

{

       static int count;

       count ++;

       rSRCPND = rSRCPND |

(0x1<<14);

       rINTPND = rINTPND |

       //每隔2秒蜂鳴器響一次,持續時間為0.5秒,并伴随着LED亮

       if (count % 4 ==0)

              rGPBDAT

=

~0x1e0;            //蜂鳴器響,LED亮

       else if (count % 4 ==1)

= 0x1e0;      //蜂鳴器不響,LED滅

}

void Main(void)

       rGPBCON =

0x155555;               //B0輸出,給蜂鳴器;B5~B8輸出,給LED

       rGPBUP  = 0x7ff;

       rGPBDAT =

0x1e0;      //蜂鳴器不響,LED滅

       rINTMSK =

~(0x1<<14);            //打開定時器4中斷

       rTCFG0 &= 0xFF00FF;

       rTCFG0 |=

0xf900;        // prescaler等于249

       rTCFG1 &=

~0xF0000;   

       rTCFG1 |=

0x20000;     //divider等于8,則設定定時器4的時鐘頻率為25kHz

       rTCNTB4 =

12500;              //讓定時器4每隔0.5秒中斷一次

       rTCON &= ~0xF00000;

       rTCON |= 0x700000;

       rTCON &= ~0x200000

;              //定時器4開始工作

       pISR_TIMER4 = (U32)Timer4_ISR;

       while(1)

       {

              ;         

       }