美文网首页
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单片机、动态数码管认识与编程

    一、根据电路图实现动态数码管 1. 对于动态数码管 首先需要知道的是,动态数码管是一种对数码管的实现方式,并不是数...

  • MHT5-交通灯套件

    功能介绍: 本套件是基于51单片机的交通灯模拟设计,通过对单片机编程,控制数码管显示和LED亮灭的变化。有深夜模式...

  • 11 动态数码管

    单片机STC89C52学习——11 动态数码管 汇总:00 单片机STC89C52学习参考教程:普中科技 1 工作...

  • 51单片机数码管的静态与动态显示

    姓名:冯子豪 学号:16020199001 转载自https://blog.csdn.net/qq_2748553...

  • 51单片机之数码管动态显示

    动态显示的原理 根据上一篇文章数码管的静态显示,我们已经知道如何精准控制某一个数码管显示某一个数字。 如果我们要前...

  • 51单片机、独立按键的认识与编程

    一、基本知识 1. 按键分类与输入原理 按键按照结构原理科分为两类,一类是触点式开关按键,如机械式开关、导电橡胶式...

  • 单片机实现秒表计时

    要求: 用stc89c51,数码管,锁存器实现秒表功能 实验仿真图: 加入两个锁存器使单片机能够分时进行位选和段选...

  • 向51单片机说再见!

    51单片机的辉煌过去 51单片机指MCS-51系列单片机,CICS指令集。由Intel公司开发,其结构增加了如乘(...

  • 51单片机常用波特率初值表(12M晶振)

    为什么51单片机的晶振一般使用11.0592? 用11.0592晶振的原因是51单片机的定时器导致的。用51单片机...

  • 51单片机基本结构

    姓名:陈婧娴 学号:19021211245 【嵌牛导读】:51单片机是初学者常接触的单片机,本文着重介绍51单片机...

网友评论

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

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