s3c2440的PWM應(yīng)用
s3c2440芯片中一共有5個(gè)16位的定時(shí)器,其中有4個(gè)定時(shí)器(定時(shí)器0~定時(shí)器3)具有脈寬調(diào)制功能,因此用s3c2440可以很容易地實(shí)現(xiàn)PWM功能。下面就具體介紹如何實(shí)現(xiàn)PWM功能。
1、PWM是通過引腳TOUT0~TOUT3輸出的,而這4個(gè)引腳是與GPB0~GPB3復(fù)用的,因此要實(shí)現(xiàn)PWM功能首先要把相應(yīng)的引腳配置成TOUT輸出。
2、再設(shè)置定時(shí)器的輸出時(shí)鐘頻率,它是以PCLK為基準(zhǔn),再除以用寄存器TCFG0配置的prescaler參數(shù),和用寄存器TCFG1配置的divider參數(shù)。
3、然后設(shè)置脈沖的具體寬度,它的基本原理是通過寄存器TCNTBn來對(duì)寄存器TCNTn(內(nèi)部寄存器)進(jìn)行配置計(jì)數(shù),TCNTn是遞減的,如果減到零,則它又會(huì)重新裝載TCNTBn里的數(shù),重新開始計(jì)數(shù),而寄存器TCMPBn作為比較寄存器與計(jì)數(shù)值進(jìn)行比較,當(dāng)TCNTn等于TCMPBn時(shí),TOUTn輸出的電平會(huì)翻轉(zhuǎn),而當(dāng)TCNTn減為零時(shí),電平會(huì)又翻轉(zhuǎn)過來,就這樣周而復(fù)始。因此這一步的關(guān)鍵是設(shè)置寄存器TCNTBn和TCMPBn,前者可以確定一個(gè)計(jì)數(shù)周期的時(shí)間長度,而后者可以確定方波的占空比。由于s3c2440的定時(shí)器具有雙緩存,因此可以在定時(shí)器運(yùn)行的狀態(tài)下,改變這兩個(gè)寄存器的值,它會(huì)在下個(gè)周期開始有效。
4、最后就是對(duì)PWM的控制,它是通過寄存器TCON來實(shí)現(xiàn)的,一般來說每個(gè)定時(shí)器主要有4個(gè)位要配置(定時(shí)器0多一個(gè)死區(qū)位):啟動(dòng)/終止位,用于啟動(dòng)和終止定時(shí)器;手動(dòng)更新位,用于手動(dòng)更新TCNTBn和TCMPBn,這里要注意的是在開始定時(shí)時(shí),一定要把這位清零,否則是不能開啟定時(shí)器的;輸出反轉(zhuǎn)位,用于改變輸出的電平方向,使原先是高電平輸出的變?yōu)榈碗娖?,而低電平的變?yōu)楦唠娖?;自?dòng)重載位,用于TCNTn減為零后重載TCNTBn里的值,當(dāng)不想計(jì)數(shù)了,可以使自動(dòng)重載無效,這樣在TCNTn減為零后,不會(huì)有新的數(shù)加載給它,那么TOUTn輸出會(huì)始終保持一個(gè)電平(輸出反轉(zhuǎn)位為0時(shí),是高電平輸出;輸出反轉(zhuǎn)位為1時(shí),是低電平輸出),這樣就沒有PWM功能了,因此這一位可以用于停止PWM。
PWM有很多用途,在這里我利用開發(fā)板的資源,用它來驅(qū)動(dòng)蜂鳴器,并通過改變脈寬來改變蜂鳴器發(fā)聲的頻率。下面的程序就是利用PWM來驅(qū)動(dòng)蜂鳴器,脈寬從低到高,再從高到低,周而復(fù)始。我們還利用4個(gè)LED來指示頻率的高低,最高時(shí)LED全亮,最低時(shí)LED全滅。并且我們用兩個(gè)按鈕來分別暫停蜂鳴器和重新開啟蜂鳴器:
#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)//暫停鍵,關(guān)閉蜂鳴器
{
rSRCPND = rSRCPND | (0x1<<1);
rINTPND = rINTPND | (0x1<<1);
rTCON &= ~0x8;//禁止定時(shí)器自動(dòng)重載,即關(guān)閉定時(shí)器
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,因?yàn)镻CLK為50MHz,所以50MHz/50/2=500kHz
rTCNTB0 = 5000;
rTCMPB0 = freq;
rTCON &= ~0x1F;
rTCON |= 0xf;//死區(qū)無效,自動(dòng)裝載,電平反轉(zhuǎn),手動(dòng)更新,定時(shí)器開啟
rTCON &= ~0x2 ;//手動(dòng)更新位清零,PWM開始工作
pISR_EINT0 = (U32)Key4_ISR;
pISR_EINT1 = (U32)Key1_ISR;
stop = FALSE;
rGPBDAT = ~0x60;//兩個(gè)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 ;//恢復(fù)PWM功能
}
}
//4個(gè)LED隨著頻率的高低,時(shí)滅時(shí)亮
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;
}
}
}
這里還需要說明幾點(diǎn):
1、開發(fā)板上的蜂鳴器是高電平發(fā)聲,低電平停止,而TOUT0定時(shí)無效時(shí),是高電平輸出,因此為了使PWM無效時(shí),蜂鳴器不發(fā)聲,我把輸出電平進(jìn)行了反轉(zhuǎn)處理(置TCON中的輸出反轉(zhuǎn)位);
2、在這里,我是通過按鍵把stop標(biāo)志變量置為FALSE來跳出while循環(huán),重新開始蜂鳴,但不知什么原因,如果在while循環(huán)內(nèi)不加一段等待時(shí)間,則永遠(yuǎn)不能跳出循環(huán)體,因此我不得不加了一個(gè)delay函數(shù),讓它等待一段時(shí)間。關(guān)于這個(gè)問題,我還給不出一個(gè)滿意的解釋,也不知是哪里出了問題!
評(píng)論