新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > s3c2440的PWM應用

        s3c2440的PWM應用

        作者: 時間:2016-11-19 來源:網絡 收藏
        PWM(Pulse Width Modulation)——脈寬調制,它是利用微控制器的數字輸出來對模擬電路進行控制的一種非常有效的技術,廣泛應用于測量、通信、功率控制與變換等許多領域。

        s3c2440芯片中一共有5個16位的定時器,其中有4個定時器(定時器0~定時器3)具有脈寬調制功能,因此用s3c2440可以很容易地實現PWM功能。下面就具體介紹如何實現PWM功能。

        1、PWM是通過引腳TOUT0~TOUT3輸出的,而這4個引腳是與GPB0~GPB3復用的,因此要實現PWM功能首先要把相應的引腳配置成TOUT輸出。

        2、再設置定時器的輸出時鐘頻率,它是以PCLK為基準,再除以用寄存器TCFG0配置的prescaler參數,和用寄存器TCFG1配置的divider參數。

        3、然后設置脈沖的具體寬度,它的基本原理是通過寄存器TCNTBn來對寄存器TCNTn(內部寄存器)進行配置計數,TCNTn是遞減的,如果減到零,則它又會重新裝載TCNTBn里的數,重新開始計數,而寄存器TCMPBn作為比較寄存器與計數值進行比較,當TCNTn等于TCMPBn時,TOUTn輸出的電平會翻轉,而當TCNTn減為零時,電平會又翻轉過來,就這樣周而復始。因此這一步的關鍵是設置寄存器TCNTBn和TCMPBn,前者可以確定一個計數周期的時間長度,而后者可以確定方波的占空比。由于s3c2440的定時器具有雙緩存,因此可以在定時器運行的狀態下,改變這兩個寄存器的值,它會在下個周期開始有效。

        4、最后就是對PWM的控制,它是通過寄存器TCON來實現的,一般來說每個定時器主要有4個位要配置(定時器0多一個死區位):啟動/終止位,用于啟動和終止定時器;手動更新位,用于手動更新TCNTBn和TCMPBn,這里要注意的是在開始定時時,一定要把這位清零,否則是不能開啟定時器的;輸出反轉位,用于改變輸出的電平方向,使原先是高電平輸出的變為低電平,而低電平的變為高電平;自動重載位,用于TCNTn減為零后重載TCNTBn里的值,當不想計數了,可以使自動重載無效,這樣在TCNTn減為零后,不會有新的數加載給它,那么TOUTn輸出會始終保持一個電平(輸出反轉位為0時,是高電平輸出;輸出反轉位為1時,是低電平輸出),這樣就沒有PWM功能了,因此這一位可以用于停止PWM。

        PWM有很多用途,在這里我利用開發板的資源,用它來驅動蜂鳴器,并通過改變脈寬來改變蜂鳴器發聲的頻率。下面的程序就是利用PWM來驅動蜂鳴器,脈寬從低到高,再從高到低,周而復始。我們還利用4個LED來指示頻率的高低,最高時LED全亮,最低時LED全滅。并且我們用兩個按鈕來分別暫停蜂鳴器和重新開啟蜂鳴器:

        #define _ISR_STARTADDRESS 0x33ffff00

        #define U32 unsigned int
        typedef unsigned char BOOL;
        #define TRUE1
        #define FALSE0

        #define pISR_EINT0(*(unsigned *)(_ISR_STARTADDRESS+0x20))
        #define pISR_EINT1(*(unsigned *)(_ISR_STARTADDRESS+0x24))

        #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 rGPFCON(*(volatile unsigned *)0x56000050)//Port F control

        #define rEXTINT0(*(volatile unsigned *)0x56000088)//External interrupt control register 0

        #define rTCFG0(*(volatile unsigned *)0x51000000)//Timerconfiguration
        #define rTCFG1(*(volatile unsigned *)0x51000004)//Timerconfiguration
        #define rTCON(*(volatile unsigned *)0x51000008)//Timer control
        #define rTCNTB0 (*(volatile unsigned *)0x5100000c)//Timer count buffer 0
        #define rTCMPB0 (*(volatile unsigned *)0x51000010)//Timer compare buffer 0

        BOOL stop;

        static void __irq Key1_ISR(void)//暫停鍵,關閉蜂鳴器
        {
        rSRCPND = rSRCPND | (0x1<<1);
        rINTPND = rINTPND | (0x1<<1);

        rTCON &= ~0x8;//禁止定時器自動重載,即關閉定時器
        stop = TRUE;
        }

        void __irq Key4_ISR(void)//重啟鍵,開啟蜂鳴器
        {
        rSRCPND = rSRCPND | 0x1;
        rINTPND = rINTPND | 0x1;

        stop = FALSE;
        }


        void delay(int a)
        {
        int k;
        for(k=0;k;
        }

        void Main(void)
        {
        int freq;

        rGPBCON = 0x155556;//B0為TOUT0,B5~B8為輸出,給LED
        rGPBUP= 0x7ff;
        rGPFCON = 0xaaaa;//F口為EINT,給按鈕
        //按鈕的一些必要配置
        rSRCPND = 0x07;
        rINTMSK = ~0x07;
        rINTPND =0x07;
        rEXTINT0 = 0x22;

        freq = 2500;

        rTCFG0 &= 0xFFFF00;
        rTCFG0 |= 0x31;//prescal是49
        rTCFG1 &= ~0xF;//1/2,因為PCLK為50MHz,所以50MHz/50/2=500kHz
        rTCNTB0 = 5000;
        rTCMPB0 = freq;
        rTCON &= ~0x1F;
        rTCON |= 0xf;//死區無效,自動裝載,電平反轉,手動更新,定時器開啟
        rTCON &= ~0x2 ;//手動更新位清零,PWM開始工作

        pISR_EINT0 = (U32)Key4_ISR;
        pISR_EINT1 = (U32)Key1_ISR;

        stop = FALSE;

        rGPBDAT = ~0x60;//兩個LED亮

        while(1)
        {
        //頻率遞增
        for ( ; freq<4950 ; )
        {
        freq+=10;
        rTCMPB0 = freq;//重新賦值
        delay(20000);

        while (stop == TRUE)//暫停
        {
        delay(1000);
        if (stop ==FALSE)//判斷是否重啟
        {
        rTCON &= ~0x1F;
        rTCON |= 0xf;
        rTCON &= ~0x2 ;//恢復PWM功能
        }
        }
        //4個LED隨著頻率的高低,時滅時亮
        if(freq == 100)
        rGPBDAT = ~0x1e0;
        if(freq == 1300)
        rGPBDAT = ~0xe0;
        if(freq == 2500)
        rGPBDAT = ~0x60;
        if(freq == 3700)
        rGPBDAT = ~0x20;
        if(freq == 4900)
        rGPBDAT = ~0x0;

        }

        //頻率遞減
        for( ; freq>50 ; )
        {
        freq-=10;
        rTCMPB0 = freq;
        delay(20000);
        while (stop == TRUE)
        {
        delay(1000);
        if (stop ==FALSE)
        {
        rTCON &= ~0x1F;
        rTCON |= 0xf;
        rTCON &= ~0x2 ;
        }
        }
        if(freq == 100)
        rGPBDAT = ~0x1e0;
        if(freq == 1300)
        rGPBDAT = ~0xe0;
        if(freq == 2500)
        rGPBDAT = ~0x60;
        if(freq == 3700)
        rGPBDAT = ~0x20;
        if(freq == 4900)
        rGPBDAT = ~0x0;
        }
        }
        }

        這里還需要說明幾點:

        1、開發板上的蜂鳴器是高電平發聲,低電平停止,而TOUT0定時無效時,是高電平輸出,因此為了使PWM無效時,蜂鳴器不發聲,我把輸出電平進行了反轉處理(置TCON中的輸出反轉位);

        2、在這里,我是通過按鍵把stop標志變量置為FALSE來跳出while循環,重新開始蜂鳴,但不知什么原因,如果在while循環內不加一段等待時間,則永遠不能跳出循環體,因此我不得不加了一個delay函數,讓它等待一段時間。關于這個問題,我還給不出一個滿意的解釋,也不知是哪里出了問題!


        關鍵詞: s3c2440PWM應

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 全南县| 珲春市| 平和县| 裕民县| 稷山县| 岳池县| 六安市| 柳江县| 安阳市| 渝北区| 麻江县| 乐至县| 若羌县| 泽普县| 麻栗坡县| 阳高县| 敖汉旗| 深圳市| 枝江市| 始兴县| 铁力市| 长海县| 尖扎县| 德令哈市| 黎平县| 顺昌县| 石楼县| 德阳市| 锦州市| 久治县| 邓州市| 手游| 贞丰县| 体育| 兴安县| 景东| 苏尼特左旗| 苗栗市| 昌黎县| 泰兴市| 邵武市|