美文网首页
51单片机、动态数码管认识与编程

51单片机、动态数码管认识与编程

作者: Murrey_Xiao | 来源:发表于2017-03-24 18:08 被阅读264次

    一、根据电路图实现动态数码管

    1. 对于动态数码管

    首先需要知道的是,动态数码管是一种对数码管的实现方式,并不是数码管的种类,静态数码管也是一种实现方式,所以说,静动态的数码管内部结构没有差异。

    动态数码管常见于对多个数码管进行编程,采用扫描方式对各个数码管给源给码(源可以理解成电源,码可以理解成段码,段码即显示的内容),再通过单片机CPU的高速循环,使各个数码管得以同时呈现不同的数字。

    2. 电路图

    动态数码管电路图

    可以看到,该8位数码管是通过J16给源,J12给码的方式来实现数码管的亮灭。电路图中,数码管将8个LED灯的引脚全部接到了J12口的八根线上,统一给码,再通过J16来控制。由于是共阴极数码管,故当J16对某一位给0时,该位对应的数码管则亮。

    注:74573本身是个锁存器,但在这个电路中没有用到锁存功能,只是简单的当作功放来用,用来驱动发光管的功率放大。

    3. 51 C编程

    • 这里使用P0口控制数码管的段码位,P2口控制数码管的COM口。
    #include <reg51.h>
    
    unsigned char screenNum[8]={1,3,5,7,2,4,6,8};
    
    void printNum(int i,int state)
    {
        //0123456789AbCDEF
        unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
        if(state==0) P0=num[i];     //共阳
        else P0=~num[i];        //共阴
    }
    int main()
    {
        unsigned char i;
        unsigned char j;
        while(1)
        {
            for(i=0;i<8;i++)
            {
                P2=~(1<<i);    // P2 接 J16 控制数码管的亮灭
                printNum(screenNum[i],1);    //显示数字
                j=8;
                while(j--) ;   //延时
                P0=0x0;        //消隐
            }
        }
        return 0;
    }
    
    • 注意:【消隐操作】在送出第N+1位的段码前,一定要先把第N位的位段码关闭,不然第N+1位的段码会在第N位有个短暂的残留。这个短暂的残留影象就是残影了。
    无消隐 消隐

    二、配合38译码器实现动态数码管

    1. 首先,什么是38译码器?

    74HC138

    38译码器有3个输入端口A、B、C和8个输出端口Y0~Y7。由输入端口控制输出端口的值。

    2. 为什么使用38译码器?

    使用38译码器来控制数码管的COM口可以节约IO口,其原理是:输入口的3位总共可以代表8个十进制数0-7,分别对应输出端口的8个引脚,使得38译码器实现以3个引脚控制八个输出端口,不过这样就造成8个端口无法同时被选中,一次只能选择一个端口,但是在实现动态数码管时可以使用它来控制COM口,因为在动态扫描过程中,要的就是一次只选择一个端口。

    3. 3个输入端口如何控制8个输出端口?

    查询74HC138芯片的数据手册,可找到芯片的译码表。

    译码表

    表中,Enable项已经初始化好了,我们只需要关心Select项中的A、B、C输入端口即可。

    4. 编程

    • 这里使用P0口控制数码管的段码位,P2口控制数码管的COM口。
    #include <reg51.h>
    
    unsigned char screenNum[8]={1,3,5,7,2,4,6,8};
    unsigned char placeArr[8]={0x0,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
    
    void printNum(int i,int state)
    {
        //0123456789AbCDEF
        unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
        if(state==0) P0=num[i];     //共阳
        else P0=~num[i];        //共阴
    }
    int main()
    {
        unsigned char i;
        unsigned char j;
        while(1)
        {
            for(i=0;i<8;i++)
            {
                P2 = placeArr[i];
                printNum(screenNum[i],1);
                j=100;
                while(j--) ;    
                P0=0x0; 
            }
        }
        return 0;
    }
    

    5. 改进

    考虑到控制38译码器只用到P2的P2.0、P2.1、P2.2三个引脚,其他引脚不应该去改动它们原本的值,故作以下改进:

    • 对P2.0、P2.1、P2.2三位清零,然后在循环中每次加一来改变其内的值。
    • 每扫描一排,则重新清零再次累加。
    #include <reg51.h>
    
    unsigned char screenNum[8]={1,3,5,7,2,4,6,8};
    
    void printNum(int i,int state)
    {
        //0123456789AbCDEF
        unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
        if(state==0) P0=num[i];        //共阳
        else P0=~num[i];        //共阴
    }
    int main()
    {
        unsigned char i;
        unsigned char j;
        while(1)
        {
            P2 &= 0xf8;
            for(i=0;i<8;i++)
            {
                printNum(screenNum[i],1);
                j=100;
                while(j--) ;    
                P0=0x0; 
                P2 += 1;    
            }
        }
        return 0;
    }
    
    • 注意:需要将P2+=1放到消隐之后,原因是:P2从000开始,若加1后再显示则会发生错位。
    最终显示

    三、【实例】使用动态数码管实现倒计时

    • 接线与上图相同

    1. 使用延时函数实现倒数间隔

    #include <reg51.h>
    
    unsigned char screenNum[8]={1,3,5,7,2,4,6,8};
    
    void printNum(int i,int state)
    {
        //0123456789AbCDEF
        unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
        if(state==0) P0=num[i];        //共阳
        else P0=~num[i];        //共阴
    }
    
    int main()
    {
        unsigned char i;
        unsigned char j;
        unsigned long count=10000;
        unsigned int timeCount=0;
        while(1)
        {
            unsigned long temp=count;
            for(i=0;i<8;i++)
            {
                screenNum[7-i]=temp%10;
                temp/=10;
            }
            P2 &= 0xf8;
            for(i=0;i<8;i++)
            {
                printNum(screenNum[i],1);
                j=100;
                while(j--) ;    
                P0=0x0; 
                P2 += 1;    
            }
            delay_ms(100);
            count--;
        }
        return 0;
    }
    

    烧录后发现,数字变化时会闪烁。

    经分析,应该是延时函数导致的,因为动态数码管需要不断扫描数码管,如果存在延时函数则会中断数字的显示。

    改进后使用一个计数器来实现近似延时,见2.

    2. 使用计数器实现倒数间隔

    #include <reg51.h>
    
    unsigned char screenNum[8]={0,0,0,0,0,0,0,0};
    
    void printNum(int i,int state)
    {
        //0123456789AbCDEF
        unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
        if(state==0) P0=num[i];        //共阳
        else P0=~num[i];        //共阴
    }
    
    int main()
    {
        unsigned char i;
        unsigned char j;
        unsigned long count=10000;
        unsigned int timeCount=0;
        while(1)
        {
            unsigned long temp=count;
            if(timeCount++>100)
            {
                for(i=0;i<8;i++)
                {
                    screenNum[7-i]=temp%10;
                    temp/=10;
                }
                timeCount=0;
                count--;
            }
            //P2接38译码器控制数码管COM口
            P2 &= 0xf8;      //P2.0-2置0
            for(i=0;i<8;i++)
            {
                printNum(screenNum[i],1);
                j=100;
                while(j--) ;      //延时
                P0=0x0; //消隐
                P2 += 1;     
            }
        }
        return 0;
    }
    

    这里还有两个问题:
    ①数字变化间隔不为真正的一秒
    ②数字变化时会轻微闪烁

    待解决。。。

    相关文章

      网友评论

          本文标题:51单片机、动态数码管认识与编程

          本文链接:https://www.haomeiwen.com/subject/ieyfottx.html