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函数,让它等候一段时刻。关于这个问题,我还给不出一个满足的解说,也不知是哪里出了问题!