查看: 2797|回复: 0

Atmega 128 学习笔记第六站---多位数码管动态显示

[复制链接]

该用户从未签到

发表于 2015-4-30 08:47:53 | 显示全部楼层 |阅读模式
分享到:
上次跟大家讲述了利用ATmega128的PA端口控制一个数码管显示0~9的数字,还让大家回去实验一下,不知道大家实验了没?有没有发现实验的结果没有按照自己预想的效果发生啊?大家想到为什么了吗?对了,问题就是出在延时上,因为我们在程序代码中设定的数码管显示数字时间间隔只有50ms,大家知道人眼所能识别的时间间隔是多少吗?电影是24帧1秒,所以人眼能识别的时间大概在0.1s,所以若设定的时间间隔比较少,人眼是识别不了的,当我们把延时时间代码改成2s或者4s,我们就会发现,实验结果按照我们所设想的效果发生了:
#include<iom128v.h>
unsigned char const SEGtable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
void Delayms(uint MS)
main()
{
unsigned char i,j;
unsigned char counter=0;
DDRA=0Xff;
PORTA=0xFF;
while(1)
   {
    delay(4000);
    if(counter>=15)
     {
      counter=0;
      }
    else
      {
     counter++;
     }
    PORTA=SEGtable[counter];
    }
}
void Delayms(uint MS)            
{
   uint i,j;
   for( i=0;i<MS;i++)
   for(j=0;j<1141;j++);     
}

     这时我们就发现调用延时子函数的好处了吧,我们只需要修改整个程序代码中某一行指令就可以,在此处我们就只需要修改delay(4000)这条指令就可以了,若我们不调用子函数,而是将延时程序编在主函数中,每次修改就需要修改整个程序,费事费力,所以经验越丰富的编程人员都会将各个功能用子函数来实现,这样便于修改。
     在我们的工作中,我们不可能仅仅使用一个数码管,很多时候需要显示多个字符或者数字,这时我们可以使用多个独立的八段数码管来拼接,但是这种方式存在一个弊端,就是多个数码管就需要多个IO端口来驱动,比如我们用4位数码管,这就需要PA~PD端口分别来驱动这四个数码管,这样就极大的浪费了IO端口的资源,所以越来越多的工程师选择多位数码管,多位数码管一般形状如下:

     多位数码管的接口只有一套八段数码管的引脚,所以引脚接口比较简单,控制起来比较方便,而且相比独立数码管来说,这种集成的多位数码管价格要便宜的多。
     给大家介绍下集成的多位数码管的原理及如何控制,以一个6位数码管为例:

     从上图中可以看出,6位数码管的A、B、C、D、E、F、DP引脚都整合到了一起,而多出来了1、2、3、4、5、6引脚来分别对应数码管的阳极或者阴极端点,以此来控制点亮哪一个数码管。这时有人要问了,假如我用两个端口来控制,一个控制是选择哪个数码管来显示,一个端口用来控制显示的数字,但是问题来了,若我需要这6个数码管同时都显示数字呢?那岂不是无法实现了吗?咋一想确实是,可是研发工程师们永远能解决人们想要实现的功能,这时他们发明了动态扫描的方法来实现多位数码管的显示。动态扫描是相对于静态扫描而言的,何为静态扫描,就是在静态显示时候,数码管中相应的发光二极管是点亮还是熄灭,也就是上一站我们所学习的显示方式。只是在数量上面多了几个而已,而动态扫描就是一个一个的轮流点亮每个数码管,多位数码管的每个发光二极管都用A、B、C、D、E、F、DP引脚来驱动,而这几个引脚又通过ATmega128的一个端口来控制,同时1、2、3、4、5、6引脚通过ATmega128的另一个端口来控制到底是点亮哪个数码管,在动态扫描时候,当选中一个数码管,把数据送给他显示,一定时间后再选定一个数码管并把相应数据送给他显示,只要扫描的速度够快(超过我们上面所说的人眼的辨别时间)动态显示的效果在我们人眼看到的就是同时显示出来了一个数字,这时有人问了,这种方法没有弊端吗?是的,有的,若我们使用的数码管个数比较多的话,单片机就需要一直的计算扫描,这样就占用了单片机比较多的时间,但是在目前为止,这种方法也是一个比较好的方法并且被广大工程师们认可。
     好了,对多位数码管铺垫了这么多,下面就开始怎么使用ATmega128来控制多位数码管吧。
      我们假定要实现的目标为使用8个数码管,依次从左到右轮流显示“0~F”字符,此次我们仍选用共阳极的数码管,数据段并通过一个排阻接ATmega128的PD端口上,位选择段则通过一个NPN的三极管来驱动然后连接到ATmega128的PE端口上,也就是通过PD端口输出字形编码,通过PE端口选通对应的数码管,具体电路如下:


     电路设计好后,接着来进行编代码:
#include<iom128v.h>
unsigned char const SEGtable[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
void Delayms(uint MS)       // 代码最初对延时子函数声明
main()
{
unsigned char i,j;
unsigned char counter=0;   // 用于确定显示的数字或者字符,在数字数组中调用
unsigned char Lcounter=0;    // 用于确定选择的数码管
DDRD=0xFF;
DDRE=0xFF;
PORTD=0x00;
PORTE=0x00;
while(1)
   {
    delay(1000);   //   延时
    PORTD=SEGtable[counter];     // 输出显示的数字或者字符的字形编码
    if(counter>=15)            // 如果显示的字符到了“F”,则又回到“0”开始
      {
     counter=0;
     }
    else
     {
       counter++;
       }
    switch(Lcounter)           // 根据选中的位输出对应的控制信号
     {
case0x00: PORTE=0x01;break;            case0x01: PORTE=0x02;break;
       case0x02: PORTE=0x04;break;
       case0x03: PORTE=0x08;break;
       case0x04: PORTE=0x10;break;
       case0x05: PORTE=0x20;break;
       case0x06: PORTE=0x40;break;   
       case0x07: PORTE=0x80;break;
       default: PORTE=0x01;break;
       }
   if(Lcounter>=7)             // 如果到了最右边上的数码管,则又回到最左边的数码管
       {
       Lcounter=0;
        }
   else
        {
       Lcounter++;
       }
    }
}

void Delayms(uint MS)        //延时子函数     
{
   uint i,j;
   for( i=0;i<MS;i++)
   for(j=0;j<1141;j++);     
}
  对了,我们要养成个编程的好习惯,在代码的那一行,用“//”注释符号之后标注一些注释的语句,方便自己下次查阅或者别人使用时候的理解,尤其当我们编的代码越来越复杂的时候,就更加需要这些注释语句。

      各位学友将上面的代码编译之后下载到单片机上面跑一炮,看看效果如何啊?数码管是不是从左向右依次显示“0~F”?若效果不明显,大家也可以将延时子函数的延时时间变长一些,也可以随意的修延时时间,观看效果。。。。
今天的学习笔记就到这了,感谢大家观看,我们下期再见。
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

手机版|小黑屋|与非网

GMT+8, 2024-4-23 20:47 , Processed in 0.116996 second(s), 16 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.