Donald's BLOG

回忆是一缕淡淡的月光,握紧了便成黑暗

« 自制LED条屏广告清明后 »

自制LED条屏 - 条屏驱动

Donald用的条屏,它采用串行移位方式,内部用的是74LS595。再加上行选择信号和地信号,一共有二十根信号线。如下:

2   NC  RD  S  L   OE  A  B  C   D   N 20

1   N   N   N  N   N   N  N  N   N   N 19

其中,RD是数据,S是时钟,L是锁存,OE是使能,ABCD是16行的地址信号,N是接地。

诸昌钤的《LED显示屏系统及工程技术》中提到,对于串行传输方式来说,列数据准备时间可能相当长,在行扫描周期确定的情况下,留给行显示的时间就太少了,以至影响到LED亮度。解决串行传输中列数据准备和列数据显示的时间矛盾问题,可以采用重叠处理方法。即在显示本行各列数据的同时,准备下一行的数据。为了达到重叠处理的目的,列数据的显示就需要具有锁存功能。

Donald的这个LED板,硬件设计原理,就是按这种思路来的,虽然只是64x16,不大,但电路是现成的,按专家的这个思路来编驱动软件,将具有更强的扩展性。

Donald让51单片机的串行口工作在方式0,这样就是同步串行方式,RXD为数据,TXD为时钟,分别接LED条屏的RD和S信号。只要对SBUF操作就行了。

对于64x16的显示大小,Donald用了一个全局变量来作为一行显示的缓存:
uchar g_ucLineBuf[8]

这样,一个函数就实现将一行数据串行移入到LED条屏的寄存器里:
void OutLineBuf()
{
    char i;
    for(i = 0; i < 8; i++){
        SBUF = g_ucLineBuf[i];
        while(TI == 0);        // Wait for sending complite.
        TI = 0;
    }
}

要显示一屏的图文,就需要结合地址线来显示,按一定顺序(从上到下,或从下到上)将每行的数据输出到LED屏上,并加上必要延时,使图像清晰。

如下,是Donald的静态显示一屏的函数。
/**************************************************************
Name: DispPage(uchar ucPage, uchar ucEft, uchar ucTime)
Func:
    Display a page of data. Just a LED screen. But not include
    the switching to the next.
Para:
    uchar ucPage: the number of the page.(是页号,我已经将每页的数据存在CODE段里了)
    uchar ucEft: the effect of displaying the page(显示效果,有闪烁,反转,全亮,全灭)
    uchar ucTime: the showing time(显示的时间,定时器定时单位的个数,我是按0.2秒一个单位)
Return: Null
**************************************************************/
void DispPage(uchar ucPage, uchar ucEft, uchar ucTime)
{
    char i, k;
    uint addrSrc;

    if(ucTime == 0) return;

    g_ucShowTime = ucTime;    // 一个全局变量,在定时器中断里修改
    TR0 = 1;    // Start timer0
   
    while(g_ucShowTime){
        if((ucEft == DISP_EFT_BLINK) && (g_ucBlink > 4)){
            LED_E = 1;
        }
        else{
            addrSrc = ucPage * 128;    // 每一屏显示数据的起始地址
   
            for(i = 0; i < 16; i++){ // 16行的显示
                for(k = 0; k < 8; k++){
                    if(ucEft == DISP_EFT_CLEAR){        // All Led dark
                        g_ucLineBuf[k] = 0xff;
                    }
                    else if(ucEft == DISP_EFT_ALL){        // All Led bright
                        g_ucLineBuf[k] = 0x00;
                    }
                    else{
                        g_ucLineBuf[k] = ucDataSrc[addrSrc + i * 8 + k];
                        if(ucEft == DISP_EFT_REVERSE){        // Reverse
                            g_ucLineBuf[k] = ~g_ucLineBuf[k];
                        }
                    }
                }
   
                OutLineBuf();
                LED_E = 1;
                LED_AD = i << 4;
                LED_L = 0;                    // Low to High, 595 Lock signal
                LED_L = 1;
                LED_E = 0;
                delay();
            }
        }
    }
    TR0 = 0;    // Stop timer0
}

上述函数显示每一行的思路是这样的,先将第一行的数据准备好放在输出缓存g_ucLineBuf里,然后调用OutLineBuf()函数输出,这时,数据还在595的寄存器里,还没最后显示。接着,不让LED条屏显示,设好地址后,通过一个由低到高的锁存信号,将数据锁存到595的输出端,再将LED条屏使能,数据就显示出来了,加上必要延时,使图像清晰。

为什么准备地址(即行信号)时要先禁止LED条屏再使用使之显示,因为开始时Donald没有这么做,发现屏幕有鬼影,原因就是串行输出数据后准备地址,这个执行过程有相当短暂的时间,会将原来上一行数据短暂残留在本行,产生鬼影。通过使用端的应用,就能避免这个问题。

当然,除了静态显示,还有切换过程的显示,只需使用一定算法,将下一个页要显示的数据准备在g_ucLineBuf输出缓存中就行了。这样,就有了如下左右移动切换和上下移动切换的函数。
void DispSwitchLR(uchar ucPageNo, uchar ucEft, uchar ucTime);
void DispSwitchUD(uchar ucPageNo, uchar ucEft, uchar ucTime);

最后,编写一个总的显示函数void Display(uchar ucPage),通过调用DispPage()、DisSwitchLR()和DispSwitchUD函数,就实现将每一页按闪烁,反转的方式显示一段自己设好的时间,再以左右移动,上下移动,或直接切换的方式切换到下一页。

每一页的显示时间和切换方式都存在CODE段的ucPageInfo[]中,每一页的显示数据放在CODE段的ucDataSrc[]中。

下面这个简单的程序是Donald编来生成ucPageInfo信息的。
  • quote 1.Greeze
  • 你好,我现在正在研究显示屏,想问你份扩展成8字动态显示屏的程序.我的邮箱hanfan320@yahoo.com.cn,谢谢
  • 2008-4-6 8:55:59 回复该留言

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Powered By Z-Blog 1.7 Laputa Build 70216

Adore designed by Donald
Copyright Donald.net.cn Some Rights Reserved.
辽ICP备08001691号