首页 🥳 笔记

本文最后更新于 2021 年 02 月 08 日,已超过 134 天没更新!内容可能已失效,请自行测试 ~

动态显示的基本原理:

多个数码管显示数字的时候,实际上是轮流点亮数码管(一个时刻内只有一个数码管是亮的),利用人眼的视觉暂留现象(也叫余辉效应),就可以做到看起来是所有数码管都同时亮了,这是动态显示,也叫动态扫描

数码管显示消隐:

数码管不应该亮的段,似乎有微微的发亮,这种现象叫做“鬼影”。

“鬼影”的出现,主要是在数码管位选和段选产生的瞬态造成的。

解决方案

⚫通过延时来使“鬼影”消失,但数码管亮度会普遍降低。❌

⚪一是刷新之前关闭所有段,改变好了位选后,再打开段即可;二是关闭数码管的位,赋值过程都做好后,再重新打开即可。

/*实现秒表功能*/
#include "reg52.h"

sbit LSA=P2^3;
sbit LSB=P2^4;
sbit LSC=P2^5;

unsigned char code LedChar[]={            //数码管显示字符转换表
        0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
        0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};
unsigned char LedBuff[8]={                    //数码管显示缓冲区,初值0x00确保启动时都不亮
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};


void main()
{
    unsigned char i = 0;          //动态扫描的索引
    unsigned int cnt = 0;            //记录T0中断次数
    unsigned long sec = 0;        //记录经过的秒数
    
    TMOD = 0x01;                            //设置T0为模式1
    TH0 = 0xFC;                                //为T0赋初值0xFC67,定时1ms
    TL0 = 0x67;                                
    TR0 = 1;                                    //启动T0

    while(1)
    {
        if(TF0 == 1)                        //判断T0是否溢出
            {
                TF0 = 0;                        //T0溢出后,清0中断标志
                TH0 = 0xFC;                    //并重新赋初值
                TL0 = 0x67;
                cnt++;                            //计数值自加1
                if(cnt >= 1000)            //判断T0溢出是否达到1000次
                {
                    cnt    = 0;                    //达到1000次后计数值清0
                    sec++;                        //秒计数自加1
                    P0 = 0x00;     //数码管显示消隐
                    //以下代码将sec按十进制位从低到高依次提取并转为数码管显示字符
                    LedBuff[0] = LedChar[sec%10];
                    LedBuff[1] = LedChar[sec/10%10];
                    LedBuff[2] = LedChar[sec/100%10];
                    LedBuff[3] = LedChar[sec/1000%10];
                    LedBuff[4] = LedChar[sec/10000%10];
                    LedBuff[5] = LedChar[sec/100000%10];
                    LedBuff[6] = LedChar[sec/1000000%10];
                    LedBuff[7] = LedChar[sec/10000000%10];
                }
                //以下代码完成数码管动态扫描刷新
                switch(i)
                {
                    case 0:LSA=1;LSB=1;LSC=1;i++;P0=LedBuff[0];break;
                    case 1:LSA=0;LSB=1;LSC=1;i++;P0=LedBuff[1];break;
                    case 2:LSA=1;LSB=0;LSC=1;i++;P0=LedBuff[2];break;
                    case 3:LSA=0;LSB=0;LSC=1;i++;P0=LedBuff[3];break;
                    case 4:LSA=1;LSB=1;LSC=0;i++;P0=LedBuff[4];break;
                    case 5:LSA=0;LSB=1;LSC=0;i++;P0=LedBuff[5];break;
                    case 6:LSA=1;LSB=0;LSC=0;i++;P0=LedBuff[6];break;
                    case 7:LSA=0;LSB=0;LSC=0;i=0;P0=LedBuff[7];break;
                    default:break;
                }
            }
        }
}
#include "reg52.h"

sbit LSA=P2^3;
sbit LSB=P2^4;
sbit LSC=P2^5;

unsigned char code LedChar[]={            //数码管显示字符转换表
        0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
        0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};

unsigned char LedBuff[8]={            //数码管显示缓冲区,初值0x00确保启动时都不亮
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

unsigned char i=0;            //动态扫描的索引
unsigned int cnt=0;            //记录T0中断次数
unsigned char flag1s=0;        //1秒定时标志

void main()
{
    char j;  //循环变量
    unsigned long sec=0;        //记录经过的秒数
    unsigned char buf[8];   //中间转换缓冲区

    EA=1;                        //使能总中断
    TMOD=0x01;                    //设置T0为模式1
    TH0=0xFC;                    //为T0赋初值0xFC67,定时1ms
    TL0=0x67;                
  ET0  = 1;     //使能T0中断            
    TR0=1;                        //启动T0

    while(1)
    {
        if(flag1s == 1)        //判断T0是否溢出   
        {
            flag1s=0;        //T0溢出后,清0中断标志
            sec++;        //秒计数自加1
      //将sec按十进制位从低到高依次提取到buf数组中
            buf[0] = sec%10;
            buf[1] = sec/10%10;
            buf[2] = sec/100%10;
            buf[3] = sec/1000%10;
            buf[4] = sec/10000%10;
            buf[5] = sec/100000%10;
            buf[6] = sec/1000000%10;
            buf[7] = sec/10000000%10;
            //从最高为开始,遇到0不显示,遇到非0退出循环
            for (j=7; j>=1; j--)
            {
                if (buf[j] == 0)
                    LedBuff[j] = 0x00;
                else
                    break;
            }
            //将剩余的有效数字位如实转换
            for ( ; j>=0; j--)  //for()起始未对j操作,j即保持上个循环结束时的值
            {
                LedBuff[j] = LedChar[buf[j]];
            }
        }
    }
}
/* 定时器0中断服务函数 */
void InterruptTimer0() interrupt 1
{
    TH0=0xFC;        //重新加载初值
    TL0=0x67;
    cnt++;            //中断次数计数值加1
    if(cnt >= 1000)        //中断1000次即1秒
     {
        cnt=0;        //清0计数值以重新开始下1秒计时
        flag1s=1;    //设置1秒定时标志为1
    }
    P0=0x00;            //数码管显示消隐
//以下代码完成数码管动态扫描刷新
    switch(i)
    {
        case 0:LSA=1;LSB=1;LSC=1;i++;P0=LedBuff[0];break;
        case 1:LSA=0;LSB=1;LSC=1;i++;P0=LedBuff[1];break;
        case 2:LSA=1;LSB=0;LSC=1;i++;P0=LedBuff[2];break;
        case 3:LSA=0;LSB=0;LSC=1;i++;P0=LedBuff[3];break;
        case 4:LSA=1;LSB=1;LSC=0;i++;P0=LedBuff[4];break;
        case 5:LSA=0;LSB=1;LSC=0;i++;P0=LedBuff[5];break;
        case 6:LSA=1;LSB=0;LSC=0;i++;P0=LedBuff[6];break;
        case 7:LSA=0;LSB=0;LSC=0;i=0;P0=LedBuff[7];break;
        default:break;
    }
}
/* 改用定时器T1的中断实现从99999999开始倒计时 */
#include "reg52.h"

sbit LSA=P2^3;
sbit LSB=P2^4;
sbit LSC=P2^5;

unsigned char code LedChar[]={            //数码管显示字符转换表
        0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
        0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};
unsigned char LedBuff[8]={                    //数码管显示缓冲区,初值0x00确保启动时都不亮
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
unsigned char i = 0;          //动态扫描的索引
unsigned int cnt = 0;            //记录T1中断次数
unsigned char flag1s=0;        //1秒定时标志

void main()
{
    unsigned long sec = 100000000;        //记录经过的秒数
    EA = 1;                                        //使能总中断
    TMOD = 0x10;                            //设置T1为模式1
    TH1 = 0xFC;                                //为T1赋初值0xFC67,定时1ms
    TL1 = 0x67;                                
    ET1 = 1;                                    //使能T1中断
    TR1 = 1;                                    //启动T1
    while(1)
    {
        if(flag1s == 1)                    //判断T1是否溢出
            {
                flag1s = 0;                    //T1溢出后,清0中断标志
                sec--;                            //秒计数自减1
                //以下代码将sec按十进制位从低到高依次提取并转为数码管显示字符
                LedBuff[0] = LedChar[sec%10];
                LedBuff[1] = LedChar[sec/10%10];
                LedBuff[2] = LedChar[sec/100%10];
                LedBuff[3] = LedChar[sec/1000%10];
                LedBuff[4] = LedChar[sec/10000%10];
                LedBuff[5] = LedChar[sec/100000%10];
                LedBuff[6] = LedChar[sec/1000000%10];
                LedBuff[7] = LedChar[sec/10000000%10];
            }
    }
}
/* 定时器1中断服务函数 */
void InterruptTimer0() interrupt 3
{
    TH1 = 0xFC;                    //重新加载初值
    TL1 = 0x67;
    cnt++;                            //中断次数计数值加1
    if(cnt >= 1000)            //中断1000次即1秒
    {
        cnt    = 0;                    //清0计数值以重新开始下1秒计时
        flag1s=1;                    //设置1秒定时标志为1
    }    
    P0 = 0x00;                    //显示消隐
    //以下代码完成数码管动态扫描刷新
    switch(i)
    {
        case 0:LSA=1;LSB=1;LSC=1;i++;P0=LedBuff[0];break;
        case 1:LSA=0;LSB=1;LSC=1;i++;P0=LedBuff[1];break;
        case 2:LSA=1;LSB=0;LSC=1;i++;P0=LedBuff[2];break;
        case 3:LSA=0;LSB=0;LSC=1;i++;P0=LedBuff[3];break;
        case 4:LSA=1;LSB=1;LSC=0;i++;P0=LedBuff[4];break;
        case 5:LSA=0;LSB=1;LSC=0;i++;P0=LedBuff[5];break;
        case 6:LSA=1;LSB=0;LSC=0;i++;P0=LedBuff[6];break;
        case 7:LSA=0;LSB=0;LSC=0;i=0;P0=LedBuff[7];break;
        default:break;
    }
}



文章评论