打印

PWM实现LED背光板渐亮渐灭 AT89S52

[复制链接]
12567|55
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gdmgb520|  楼主 | 2009-11-13 15:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
第一次接触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)

相关帖子

沙发
程序匠人| | 2009-11-13 16:00 | 只看该作者
鼓励一下

使用特权

评论回复
板凳
fover| | 2009-11-13 16:40 | 只看该作者
谢谢LZ的分享
然后再使劲的顶一下

使用特权

评论回复
地板
tigedtp| | 2009-11-13 20:16 | 只看该作者
这样闪背光灯闪烧了怎么办?

使用特权

评论回复
5
jweiok| | 2009-11-14 10:34 | 只看该作者
LS说的有道理

应该跟灯的品质好坏有关系。

使用特权

评论回复
6
leolle| | 2009-11-14 13:58 | 只看该作者
不错鼓励一下

使用特权

评论回复
7
lost1421| | 2009-11-14 14:55 | 只看该作者
鼓励一下是应该的,但是加条裤子就没有必要了。

使用特权

评论回复
8
bg6nw| | 2009-11-16 17:17 | 只看该作者
单片机还干其它的不干了?只顾着背光灯了

使用特权

评论回复
9
ningling_21| | 2009-11-16 22:25 | 只看该作者
8# bg6nw

当然还做别的,只亮背光有多大用?

使用特权

评论回复
10
gdmgb520|  楼主 | 2009-11-17 10:13 | 只看该作者
哈哈,谢谢大家鼓励,作为一个电子新人,论坛新人,得了条裤子,我太高兴啦。哈哈哈……以前玩什么游戏都没这么高兴过。O(∩_∩)O哈哈~
说正经的:
4L 说的背光板烧的问题,这我确实没考虑过。我这是初生牛犊不怕虎,根本就没意识到这样的危险,只见网上说用这个方法实现LED灯的渐亮渐灭,我也就试了试。
虽然在网上down了几个代码(就两个版本),但还是琢磨了一番才得到自己想要的效果的。首先我先看了匠人先生的手记里关于PWM的概括,然后又在网上搜了一些资料才明白了PWM的原理。
8L 说的资源的问题。我这个测试程序没有放到大工程里去用,我也不清楚到底是否可行。本来是老板提议搞个LED背光板的渐亮渐灭,我就调了代码,但后来还是没有放进去。所以我也不清楚到底是否可用。

使用特权

评论回复
11
woshiwml| | 2009-11-17 14:41 | 只看该作者
本帖最后由 woshiwml 于 2009-11-17 14:43 编辑

gg

使用特权

评论回复
12
zptonghua| | 2009-11-17 16:45 | 只看该作者
cpu怎么没干别的啊,没看见人家的用的是硬件定时器么,可不是软件延时啊!

使用特权

评论回复
13
暮然| | 2009-11-17 21:14 | 只看该作者
定时器中断里干活太多。其实利用定时器做一个系统时间片,系统会很清晰干脆的。
楼主加油,我们都是这样过来的。

使用特权

评论回复
14
ppsen| | 2009-11-17 21:54 | 只看该作者
楼主能不能搞个视频贴过来呀

使用特权

评论回复
15
gdmgb520|  楼主 | 2009-11-17 21:56 | 只看该作者
ls 能不能说一下系统时间片的大体原理,我在百度上搜了一下,没搞明白。
谢谢大家的鼓励。

使用特权

评论回复
16
暮然| | 2009-11-18 21:54 | 只看该作者
巧了,你那头像太贴切了。
假如,你设计一个一12小时的时间轮,那么设置12个时间片,每一个就是1小时。
那么:
1点钟:task1();
2点钟:task2();
3点钟:task3();
.........
12点钟:task12();

使用特权

评论回复
17
gdmgb520|  楼主 | 2009-11-19 13:21 | 只看该作者
呵呵!

谢谢讲解,估计我要找点这方面的书看看,可不可以推荐一下这方面的资料啊!

使用特权

评论回复
18
dspfans| | 2009-11-23 15:06 | 只看该作者
鼓励一下

使用特权

评论回复
19
leofoolish| | 2009-11-23 17:05 | 只看该作者
:lol牛人

使用特权

评论回复
20
gdmgb520|  楼主 | 2009-11-24 17:41 | 只看该作者
呵呵,今天看了匠人手记中对时间片的讲解,大体思路明白了。
我觉得匠人手记确实不错,我看了前面的几章,感觉很适合,他把一些常用的经验和技巧做了总结和概括,但是有没有面面俱到的讲,这样我们需要用的时候知道有这种方法,具体再查找相关资料。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:了解新东西才知道自己的不足。 www.elecbench.com

67

主题

452

帖子

1

粉丝