第一次接触PWM脉宽调制,终于实现了LED背光板的渐亮渐灭,把代码贴出来。一则请大家指点,二则把实现的思想跟新人分享。
/*****************************************************************************
硬件说明:
AT89S52,晶振11.0592MHz。P3.6为一个LED背光板,等于0时发光。
P0.0为一个按键,按下时为0。
*****************************************************************************/
/******************************************************************************
程序思路说明:
LED背光板的渐亮渐灭实际上就是LED的亮度等级由低到高(渐亮)再由高到低(渐灭)的
过程,那么首先要通过PWM脉宽调制实现LED显示不同的亮度等级。(脉宽调制的基本原理
可以参考http://hi.baidu.com/gdmgb520/blog/item/077f0601810d1a047bec2cb7.html)
怎么实现不同的亮度等级呢?假设在某个长度的周期(一个适当的时间长度)内如果LED
的管脚一直输出0(我这里输出0时LED背光板点亮),那么很显然LED肯定是最亮的;相
反如果一直输出1,那LED肯定是最暗的(也就是不亮)。如果在这个周期内管脚输出的是
脉冲波(10101010……)那么LED的亮度就只有最亮时的一半,或者说如果前一半时间是
高电平后一半时间是低电平,那LED的亮度也是最亮的一半,这是由于LED的余晖效应,但
这个时间必须恰当,不然LED就不是亮而是闪烁。下面这段代码即可实现LED显示在某个亮度
等级:
void timer0(void) interrupt 1 using 2
{
static uchar counter=0; //中断次数计数器变量
TH0=V_TH0; //恢复定时器初始值
TL0=V_TL0;
counter++;
if (counter<=(ZKB1)) //当小于占空比值时输出低电平,高于时是高电平,从而实现占空比的调整
{LED3=0;}
else
{LED3=1;}
if (counter==100)
{counter=0;}
}
那么现在我们就可以依次变换LED的亮度等级,从而实现LED的渐亮渐灭了。若上面的定时器
中断是0.1ms触发一次、ZKB1=20,那么整个周期为0.1ms*100=10ms,LED3为低脉冲的时间
长度为20*0.1ms=2ms,显示亮度为最亮的20%。如果我们把100个不同的亮度等级挨个显示
一遍就出现了有暗到亮的渐亮过程或渐灭过程。那么我们就在每当counter==100的时候,
ZKB1++就行了(由暗到亮)。上面的程序第24行{}内加入ZKB1++;,并在第25行加入
if (ZKB1==100) ZKB1=0; 语句即可。这样看到的效果是LED由暗变亮然后又有暗变亮。
现在我们再加入由亮变暗。新增一个变量ZKB2,counter==100时ZKB2++,当ZKB2<=100
时ZKB1=ZKB2,实现有暗变亮;当100<ZKB2<=200时ZKB1=200-ZKB2,实现由亮变暗;当
200<ZKB2<=400时ZKB1=0,LED保持熄灭。从时间上来说,每一个亮度等级耗时10ms,那
么渐亮耗时1s,渐灭耗时1s,熄灭保持2s,然后开始下一个周期。
这里我还加了一个flag0变量,作用是当K0按下时使LED停止发光。
******************************************************************************/
#include <REG52.H>
#define uchar unsigned char
#define V_TH0 0xff //定时器0初值
#define V_TL0 0xa3
sbit LED3=P3^6; ///背光片接口
sbit K0=P0^0;
unsigned char ZKB1,ZKB2;
bit flag0;
/*-------------------------定时器初始化-----------------------------------*/
void init_sys(void)
{
TMOD=0x01; //定时器0工作在方式1
TH0=V_TH0; //定时周期为0.1ms
TL0=V_TL0;
TR0=1;
ET0=1;
EA=1;
}
/*-----------------------定时器0中断函数---------------------------------*/
void timer0(void) interrupt 1 using 2
{
static uchar counter=0; //中断次数计数器变量
TH0=V_TH0; //恢复定时器初始值
TL0=V_TL0;
if (flag0==1)
{
counter++;
if (counter>=100)
{
counter=0;
ZKB2++;
if (ZKB2<=100) //占空比变化部分
{ ZKB1=ZKB2;}
else if (ZKB2<=200)
{ ZKB1=200-ZKB2;}
else
{ ZKB1=0;}
}
if (counter<=(ZKB1)) //当小于占空比值时输出低电平,高于时是高电平,从而实现占空比的调整
LED3=0;
else
LED3=1;
if (ZKB2>399) ZKB2=1;
}
else
{
LED3=1;
}
}
/*------------------------------主函数-------------------------------------*/
void main (void)
{
init_sys();
while(1)
{
P0=0xff;
flag0=K0;
}
}
/***************************************************************************
小结:这里定时器的定时长度需要根据具体情况作出适当调节
****************************************************************************/
测试-LED3.rar
(18.14 KB)
|