主要有2个功能:
1定时
2计时
在我们开发板上有5个pwm定时器。TIMER0到TIMER4。
其中TIMER4是没有输出的,作为内部时钟使用。而其他四个是GPB0~3的复用引脚功能。
四个中TIMER0还有个叫死区发生器的东西,用来对大功率的外设来限流的。
再提一个概念。叫占空比。即一个周期内高电平占总的电平时间的比率。这个就是我们说的脉宽调制。
现在来分析内部结构。
定时器用的是PCLK的时钟,我们的开发板PCLK是50Mhz。这个频率太高了,速度太快了,不方便我们计时。所以我们内部有2个分平器。
第一个分屏器是Timer0和1共享的。另外一个是3,4,5共享。可以分成1/2~1/16 。第2个分屏器是8位。每个定时器都有单独的。
之后。
再来介绍下内部的计数方法。内部有两个寄存器,TCNT 是计数递减的 减到0会重新reload TCNTB中的值 TCMP是当TCNT中的值与TCMP的值相同时,高低电平要颠倒。这个就是调节占空比的方法。而TCNT到0的时候 TCMP也会去reload 不过load的是TCMPB中的值。
计算时间的公式:例如我们要算0.5s
0.5*( PCLK / (prescale*devide) ) = TCNTB
注意在第一次开始计数的时候,需要手动导入TCNT的值。
步骤如下:
1设置数值到TCNTB
2打开手动更新位
3打开自动更新为和使能PWM位。
以下写个程序:
用PWM的实现小灯0.5秒闪,0.5秒暗。分屏1是1/4 分屏2是100 计数是0xffff。
以下是pwm.c
#include"s3c2440.h"
void init_led()
{
rGPECON = GPE12_out|GPE13_out;
}
void init_timer0()
{
rTCFG0 = 0x63;
rTCFG1 = 0x1;
rTCNTB0 = 0xFFFF;
rTCON = 0xa; //手动载入
rTCON = 0x9; //自动载入
}
void init_irq()
{
rINTMOD = 0;
rINTMSK = ~(1<<10); //设置了计数器TIMER0的屏蔽位打开。
}
int main()
{
init_led();
init_irq();
init_timer0();
while(1);
}
以下是中断服务程序:
#include"s3c2440.h"
void ISR_Handle()
{
rGPEDAT ^= (3<<12); //用异或的方式可以实现执行一次点亮再执行一次灭灯
rSRCPND = 1<<10; //清中断
rINTPND = 1<<10;
}
其他makefile crt0.s pwm.lds s3c2440.h 文件省略。
整个程序还是比较简单的。
但是我们并没有利用到它的PWM功能。因为我们的引脚并没有连接到其他外设上,而是在GPB0~3复用的位置。所以要利用PWM,我们只能采用模拟的方法。例如下面写了一个利用小灯交替闪烁的方法,制造出小灯渐渐变亮和小灯渐渐变暗的视觉。
#include"s3c2440.h"
void init_led()
{
rGPECON = 5<<24;
}
void delay()
{
long i=200;
do{
i--;
}
while(i>0);
}
void pwm_like(int duty) delay(); int main()
{
int i,j;
rGPEDAT = 0;
for(i=0;i
rGPEDAT = 3<<12;
for(j=0;j<100-duty;j++)
delay();
}
{
init_led();
while(1){
int duty1=0;
int duty2=100;
while(duty1<=100){
pwm_like(duty1); //这边是控制占空比从0到100
duty1++;
}
while(duty2>=0){
pwm_like(duty2);
duty2--;
}
}
return 0;
}
上一篇:第5课:ARM的中断
下一篇:第7课:DMA
推荐阅读最新更新时间:2024-03-16 15:03