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

2017-03-24  本文已影响264人  Murrey_Xiao

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

1. 对于动态数码管

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

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

2. 电路图

动态数码管电路图

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

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

3. 51 C编程

#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;
}
无消隐 消隐

二、配合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. 编程

#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三个引脚,其他引脚不应该去改动它们原本的值,故作以下改进:

#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;
}
最终显示

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

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;
}

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

待解决。。。

上一篇 下一篇

猜你喜欢

热点阅读