多位数码管动态显示的实验.docx

上传人:b****5 文档编号:29538111 上传时间:2023-07-24 格式:DOCX 页数:20 大小:137.50KB
下载 相关 举报
多位数码管动态显示的实验.docx_第1页
第1页 / 共20页
多位数码管动态显示的实验.docx_第2页
第2页 / 共20页
多位数码管动态显示的实验.docx_第3页
第3页 / 共20页
多位数码管动态显示的实验.docx_第4页
第4页 / 共20页
多位数码管动态显示的实验.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

多位数码管动态显示的实验.docx

《多位数码管动态显示的实验.docx》由会员分享,可在线阅读,更多相关《多位数码管动态显示的实验.docx(20页珍藏版)》请在冰豆网上搜索。

多位数码管动态显示的实验.docx

多位数码管动态显示的实验

【006】多位数码管动态显示 [51]

 

实验目的:

数码管动态显示多位数字。

实验参考:

笨笨工作室实验五、多位数码动态显示。

()

实验板:

FB51A()。

该实验用到实验板的资源电路图如下:

其中P0口是段码,低电平有效。

P2口是位码,高电平有效。

口操纵第1个数码管,一直到口操纵第8个。

该板的段码表如下:

    

各个数码管的段码都是p0口的输出,即各个数码管输入的段码都是一样的,为了使其别离显示不同的数字,可采纳动态显示的方式,即先只让最低位显示0(含点),通过一段延时,再只让次低位显示1,如此类推。

由视觉暂留,只要咱们的延不时刻足够短,就能够够使得数码的显示看起来超级的稳固清楚。

进程如以下图。

           

 

采纳上述方式思路编写如下:

      org  0000h

start:

mov  a,#08h      ;0   ;段码

      mov  p0,a

      mov  p2,#01h           ;位码

      lcalldelay_1ms

      mov  a,#0abh     ;1    

      mov  p0,a

      mov  p2,#02h

      lcalldelay_1ms

      mov  a,#12h      ;2

      mov  p0,a

      mov  p2,#04h

      lcalldelay_1ms

      mov  a,#22h      ;3

      mov  p0,a

      mov  p2,#08h

      lcalldelay_1ms

      mov  a,#0a1h     ;4

      mov  p0,a

      mov  p2,#10h

      lcalldelay_1ms

      mov  a,#24h      ;5

      mov  p0,a

      mov  p2,#20h

      lcalldelay_1ms

      mov  a,#04h      ;6

      mov  p0,a

      mov  p2,#40h

      lcalldelay_1ms

;     mov  a,#0aah     ;7

;     mov  p0,a

      mov  p0,#0aah    ;感觉用这句和上面两句实现一样,可能这种适应以后会有效吧

      mov  p2,#80h

      lcalldelay_1ms

      ljmp start

delay_1ms:

mov r6,#2

temp:

     mov r5,#0ffh

          djnzr5,$

          djnzr6,temp

          ret

end

下载到板上取得测结果为从低到高八位别离显示0到7(含点)。

★上述方式逐次给P0或P2赋值,一方面程序的复杂程度增加,另外一方面会使得程序的灵活性降低。

若是要改变显示的数字,程序改动起来很麻烦。

 因此要用51单片机中经常使用的一种方式:

查表法。

例如P0口输出段码时,咱们能够把要显示的段码放在一个表格中,然后每次从那个表格里面取数,送到P0口即可。

P2口输出位码时,能够把要用的位码放在另一个表格里,每次从此表中取数,送入P2口。

如此,若是要改变显示的数字,只需要改变表格里面的数。

      org  0000h

start:

mov  r7,#0ffh    ;r7,r6查表时送入变址寄放器a(因自加1后为0,因此预置ffh)

      mov  r6,#0ffh

loop:

 lcallplay1       ;调用显示段码子程序

      lcallplay2       ;调用显示位码子程序

      lcalldelay_1ms

      cjne a,#80h,loop ;判断是否到了最左边的数,即第8个位码

      ajmp start

play1:

                   ;查表求段码子程序             

;     mov  a,r7          

;     inc  a

;     mov  r7,a

      inc  r7          ;这2句和上面三条语句实现功能相同

      mov  a,r7        ;a在这里做变址寄存器

      mov  dptr,#table1;表首址送dptr,dptr做基址寄放器

      movc a,@a+dptr   ;基址寄放器加变址寄放器寻址

      mov  p0,a

      ret

play2:

                   ;查表求位码子程序(原理同play1)

      mov  a,r6             

      inc  a

      mov  r6,a

      mov  dptr,#table2

      movc a,@a+dptr

      mov  p2,a

      ret

table1:

db08h,0abh,12h,22h,0a1h,24h,04h,0aah ;段码表

table2:

db01h,02h,04h,08h,10h,20h,40h,80h    ;位码表

delay_1ms:

 mov  r5,#02h                     ;延时1ms子程序

temp:

      mov  r4,#0ffh

           djnz r4,$

           djnz r5,temp

           ret

end

下载到板上验证得到预想结果。

C51实现如下(参考了的例程):

#include<>

#include<>            //包含了左移函数_crol_()

voiddelayms(unsignedcharms);//延时子程序

unsignedchardatadis_digit;  //位选通值,传送到P2口用于选通当前数码管的数值,

                               //如等于0x01时,选通口数码管

unsignedcharcodedis_code[11]={0x08,0xab,0x12,0x22,0xa1,       //0,1,2,3,4

                                0x24,0x04,0xaa,0x00,0x20,0xff};//5,6,7,8,9,off

unsignedchardatadis_buf[8]; //dis_buf显于缓冲区基地址

unsignedchardatadis_index;  //显示索引,用于标识当前显示的数码管缓和冲区的偏移量

voidmain()

{

   P0=0xff; //关闭所有数码管

   P2=0x00;

   dis_buf[0]=dis_code[0];

   dis_buf[1]=dis_code[1];

   dis_buf[2]=dis_code[2];

   dis_buf[3]=dis_code[3];

   dis_buf[4]=dis_code[4];

   dis_buf[5]=dis_code[5];

   dis_buf[6]=dis_code[6];

   dis_buf[7]=dis_code[7];

   

   dis_digit=0x01; //首先选通

   dis_index=0;    //当前偏移量为0

   

   while

(1)

   {

        P0=dis_buf[dis_index];         //段码送P0口

        P2=dis_digit;                  //选能位(即位码)

        delayms

(1);                      //延时

        dis_digit=_crol_(dis_digit,1);//位选通左移,下次选通下一位

        dis_index++;                     //下一个段码

        

        dis_index&=0x07;               //见注释

   }

}

voiddelayms(unsignedcharms)            //延时子程序(晶振12M)

{                       

   unsignedchari;

   while(ms--)

   {

       for(i=0;i<120;i++);

   }

}

★注释:

此句作用是8个数码管全数扫描完一遍以后,再回到第一个开始下一次扫描。

写回一样形式:

dis_index=dis_index&0x07。

这种方式挺新,第一次见到,十六进制的07确实是二进制的00000111,如此通过与操作能够操纵循环了。

比如dis_index经第一次循环后值为00000001,和0x07与操作后值不变仍为0x01,第二次循环时,其值为0为0x02,与0x07后仍为0x02,一直到其值增为0x07时仍是不变的,但再次循环后其值为0x80,再与0x07后就变成0x00了,如此又从初始循环了。

此句可用if(dis_index==8)dis_index=0代替,成效一样。

★通过C51用上述方式实现时,其段码放在了数组dis_code[11]中,再通过缓冲区数组dis_buf[]将程序中要挪用的值装入,如此就能够够用下标(偏移量)访问了。

如此看上去有些繁锁,但其思路比较清楚,结构上也很明了,具有通用性,便于扩展。

★另外只要把程序中的延时加长,如delayms(250),下载到板上就能够够看到事实上数码管是由低位到高位逐位显示的。

   假设单单就实现那个功能而言,能够直接调入段码数组dis_code[11]中下标从0到7的值,而没必要再设置缓冲数组dis_buf[],实现如下:

#include<>

#include<>           //_crol_()用

voiddelayms(unsignedcharms);//延时子程序

unsignedchardatadis_digit;  //位选通值,传送到P2口用于选通当前数码管的数值,

                               //如等于0x01时,选通口数码管

unsignedcharcodedis_code[11]={0x08,0xab,0x12,0x22,0xa1,       //0,1,2,3,4

                                0x24,0x04,0xaa,0x00,0x20,0xff};//5,6,7,8,9,off

unsignedchardatadis_index; //显示索引,用于标识当前显示的数码管缓和冲区的偏移量

voidmain()

{

   P0=0xff;       //关闭所有数码管

   P2=0x00;

   dis_index=0;   //当前偏移量为0

   dis_digit=0x01;//选通

   while

(1)

   {

       P0=dis_code[dis_index];//段码送P0口

       P2=dis_digit;          //位码送P2口

       delayms

(1);

       dis_digit=_crol_(dis_digit,1);//位选通左移,下次选通下一名

       dis_index++;

       dis_index&=0x07;

   }

}

voiddelayms(unsignedcharms) //延时子程序(晶振12M)

{                       

   unsignedchari;

   while(ms--)

   {

       for(i=0;i<120;i++);

   }

}

★本来是想通过以下方式实现一次循环的:

       for(dis_index=0;dis_index<8;dis_index++)

       {

           P0=dis_code[dis_index];//段码送P0口

           P2=dis_index+1;        //位码送P2口

           delayms

(1);

       }

可得到的总是错误的结果:

第0位到第2位这三位显示的是三个8,第3位显示的是7,高四位没有显示。

加长延时逐位观察也没有发现错误的规律,对Keil的调试也不熟悉,先把问题留到这,待找出原因后再补上。

[找出缘故啦,补上:

今天又看了一下,找到上面的错误出在哪了。

那时是想用dis_index的值做为位码的,即第一名显示0时,段码为dis_code[0],即dis_index值为0,现在位码值为1。

第二位显示1时,段码为dis_code[1],即dis_index值为1,现在位码值为2。

因此就简单用了个加1运算,将P0口的偏移值与P2口的位码联系起来。

但认真想一下位码的原理,上述方式显然是错的,只要再验证一步就明白了,即当第3位显示2时,段码为dis_code[2],dis_index值为2,加1后为3,按上述方式时就将那个3作为了位码,而正确的位码应该是4(00000100B)。

因此犯错。

事实上那个对应关系是有的,但不是简简单单的加1,位码应该是2的dis_index次幂。

即:

0--1

1--2

2--4

3--8

4--16       ……

幂次运算函数flaotpow(floatx,floaty)包含在中,返回值为xy(float型):

 

       for(dis_index=0;dis_index<8;dis_index++)

       {

           P0=dis_code[dis_index];//段码送P0口

           P2=(char)pow(2,dis_index);        //位码送P2口

           delayms(255);

       }

再次下载到板上发现仍有问题,即延时很小的时候显示混乱,但加大延时时间(如程序中的值)可以观查到数码管是按位正确显示的。

另外用这种方法产生的代码量也很大(从写入速度看,很明显)。

这里仅提出了一个思路,只在此实验中适用,意义不大,到此为止。

[补充终止]

中绐出的例程是利用按时中断做的延时,参考修改到我的板上,程序如下:

#include<>

#include<>           //包含了左移函数_crol_()

unsignedchardatadis_digit;  //位选通值,传送到P2口用于选通当前数码管的数值,

                               //如等于0x01时,选通口数码管

unsignedcharcodedis_code[11]={0x08,0xab,0x12,0x22,0xa1,       //0,1,2,3,4

                                0x24,0x04,0xaa,0x00,0x20,0xff};//5,6,7,8,9,off

unsignedchardatadis_buf[8]; //dis_buf显于缓冲区基地址

unsignedchardatadis_index;  //显示索引,用于标识当前显示的数码管缓和冲区的偏移量

voidmain()

{

   P0=0xff;   //关闭所有数码管

   P2=0x00;

   TMOD=0x01; //00000001B按时计数器0工作在方式1,16位按时器/计数器

   TH0=0xFC;     

   TL0=0x17;  //预置初值FC17H=64535D,216-64535=1001us=1ms

   IE=0x82;   //BT0溢出中断许诺

   dis_buf[0]=dis_code[0x0];

   dis_buf[1]=dis_code[0x1];

   dis_buf[2]=dis_code[0x2];

   dis_buf[3]=dis_code[0x3];

   dis_buf[4]=dis_code[0x4];

   dis_buf[5]=dis_code[0x5];

   dis_buf[6]=dis_code[0x6];

   dis_buf[7]=dis_code[0x7];

   

   dis_digit=0x01;  //选通第0位数码管

   dis_index=0;     //偏移初值为0

   

   TR0=1;   //启动T0

   while

(1);  //循环等待中断

}

voidtimer0()interrupt1 //按时器0中断效劳程序,用于数码管的动态扫描

{

   TH0=0xFC;                      //发生中断定时/计数器重装初值

   TL0=0x17;                      //感觉此处(及上)应该是0x18,而不是17,分析如下

    

   P2=0x00;                       //先关闭所有数码管

   P0=dis_buf[dis_index];         //段码送P0口

   P2=dis_digit;                  //位码送P2口

   dis_digit=_crol_(dis_digit,1); //位选通值左移,下次中断时选通下一名数码管

   dis_index++;

                   

   dis_index&=0x07;    //8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描

}

★按时器/计数器的输入脉冲周期与机械周期一样,为时钟振荡频率的1/12。

晶振用12M时,输入脉冲周期距离为1us。

机械周期为1us。

设T0的初值为X,计算初值的方式:

本例中按时器用方式1,是16位的按时器,即最大值为216=65536,超过此值将发生溢出,引发中断,进入中断处置程序。

那个地址要让其延时1ms,即1000us,那么有式216-X=1000,可得X=64536,换算为16进制为FC18,即初值TH0=0xFC,TL0=0x18。

即按时器由64536开始计数,经1000次计数后值为65536,将发生按时中断,再进入中断处置子程序后,从头装和初值,如此循环下去。

   而在上例中其装入的初值并非FC18(64536),而是FC17(64535)。

我想大概认为其计数范围在0~65565的原因吧,我也想过这个问题,是用216-计数初值=中断距离 呢,仍是用(216-1)-计数初值=中断距离呢?

顺手查了几本书,说法不一,只是用前者的较多,我自己也以为前者比较合理,因为在运算机中16位的二进制不能表示65536,在列位均为1时表示的值为65535,即65535H=111B,也能够说65536是溢出取得的。

而何时响应中断就成了关键,拿上例来讲,如设初值为64535(FC17),那么计数到65535时,已经计数为1000个,即1ms,但现在并未发生溢出,因此也没有触发中断。

而是在下一个计数后才发生。

确切值应为1001us。

假设初值为64536(FC18),那么恰好为所需值,因此上例中的初值应该用FC18而不是FC17。

这仅仅是我自己的一点观点,至于是不是如此,还有待进一步考证。

最终下载到实验板上结果:

 

######################################补充########################################

用Proteus仿真结果如下(某一状态的截图):

 

★该电路段码是按与板上接法对应的,即按前面的段码表顺序连接。

另外那个八位的仿真数码管最左端是第一名,最右端是第八位,与板上的顺序相反,因此接为了统一,该图以板为准连接。

上图不加上拉电阻也可仿真出结果,只是P0口高电平显示为灰,即高阻。

引用地址:

多功能数字钟的设计方案

一、蜂鸣器的设计

二、温度传感器(DB18B20)设计

3、液晶(1620)模块

4、正弦波转换为方波电路图

五、+12V交流电压转换为+5V直流电压

六、红外发射模块

7、红外接收模块

八、综合电路图

方案报告:

校电子设计大赛设计与总结报告

(题目:

多功能数字钟)

一、任务与要求

任务:

设计制作一个24小时制多功能数字钟。

要求:

a.大体要求

一、具有时刻设置(小时和分钟)、闹钟时刻设置、闹钟开、闹钟关功能。

二、数字显示小时、分钟,有AM、PM指示器,闹钟就绪灯,蜂鸣器。

3、220V供电。

b.发挥部份

一、键盘切换现场环境温度显示。

(0~60℃1℃)

二、键盘切换电网频率、电压显示。

3、电压欠压、过压报警(~220V+/—10%)功-能。

4、非接触止闹功能。

二、方案比较及作品模块介绍

多功能数字钟,具有时钟时刻设置、闹钟时刻设置、闹钟开、闹钟关等功能,数字显示日期、小时、分钟、秒,有AM、PM指示器,闹钟就绪灯(由指示灯指示是不是设有闹钟)、蜂鸣器。

可用键盘切换现场温度、电网频率、电压等,能动态刷新显示以上各测量参数。

还能够进行电压欠压、过压报警(220V±10%)。

当闹钟启动后,能够通过遥控器遥控止闹。

电子钟的设计包

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 企业管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1