单片机之基础编程 八位数码管(三)

我们已经了解了最简单的流水灯模型,我们就开始学习数码管啦!我们可以慢慢的循序渐进学习这些神奇的现象,从这篇开始我们重点只介绍实验原理和代码

八位数码管实际上很多的案例,这里主要介绍

  • 八位数码管动态扫描
  • 八位数码管+流水灯
  • 八位数码管滚动显示
  • 可变亮度的数码管显示

八位数码管动态扫描

实验现象为:
从左到右8个数码管分别显示1、2、3、4、5、6、7、8
我们就直接进入到其

电路图

先放图:
在这里插入图片描述
在学习流水灯的时候我们已经接触过这个图了,心细的同学可能已经发现八位数码管也存在这里面

那放大的数码管外部又是怎么定义各段的呢
在这里插入图片描述

扩展:(这些我们下面的例子会具体的涉及到)

A在8位中的最低位,DP位为最高位。组合成的八位对应P0口的八位。数码管又分为共阴极和共阳极两种类型;其中共阴极就是将八个LED阴极连在一起,让其接地,这样给任何一个LED发光管另一端高电平,它便能点亮。而共阳极就是将八个LED的阳极连在一起

共阴极数码管相应段位输入编码位1,则相应段灯亮;而共阳极数码管对应段位输入编码为0,则相应段灯亮。本处是采用的共阴极数码管。如果想让共阴极数码管显示数字0,则A、B、C、D、E、F、G位都需要输入为1。H与DP位为0,组合即为00111111

工作原理
  • P0口的8位输出分别控制1个LED数码管的7段和一个小数点
  • 而P2.3经反相器U4C控制74HC138的使能信号E3,结合P2.0、P2.1、P2.2这3个位选控制信号确定8个LED数码管中的哪个被点亮
  • 电阻R15~R22为限流电阻
  • 当段选为高、使能信号有效时,对应的LED管将会发光
  • 通过以一定频率扫描位选信号,修改段选信号进行数码管点亮一段时间,从而给人视觉上几个数码管几乎同时显示的效果

编写任何代码,我们都需要心里有一个框架,即我们需要做哪些工作

  1. 初始化我们的数码管显示(利用数组预定义)
  2. 设置输出方式,即初始化硬件
  3. 循环内部(扫描位选并完成位的显示正确)
    在这里插入图片描述
代码编写
  • 预定义
uint i=0; //全局定义
uchar duanxuan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f}; 
//即按照a-h顺序定义了各段.
//e.g. 数组中第一个应该显示0,其对应的段选有效应为0011 1111
//即a-f均有效,
//注意低位为a

uchar weixuan[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
//选择数码管0-7中的一个
  • 延时函数
void Delay(int n)				
{
	while(n--);
}
  • 主函数
void main()
{
	P2M0=0xff;					
   	P2M1=0x00;
   	//只要设置p2.3为推挽输出即可
   	//即P2M0也可设置为0x08
   	
    P0M0=0xff;
    P0M1=0x00;
    //设置推挽输出

	while(1)
	{
		//利用for循环,不断扫描数码管
		//使数码管在点亮一段时间,视觉上达到一直亮的状态。
		for(i=0;i<8;i++)
		{
			P0=0;   //最开始设置不发光
			P2=weixuan[i];		//选择第i位数码管发光
			P0=duanxuan[i+1];	//第i位显示数字i+1
			Delay(600);        //设定一定的延时
		}
	}
}

看到这,可能会有同学有疑惑,为啥我们观察到的实验现象是一直在亮,而不是一个一个亮呢,这是由于我们的视觉暂留效应


八位数码管+流水灯
实验现象

应为:
从左到右8个数码管分别显示1、2、3、4、5、6、7、8。LED灯从右到左依次亮起

再放图:
在这里插入图片描述
还是这个图,是不是越看越亲切捏
数码管和流水灯的原理我们都已经涉及过了,那只要设置其同时显示就可以了(但是他能同时显示吗)

细心的同学可能会发现一个问题,上面在说数码管的时候,我们说到
P2.3经反相器U4C控制74HC138的使能信号E3
也就是P2.3为高电平的话,E3只能为低,那么数码管的使能就不能有效了,这不就是只能存活一个嘛,那是不是我们就可以结束了,这个就不能实现了呢
(毕竟人眼的感光不是那么的强,我们几乎是观察不到他们不是同时显示的呢)

工作原理

(下面的这段原理就不用看啦,实际上就是考虑LED_SEL有多长时间为1还是为0,时间确定很重要,如果还是不懂,可以看代码的解释)

  • P0口的8位输出分别控制8个发光二极管L0~L7的阳极

  • 而P2.3经反相器U4C控制8个发光管阴极E3;当阳极为高(对应P0口位为1)、阴极为低时,对应的二极管将会发光

  • 而P2.3经反相器U4C控制74HC138的使能信号E3,结合P2.0、P2.1、P2.2这3个位选控制信号确定8个LED数码管中的哪个被点亮;电阻R15~R22为限流电阻。当段选为高、使能信号有效时,对应的LED管将会发光

  • 通过以一定频率扫描位选信号,选择段选信号进行数码管点亮一段时间,从而给人视觉上几个数码管几乎同时显示的效果;同时扫描led,使led从左到右不断亮起

代码解析
  • 初始化
sbit sbtLedSel = P2 ^ 3; 

这是一种引脚别名定义的方式

uchar uiLed = 0x01;

定义其最开始二极管为最低位有效

void Init()
{
    P0M1 = 0x00;
    P0M0 = 0xff;
    P2M1 = 0x00;
    P2M0 = 0x08;
    //这些讲过很多遍,就放过它们吧,不拿它们念经了(嘻嘻嘻)
    
    sbtLedSel = 0;  
    //设定最开始是数码管亮
}
  • 主函数部分
    延时以及数码管初始化部分我们就不做阐述了
void main()
{
    Init();
    while( 1 )   //永真循环
    {
        sbtLedSel = 0;  
        //每次执行完一次循环,仍设定其初始为数码管先亮
        for( i = 0; i < 8; i++ )
        {
            P0 = 0;
            P2 = arrDigitSelect[i];     //Ñ¡ÔñÊýÂë¹ÜµÄλÊý
            P0 = arrSeg7Select[i + 1];  //ÏÔʾ¶ÔÓ¦µÄÊýÖµ
            delay_ms( 1 );
        }
        //数码管8位显示正确数字
        
        uiLedCnt++;  //累加其次数
        sbtLedSel = 1;  //设定其为二极管亮
        P0 = uiLed;     //设定初始情况为最右边的灯先亮       
        delay_ms( 1 );     //构造流水灯效果      
        if( uiLedCnt == 50 )  //累加到50次才改变一位的二极管
        {
            if( uiLed == 0x80 )        
                uiLed = 0x01;
            else
                uiLed = uiLed << 1;    
            uiLedCnt = 0;
        }
    }
}

嘻嘻嘻,加上代码和原理,感觉这些东西都简单了很多呢
那就继续往下深入学习吧


八位数码管滚动显示

该案例算是数码管里的黄金级别了吧,因为代码辣么长

实验现象

8个数码管从左到右分别显示0到7的八个数字
隔一段时间后显示1到8,接着是2到9,再接着是3到0……重复这样的规律显示
达到的效果是0到9这10个数字循环向左移动

工作原理

只需要改变其扫描的频率,并且每过多久改变一次显示的数值即可并且循环显示,原理比较简单
其中涉及的定时计数概念,我们将在后面详细讲解

代码解析
void Init()
{
    P2M0 = 0xff;
    P2M1 = 0x00;
    P0M0 = 0xff;
    P0M1 = 0x00; //推挽输出

    ucSeg7State = 0;  //统计中断次数
    ucCount = 0;     //内部统计数码管扫描频率

    ucDig1Tmp = 0; //初始化设置数码管显示为从左到右0-7
    ucDig2Tmp = 1;
    ucDig3Tmp = 2;
    ucDig4Tmp = 3;
    ucDig5Tmp = 4;
    ucDig6Tmp = 5;
    ucDig7Tmp = 6;
    ucDig8Tmp = 7;

    TMOD = 0x01;        //寄存器0,方式1      
    ET0 = 1;            //开启定时器中断       
    TH0 = ( 65535 - 1000 ) / 256;  //定时器高8位设置
    TL0 = ( 65535 - 1000 ) % 256;   //定时器低8位设置
    TR0 = 1;              //启动定时器    
    EA = 1;               //打开总的中断
}
  • 定时器自动中断
    代码比较长,但是理解很容易(定时等后面的博客会提及)
//当定时器0初始值不断加一最终溢出时激发的处理方法
void T0_Process() interrupt 1    //把数码管的显示提到中断里
{
	//重设TH0、TL0
    TH0 = ( 65535 - 1000 ) / 256; //重新装载定时器0的初始值,为下一次定时做准备
    TL0 = ( 65535 - 1000 ) % 256;
    ucSeg7State++;       
    
    if( ucSeg7State == 8 )   //每中断8次才让count加一
    {
        ucSeg7State = 0;
        ucCount++;
    }
    
    if( ucCount == 100 )     //count每递加到100,设定每一位显示的新值
    {
        ucCount = 0;
        ucDig1Tmp++;   
        ucDig2Tmp++;
        ucDig3Tmp++;
        ucDig4Tmp++;
        ucDig5Tmp++;
        ucDig6Tmp++;
        ucDig7Tmp++;
        ucDig8Tmp++;
    }
    P0 = 0;       //使P0显示不受上一次的影响  
		
    P2 = arrDigSelect[ucSeg7State];   //位选,选择第ucSeg7State个数码管
    switch( ucSeg7State )           //每次中断选择一个数码管来显示
    {
        case 0:
            P0 = arrSegSelect[ucDig1Tmp % 10];
            break;  //从左到右,第一个
        case 1:
            P0 = arrSegSelect[ucDig2Tmp % 10];
            break;   //第二个
        case 2:
            P0 = arrSegSelect[ucDig3Tmp % 10];
            break;   //第三个
        case 3:
            P0 = arrSegSelect[ucDig4Tmp % 10];
            break;   //...
        case 4:
            P0 = arrSegSelect[ucDig5Tmp % 10];
            break;
        case 5:
            P0 = arrSegSelect[ucDig6Tmp % 10];
            break;
        case 6:
            P0 = arrSegSelect[ucDig7Tmp % 10];
            break;
        default:
            P0 = arrSegSelect[ucDig8Tmp % 10];
            break;
    }
}
  • 主函数
void main()
{
    Init(); 
    while( 1 )
    {
    }
}

只要设定永真循环就好,因为定时器只要溢出,就会自动中断

这个似乎涉及到了我们的定时器,我们后面好好学习一下


可变亮度的数码管显示

那我们现在学习一下数码管中的骨灰级的案例趴(因为我们现在这个案例可以自己来控制很多显示现象了)

实验现象
  • 按KEY1可以增加扫描的位数,最多达到255位,如果继续增加则成0位(数码管最多只能显示8位,第8位之后的不显示)
  • 按KEY2可以减少数码管显示的位数,直至无数码管显示数字,继续减少则成255位
  • 随着扫描位数的增加,数码管的亮度会逐渐下降

很神奇有没有
那么赶紧学一下原理把

工作原理
  • 8个数码管不能同时亮,所以需要以一定频率修改位选信号,对数码管进行动态扫描,让数码管轮流发光一段时间。
  • 由于人眼的视觉暂留,从而给人视觉上一种数码管是同时显示的效果。
  • 随着扫描位数的增多,扫描到每一位数码管上的时间会减少,因此数码管的亮度会下降

似乎看完原理没啥用,那还是直接看代码吧

代码解析

菜菜似乎能力不够,老师这一节都没给我们分享代码(/(ㄒoㄒ)/~~,感谢老师没有为难我们


那我们这一节的学习就到此结束啦!

  • 22
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值