天天看點

一起學mini2440裸機開發(五)--定時器0的基礎實驗 - 無網不進

一起學mini2440裸機開發(五)--定時器0的基礎實驗

本篇文章接上一篇關于定時器原理:http://blog.csdn.net/mybelief321/article/details/8916775

實驗前的準備 

      既然是關于定時器的實驗,肯定要用到系統時鐘,是以一定要保證系統時鐘設定好,在這裡需要的PCLK為50MHz。第二節分析MDK自帶的S3C2440.c可以知道,預設的是不初始化系統時鐘(是否選擇初始化可以通過修改S3C2440.s中的CLOCK_SETUP來選擇)。那麼在這裡首先修改一下S3C2440.s,對時鐘進行初始化。

     在這裡隻需要設定一處即可将 CLOCK_SETUP     EQU     0修改為CLOCK_SETUP     EQU     1,這樣系統在啟動時就會對咱們的晶片進行初始化,初始化之後的系統時鐘值為:FCLK=300MHz,HCLK=100MHz,PCLK=50MHz。

實驗1

     實驗實作的功能:使用定時器0的定時功能,是LED每秒鐘閃爍一次。   

    因為在啟動代碼階段,已經對系統時鐘進行初始化,PCLK=50MHz,定時器的輸入頻率由PCLK分頻得到,如圖1所示展示了從晶振輸入頻率到定時器工作頻率産生的整體過程。

一起學mini2440裸機開發(五)--定時器0的基礎實驗 - 無網不進

      下圖是我的定時器工程的檔案布局圖:

一起學mini2440裸機開發(五)--定時器0的基礎實驗 - 無網不進

    從上圖可以看出,這個工程需要咱們自己編寫的檔案一共有5個:main.c  timer.c   timer.h    led.c   led.h

    實驗代碼:

    main.c檔案内容:

/* *  使用定時器0的定時功能,使LED燈每秒鐘閃爍一次 */

#include<s3c2440.h> #include"timer.h" #include"led.h"

int main() {          int flag=0;      Led_Init();   //對LED初始化為全滅     Timer0_Init();  //定時器0初始化,打開定時器0,定時器0開始進行減1計數。      while(1)     {         if(SRCPND&(1<<10))     //當TCNT0中的計數值減為0時,定時器0中斷标志會置位         {                                     //是以,在程式中可以通過不斷的檢測該位是否置位來判斷1s定時              flag=!flag;                     //是否到達。定時器0中斷标志位位于SRCPND寄存器的第10位              SRCPND|=(1<<10);     //清除定時器0中斷标志位          }          if(1==flag)                      //判斷falg是否為1,這裡使用一個小技巧,使用if(1==flag)。也可以

                                              //使用if(flag==1)。         {             Led1_On();         }           else        {            Led1_Off();         }        } }

    timer.c檔案内容

            #include<s3c2440.h>   //s3c2440.h對S3C2440晶片的一些位址的宏定義             #include"timer.h"

 /*************************************************************** * 函數名稱:void Timer0_Init(void) * 參數說明:無 * 全局變量:無 * 返 回 值:無 * 功    能:對于50MHz的PCLK,經過分頻獲得62.5KHz的定時器0 *     的輸入時鐘。 ***************************************************************/ void Timer0_Init(void) {  TCFG0&=~(0xff);          //設定第1級分頻系數,分頻系數為99  TCFG0|=99;

 TCFG1&=~(0xf);            //設定第2級分頻系數,分頻系數為8  TCFG1|=0x02;               //62.5KHz=50MHz/(99+1)/8

 TCNTB0=62500;            //1s中斷一次。經過上述分頻器得到定時器0的輸入時鐘頻率為62.5kHz,即定時                                        //器每秒鐘計數62500次。是以,初始化時,定時器0計數值初始值為62500,在這                                        //裡我們可以看出TCMPBn沒有設定,因為咱們用它的預設值0,是以就不需要設定

 TCON|=(1<<1);             //開啟手動更新位,即當定時器開啟後,TCMPB0和TCNTB0中的值會加載到寄存

                                      //器TCMP0和TCNT0中  TCON=0x09;                //關閉手動更新位,設定自動加載位,同時開啟定時器,這樣,TCNT0進行減1計

                                     //數,當TCNT0中的計數值減到0時,TCNTB0、TCMPB0中的資料分别會                                      //自動加載到TCNT0、TCMP0中并進行新一輪的減1計數 }

   timer.h檔案内容:

#ifndef __TIMER_H__ #define __TIMER_H__

/*************************************************************** * 函數名稱:void Timer0_Init(void) * 參數說明:無 * 全局變量:無 * 返 回 值:無 * 功    能:對于50MHz的PCLK,經過分頻獲得62.5KHz的定時器0 *     的輸入時鐘。 ***************************************************************/ void Timer0_Init(void);

#endif

   led.c檔案内容:

/* *  在我的mini2440開發闆上,4個led燈對應的GPIO引腳如下 *   LED1----GPB5 *   LED2----GPB6 * LED3----GPB7 *   LED4----GPB8 *   當GPIO引腳輸出低電平時,對應的led燈亮,輸出高電平時,對應的led燈滅。 */

#include<s3c2440.h>   #include"led.h"

/*************************************************************** * 函數名稱:void Led_Init(void) * 參數說明:無 * 全局變量:無 * 返 回 值:無 * 功    能:led初始化函數,使4個led初始化為滅 *     的輸入時鐘。 ***************************************************************/ void Led_Init(void) {  GPBCON&=~((3<<10)|(3<<12)|(3<<14)|(3<<16));  //注意這裡設定寄存器的方式,采用先與後或的方式  GPBCON|=((1<<10)|(1<<12)|(1<<14)|(1<<16));    //設定GPB5、6、7、8為輸出功能

 GPBUP&=~((1<<5)|(1<<6)|(1<<7)|(1<<8));      //上拉電阻使能。上拉電阻的作用是:當GPIO引腳處于

                                                                          //第三态(既不是輸出高電平,也不是輸出低電平,而是呈

                                                                         //高阻态,即相當于沒接晶片)時,它的電平狀态由上拉                                                                            //電阻、下拉電阻确定

 GPBDAT|=((1<<5)|(1<<6)|(1<<7)|(1<<8));      //初始化這4個引腳輸出高電平,即4個led燈全滅。 }

    led.h檔案内容:

#ifndef __LED_H__ #define __LED_H__

#define Led1_On() {GPBDAT&=(~(1<<5));}       //在程式調用函數時,調用函數需要儲存函數的傳回位址, #define Led1_Off() {GPBDAT|=(1<<5);}           //然後從函數傳回是需要将傳回位址指派給PC,這些都會 #define Led2_On() {GPBDAT&=(~(1<<6));}    //使程式執行速度變慢。為了改善這種情況,對于這種 #define Led2_Off() {GPBDAT|=(1<<6);}         //代碼量很小的程式段,可以使用宏的形式實作。 #define Led3_On() {GPBDAT&=(~(1<<7));} #define Led3_Off() {GPBDAT|=(1<<7);} #define Led4_On() {GPBDAT&=(~(1<<8));} #define Led4_Off() {GPBDAT|=(1<<8);} /*************************************************************** * 函數名稱:void Led_Init(void) * 參數說明:無 * 全局變量:無 * 返 回 值:無 * 功    能:led初始化函數,使4個led初始化為滅 *     的輸入時鐘。 ***************************************************************/ void Led_Init(void);

#endif

      以上實驗1的代碼我已經上傳到csdn,如有需要可自行下載下傳:http://download.csdn.net/detail/mybelief321/5371577,mske編譯成功後,就可以仿真看到結果了。

     上述實驗1的已經說完了,再強調一下,我沒有再編寫代碼另外設定系統時鐘,而是用MDK自帶的S3C2440.s來初始化的,隻需要修改一處地方,本文章開頭所示。

      還有一處需要說明一下,那就是關于main函數裡的中斷。雖然定時器0中斷标志還沒有講,但是我們可以先了解以下三點:

      ①SRCPND寄存器中的每一位代表一種類型的中斷标志,當該位置1時,說明相應的中斷發生了。

      ②定時器0中斷标志位于SRCPND寄存器的第10位,當定時器0中的計數值減到0時,會觸發定時器0中斷标志,即SRCPND寄存器第10位會置1.

     ③清除定時器0中斷标志的方法是:想SRCPND寄存器的第10位寫入1即可。

實驗2

      實驗1主要是針對定時器的原理進行的實驗,下面的實驗是為了展示定時器0的脈沖寬度調制功能。

    從下圖可以看出,當TCMP0=TCNT0時,TOUT0引腳電平會發生翻轉;當TCNT0中計數值減為0時,TOUT0引腳電平再次發生翻轉。是以,可以利用TOUT0引腳電平的兩次翻轉進行脈沖寬度調制,即PWM。查詢S3C2440資料手冊可以得到,TOUT0引腳對應的是GPB0引腳。

一起學mini2440裸機開發(五)--定時器0的基礎實驗 - 無網不進

       在實驗1的基礎上,修改timer.c中定時器0初始化函數。修改後的定時器0初始化函數如下:    

void  Timer0_Init(void) {  GPBCON&=~(3<<0);  GPBCON|=(1<<1);

 TCFG0&=~(0xff);    //設定第1級分頻系數,分頻系數為99  TCFG0|=99;

 TCFG1&=~(0xf);      //設定第2級分頻系數,分頻系數為8  TCFG1|=0x02;        //62.5KHz=50MHz/(99+1)/8                                 //此時定時器0的工作頻率為62500Hz

 TCNTB0=62;                  //由于此時定時器0的工作頻率為62500Hz,即每秒種可以計數62500次,而其初始值為62,是以産生的方波                                        //的頻率為62500/62=1008Hz。又因為TCMP0=TCNT0/2,是以産生的方波高電平持續時間和低電平持續時間  TCMPB0=TCNTB0/2;   //各占一半。

 TCON|=(1<<1); //開啟手動更新位,即當定時器開啟後,TCMPB0和TCNTB0中的值會加載到寄存器TCMP0和TCNT0中  TCON=0x0d;     //關閉手動更新位,設定自動加載位,同時開啟定時器,設定當TCMP0=TCNT0時,TOUT0引腳電平發生翻轉 }

      程式總體流程:

       ①開啟定時器0後,TCNTB0、TCMPB0中的值分别裝入TCNT0和TCMP0中,然後,TCNT0從初值62開始減1計數;

       ②當TCNT0=TCMP0=31時,TOUT0引腳電平發生翻轉;

       ③TCNT0繼續減1計數,當TCNT0減為0時,TOUT0引腳電平再次發生翻轉,此時恰好産生一個方波;

       ④TCNTB0、TCMPB0中的值被自動裝入TCNT0、TCMP0中,TCNT0繼續從初值62開始減1計數。

     上述程式,占空比為50%,如果将 TCMPB0=TCNTB0/2 改為 TCMPB0=TCNTB0/4,那麼輸出方波的占空比發生了變化,變為75%,這就是所謂的PWM功能。

     由于咱們的開發闆的GPB0連接配接着蜂鳴器,是以你可以通過調節占空比來改變蜂鳴器的頻率,将上述初始化函數修改後,直接make,仿真就可以了。

posted on

2018-05-10 14:53 

無網不進 

閱讀(216) 

評論(0) 

編輯 

收藏 

舉報

一起學mini2440裸機開發(五)--定時器0的基礎實驗 - 無網不進