传统数码管动态驱动程序的改进
科学人2011/12/25电子技术 IP:北京
    /*本贴纯属原创,如有雷同不胜荣幸*/
    这是用C51编写的数码管动态显示驱动程序:


#include"reg51.h"

#define uchar unsigned char    
#define uint unsigned int

sbit duan=P2^0;    
sbit wei=P2^1;    

void delay(uint);

uchar code numbers[]=
{
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};

void main()
{
    while(1)
    {
        duan=1;    
        P1=numbers[1];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xfe;
        wei=0;
        delay(10);
        duan=1;    
        P1=numbers[2];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xfd;
        wei=0;
        delay(10);

        duan=1;    
        P1=numbers[3];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xfb;
        wei=0;
        delay(10);

        duan=1;    
        P1=numbers[4];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xf7;
        wei=0;
        delay(10);

        duan=1;    
        P1=numbers[5];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xef;
        wei=0;
        delay(10);

        duan=1;    
        P1=numbers[6];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xdf;
        wei=0;
        delay(10);

        duan=1;    
        P1=numbers[7];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0xbf;
        wei=0;
        delay(10);

        duan=1;    
        P1=numbers[8];
        duan=0;
        P1=0xff;
        wei=1;
        P1=0x7f;
        wei=0;
        delay(10);
    }
}

void delay(uint a)
{
    uchar b;
    uint c;
    for(c=a;c>0;c--)
        for(b=200;b>0;b--);
}
    
   乍一看好像没什么问题,这不就是书上的例程吗?不错,这就是在书上、网上能够找到的最普遍的使用锁存器驱动数码管的C程序,大家已经很习惯了。
    如果我告诉你还有比它更好的程序,你会不会很惊讶?不用惊讶,下面请看我的分析。
    为了使显示清晰,设计者加入了“消影”。想必大家已经知道“消影”的概念了:在送完段选数据之后,I/O 口仍然保持该状态。若直接打开位选,原来的段选数据就会被送入位选,虽然持续时间短暂,但在高速显示的状态下仍会相互重叠,产生“影子”。加上消影后,使I/O 口在位选打开之前变成FF,这样哪一位也不会亮,“影子”问题也就解决了。
    问题真的解决了吗?我们将这个程序下载至单片机:嗯,比不加消影好多了,可是还感觉不太稳定,能不能把延时调短呢?将延时调短,下载至单片机,效果如图所示。
IMG_0062.jpg
   重影出现了,它从哪里来呢?原因如下:段选打开之后,上次的位选还没有清除,虽然单片机反应很快,但延时的减少使其在高速下变得非常明显。
    针对以上问题,本人编写了一个程序,既能保证数码管显示流畅,又解决了所有重影问题:

#include"reg51.h"    //头文件

#define uchar unsigned char    //宏定义
#define uint unsigned int

sbit duan=P2^0;    //段选端
sbit wei=P2^1;    //位选端

void delay(uint);    //延时函数声明

uchar code numbers[]=    //数码数组
{
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};

void main()
{
    while(1)
    {
        P1=numbers[1];
        duan=1;        //数据入锁存
        duan=0;
        P1=0xfe;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;    //11111111
        wei=1;
        wei=0;
        P1=numbers[2];
        duan=1;
        duan=0;
        P1=0xfd;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;
        wei=1;
        wei=0;
        P1=numbers[3];
        duan=1;
        duan=0;
        P1=0xfb;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;
        wei=1;
        wei=0;
        P1=numbers[4];
        duan=1;
        duan=0;
        P1=0xf7;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;
        wei=1;
        wei=0;
        P1=numbers[5];
        duan=1;
        duan=0;
        P1=0xef;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;
        wei=1;
        wei=0;
        P1=numbers[6];
        duan=1;
        duan=0;
        P1=0xdf;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;
        wei=1;
        wei=0;
        P1=numbers[7];
        duan=1;
        duan=0;
        P1=0xbf;
        wei=1;
        wei=0;
        delay(10);

        P1=0xff;
        wei=1;
        wei=0;
        P1=numbers[8];
        duan=1;
        duan=0;
        P1=0x7f;
        wei=1;
        wei=0;
        delay(10);
    }
}

void delay(uint a)
{
    uchar b;
    uint c;
    for(c=a;c>0;c--)
        for(b=10;b>0;b--);    //数值越小,亮度越低。
}
  
[size=4][color=#FF9900]原理就不说了,大家都看得懂吧。有一点需要注意:延时并非越短越好,因为单片机每次关闭输出需要一定时间,延时太短会降低占空比,导致亮度减弱。
对比如图:
[/size] IMG_0061.jpg
   总之,大家在学习时不要迷信权威,要勤动脑,这样才能把别人的知识变成自己的。
+100  科创币    ehco    2011/12/25 动态scan中,必须有消隐,尤其在LED点阵应用上。
+100  科创币    1989sean    2011/12/25
+100  科创币    delete    2011/12/25 支持下,做过LED阵列屏的深有体会......
+1  学术分    虎哥    2011/12/25 大神辛苦了。
来自:电子信息 / 电子技术
10
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
1989sean
13年2个月前 IP:未同步
347752
教科书上的例程都是互相抄,抄错了都不知道...还得让看书的人自己改...
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
jrcsh
13年2个月前 IP:未同步
347754
数码管利用状态标记+程序流程上的占用代替,亮度保护保持时间,提升运行效率.

#include<reg52.h>
#define uchar unsigned char
#define uint  unsigned int
sbit w1=P2^4;
sbit w2=P2^5;
sbit w3=P2^6;
sbit w4=P2^7;
unsigned int bbb,aaa,smg,ccc;
uchar code table[]={0x28,0xeb,0x32,0xa2,0xe1,0xa4,0x24,0xea,0x20,0xa0,0xff};
void delay()
{
   for(bbb=0;bbb<250;bbb++)
  {
;
}
}
void smg_xs()
{
smg++;
if(smg==5)
{
smg=1;
}
if(smg==1)
{
w2=w3=w4=1;
P0=table[aaa%10];
w1=0;
}
if(smg==2)
{
w1=w3=w4=1;
P0=table[aaa/10%10];
w2=0;
}
if(smg==3)
{
w1=w2=w4=1;
P0=table[aaa/100%10];
w3=0;
}
if(smg==4)
{
w1=w2=w3=1;
P0=table[aaa/1000%10];
w4=0;
}
}
void main()
{
smg=0;
aaa=1234;
ccc=0;
while(1)
{
smg_xs();
delay();
delay();//#%%%¥#%¥@%@¥#%#@
ccc++;
if(ccc>30)
{
ccc=0;
aaa++;
}
if(aaa>9999)
{
aaa=0;
}
}
}



delay(10);
估计要是10ms 的话 因当消耗了 10000个左右的指令周期 ,  以上程序着是利用上这些时间,处理其它任务,在加上自己的循环
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
科学人作者
13年2个月前 IP:未同步
347755
回 2楼(jrcsh) 的帖子
谢谢!我的方法还是以牺牲亮度和资源为代价的。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
jrcsh
13年2个月前 IP:未同步
347767
效率和亮度上还能在改进,你这样的消影的确会浪费去一定亮度
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
ldc
13年2个月前 IP:未同步
347788
每位数码管用一个74LS373,解放CPU
+1
科创币
jrcsh
2011-12-26
神人阿~~··潜伏多年认个数码管给炸出水面了
+1
科创币
科学人
2011-12-26
一堆595级联~
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
神之觉醒
13年2个月前 IP:未同步
347809
[s:225] 和我刚学用程序刷数码管时候的症状一样!!! 后来才发现不能连续刷  要隔一个程序周期切换刷才不拖影[s:223]
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
wacke
13年2个月前 IP:未同步
347819
我也来发一个吧。我自己用的LED的驱动程序,Freescale 08 的片子,改一下就可以用到51上。主要大家看一下思路。
使用一个定时中断,并用了一个缓冲。这样做想显示什么都很方便了。而且点用CPU的资源很少。
其实只要加几个函数就可以显示数字,字符,字符串都可以。

#define LEDNUM    8

uhar uLedBuf[LEDNUM];

void InitLed(void)
{
    memset(uLedBuf,' ',LEDNUM);
    T1MOD = 0x01000;
}

void interrupt 7 LedDrv(void)    //10ms
{
    static uchar i = 0;
    static uchar bBit = 0x01;
    if(i >= LEDNUM){
        i = 0;
        bBit = 0x01;
    }
    PTC = 0;
    PTD = uLenBuf[i];
    PTC = bBit;
    bBit <<= 1;
    i++;
    T1SC_TOF = 0;        //清中断标志
}

void Dis(uchar uBit, char Ch)
{
    if(uBit >= LEDNUM)
        return;
    uLedBuf[uBit] = Ch;
}

void DisNum(uint n)
{
    sprintf(uLedBuf,"%d",n);
    return;
}
+1
科创币
科学人
2011-12-26
我的程序是原型,说明原理而已
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
jxs
13年2个月前 IP:未同步
347855
要是我不用(没有)锁存器,应该怎样弄呢?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
caoyuan9642
13年2个月前 IP:未同步
347894
用个锁存器多好。。。。。。
这样单片机负载太大搞不了复杂的运算了就
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
科学人
学者 笔友
文章
178
回复
1739
学术分
1
2011/07/24注册,7年0个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}