ImageVerifierCode 换一换
格式:DOCX , 页数:14 ,大小:92.90KB ,
资源ID:9917641      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9917641.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(多位数码管动态显示.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

多位数码管动态显示.docx

1、多位数码管动态显示【006】多位数码管动态显示51点击数:2102发布日期:2006-4-16 16:04:00【收藏】【评论】【打印】【编程爱好者论坛】【关闭】实验目的:数码管动态显示多位数字。实验参考:笨笨工作室 实验五、多位数码动态显示。(查看原文)实验板: FB51A(查看)。 该实验用到实验板的资源电路图如下: 其中P0口是段码,低电平有效。P2口是位码,高电平有效。P2.0口控制第1个数码管,一直到P2.7口控制第8个。该板的段码表如下: 各个数码管的段码都是p0口的输出,即各个数码管输入的段码都是一样的, 为了使其分别显示不同的数字, 可采用动态显示的方式,即先只让最低位显示0(

2、含点),经过一段延时,再只让次低位显示1,如此类推。由视觉暂留,只要我们的延时时间足够短,就能够使得数码的显示看起来非常的稳定清楚。过程如下图。 采用上述方法思路编写如下: org 0000hstart: mov a,#08h ;0 ;段码 mov p0,a mov p2,#01h ;位码 lcall delay_1ms mov a,#0abh ;1 mov p0,a mov p2,#02h lcall delay_1ms mov a,#12h ;2 mov p0,a mov p2,#04h lcall delay_1ms mov a,#22h ;3 mov p0,a mov p2,#08h

3、lcall delay_1ms mov a,#0a1h ;4 mov p0,a mov p2,#10h lcall delay_1ms mov a,#24h ;5 mov p0,a mov p2,#20h lcall delay_1ms mov a,#04h ;6 mov p0,a mov p2,#40h lcall delay_1ms; mov a,#0aah ;7; mov p0,a mov p0,#0aah ;感觉用这句和上面两句实现一样,可能这种习惯以后会有用吧 mov p2,#80h lcall delay_1ms ljmp startdelay_1ms: mov r6,#2temp

4、: mov r5,#0ffh djnz r5,$ djnz r6,temp retend下载到板上得到测结果为从低到高八位分别显示0到7(含点)。上述方法逐次给P0或者P2赋值,一方面程序的复杂程度增加,另外一方面会使得程序的灵活性降低。如果要改变显示的数字,程序改动起来很麻烦。所以要用51单片机中常用的一种方法:查表法。例如P0口输出段码时,我们可以把要显示的段码放在一个表格中,然后每次从这个表格里面取数,送到P0口即可。P2口输出位码时,可以把要用的位码放在另一个表格里,每次从此表中取数,送入P2口。这样,如果要改变显示的数字,只需要改变表格里面的数。 org 0000hstart: mo

5、v r7,#0ffh ;r7,r6查表时送入变址寄存器a (因自加1后为0,所以预置ffh) mov r6,#0ffhloop: lcall play1 ;调用显示段码子程序 lcall play2 ;调用显示位码子程序 lcall delay_1ms cjne a,#80h,loop ;判断是否到了最左边的数,即第8个位码 ajmp startplay1: ;查表求段码子程序 ; mov a,r7 ; inc a; mov r7,a inc r7 ;这2句和上面三条语句实现功能相同 mov a,r7 ;a在这里做变址寄存器 mov dptr,#table1 ;表首址送dptr,dptr做基址

6、寄存器 movc a,a+dptr ;基址寄存器加变址寄存器寻址 mov p0,a retplay2: ;查表求位码子程序(原理同play1) mov a,r6 inc a mov r6,a mov dptr,#table2 movc a,a+dptr mov p2,a rettable1: db 08h,0abh,12h,22h,0a1h,24h,04h,0aah ;段码表table2: db 01h,02h,04h,08h,10h,20h,40h,80h ;位码表delay_1ms: mov r5,#02h ;延时1ms子程序temp: mov r4,#0ffh djnz r4,$ djn

7、z r5,temp retend下载到板上验证得到预想结果。C51实现如下(参考了AS的例程): #include #include / 包含了左移函数_crol_()void delayms(unsigned char ms); / 延时子程序unsigned char data dis_digit; / 位选通值, 传送到P2口用于选通当前数码管的数值, / 如等于0x01时,选通P2.0口数码管unsigned char code dis_code11=0x08,0xab,0x12,0x22,0xa1, / 0,1,2,3, 4 0x24,0x04,0xaa,0x00,0x20, 0xf

8、f; / 5,6,7,8,9, off unsigned char data dis_buf8; / dis_buf 显于缓冲区基地址unsigned char data dis_index; / 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量void main() P0 = 0xff; / 关闭所有数码管 P2 = 0x00; dis_buf0 = dis_code0; dis_buf1 = dis_code1; dis_buf2 = dis_code2; dis_buf3 = dis_code3; dis_buf4 = dis_code4; dis_buf5 = dis_code5;

9、 dis_buf6 = dis_code6; dis_buf7 = dis_code7; dis_digit = 0x01; / 首先选通P2.0 dis_index = 0; / 当前偏移量为0 while(1) P0 = dis_bufdis_index; / 段码送P0口 P2 = dis_digit; / 选能位(即位码) delayms(1); / 延时 dis_digit = _crol_(dis_digit, 1); / 位选通左移, 下次选通下一位 dis_index+; / 下一个段码 dis_index &= 0x07; / 见注释 void delayms(unsigne

10、d char ms) / 延时子程序(晶振12M) unsigned char i; 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时还是不变的,但

11、再次循环后其值为0x80,再与0x07后就变成0x00了,这样又从初始循环了。此句可用 if (dis_index = 8) dis_index = 0 代替,效果一样。通过C51用上述方法实现时,其段码放在了数组dis_code11中,再通过缓冲区数组dis_buf将程序中要调用的值装入,这样就可以用下标(偏移量)访问了。这样看上去有些繁锁,但其思路比较清楚,结构上也很明了,具有通用性,便于扩展。另外只要把程序中的延时加长,如delayms(250),下载到板上就可以看到实际上数码管是由低位到高位逐位显示的。 若单单就实现这个功能而言,可以直接调入段码数组dis_code11中下标从0到7的

12、值,而不必再设置缓冲数组dis_buf,实现如下:#include #include /_crol_()用 void delayms(unsigned char ms); /延时子程序unsigned char data dis_digit; /位选通值, 传送到P2口用于选通当前数码管的数值, /如等于0x01时,选通P2.0口数码管unsigned char code dis_code11=0x08,0xab,0x12,0x22,0xa1, / 0,1,2,3,4 0x24,0x04,0xaa,0x00,0x20, 0xff; / 5,6,7,8,9,off unsigned char d

13、ata dis_index; /显示索引, 用于标识当前显示的数码管和缓冲区的偏移量void main() P0 = 0xff; / 关闭所有数码管 P2 = 0x00; dis_index = 0; / 当前偏移量为0 dis_digit = 0x01; / 选通P2.0 while(1) P0 = dis_codedis_index; / 段码送P0口 P2 = dis_digit; / 位码送P2口 delayms(1); dis_digit = _crol_(dis_digit, 1); / 位选通左移, 下次选通下一位 dis_index+; dis_index &= 0x07; v

14、oid delayms(unsigned char ms) / 延时子程序(晶振12M) unsigned char i; while(ms-) for(i = 0; i 120; i+); 本来是想通过以下方式实现一次循环的: for (dis_index = 0; dis_index 8; dis_index+) P0 = dis_codedis_index; / 段码送P0口 P2 = dis_index+1; / 位码送P2口 delayms(1); 可得到的总是错误的结果:第0位到第2位这三位显示的是三个8,第3位显示的是7,高四位没有显示。加长延时逐位观察也没有发现错误的规律,对K

15、eil的调试也不熟悉,先把问题留到这,待找出原因后再补上。2006.5.2 找出原因啦,补上:今天又看了一下,找到上面的错误出在哪了。当时是想用dis_index的值做为位码的,即第一位显示0时,段码为dis_code0, 即dis_index值为0, 此时位码值为1。第二位显示1时,段码为dis_code1,即dis_index值为1,此时位码值为2。所以就简单用了个加1运算,将P0口的偏移值与P2口的位码联系起来。但仔细想一下位码的原理,上述方法显然是错的,只要再验证一步就明白了,即当第3位显示2时,段码为dis_code2, dis_index值为2,加1后为3,按上述方法时就将这个3作

16、为了位码,而正确的位码应该是4 (00000100B)。所以出错。实际上这个对应关系是有的,但不是简简单单的加1,位码应该是2的dis_index次幂。即:01122438416 幂次运算函数flaot pow(float x, float y)包含在math.h中, 返回值为xy (float型): for (dis_index = 0; dis_index 8; dis_index+) P0 = dis_codedis_index; / 段码送P0口 P2 = (char) pow(2, dis_index); / 位码送P2口 delayms(255); 再次下载到板上发现仍有问题, 即

17、延时很小的时候显示混乱,但加大延时时间(如程序中的值)可以观查到数码管是按位正确显示的。另外用这种方法产生的代码量也很大(从写入速度看,很明显)。这里仅提出了一个思路,只在此实验中适用,意义不大,到此为止。补充结束AS中绐出的例程是利用定时中断做的延时,参考修改到我的板上,程序如下:#include #include / 包含了左移函数_crol_()unsigned char data dis_digit; / 位选通值, 传送到P2口用于选通当前数码管的数值, / 如等于0x01时,选通P2.0口数码管unsigned char code dis_code11=0x08,0xab,0x12

18、,0x22,0xa1, / 0,1,2,3,4 0x24,0x04,0xaa,0x00,0x20, 0xff; / 5,6,7,8,9,off unsigned char data dis_buf8; / dis_buf 显于缓冲区基地址unsigned char data dis_index; / 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量void main() P0 = 0xff; /关闭所有数码管 P2 = 0x00; TMOD = 0x01; / 00000001B 定时计数器0工作在方式1,16位定时器/计数器 TH0 = 0xFC; TL0 = 0x17; / 预置初值

19、FC17H=64535D, 216-64535=1001us=1ms IE = 0x82; / 10000010B T0溢出中断允许 dis_buf0 = dis_code0x0; dis_buf1 = dis_code0x1; dis_buf2 = dis_code0x2; dis_buf3 = dis_code0x3; dis_buf4 = dis_code0x4; dis_buf5 = dis_code0x5; dis_buf6 = dis_code0x6; dis_buf7 = dis_code0x7; dis_digit = 0x01; / 选通第0位数码管 dis_index =

20、0; / 偏移初值为0 TR0 = 1; / 启动T0 while(1); / 循环等待中断void timer0() interrupt 1 / 定时器0中断服务程序, 用于数码管的动态扫描 TH0 = 0xFC; / 发生中断定时/计数器重装初值 TL0 = 0x17; / 感觉此处(及上)应该是0x18,而不是17,分析如下 P2 = 0x00; / 先关闭所有数码管 P0 = dis_bufdis_index; / 段码送P0口 P2 = dis_digit; / 位码送P2口 dis_digit = _crol_(dis_digit,1); / 位选通值左移, 下次中断时选通下一位数

21、码管 dis_index+; dis_index &= 0x07; / 8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描定时器/计数器的输入脉冲周期与机器周期一样, 为时钟振荡频率的1/12。晶振用12M时,输入脉冲周期间隔为1us。机器周期为 1us。设T0的初值为X,计算初值的方法:本例中定时器用方式1,是16位的定时器,即最大值为21665536,超过此值将发生溢出,引起中断,进入中断处理程序。这里要让其延时1ms,即1000us, 则有式216X1000,可得X64536,换算为16进制为FC18,即初值TH0=0xFC,TL0=0x18。即定时器由64536开始计数,经100

22、0次计数后值为65536,将发生定时中断,再进入中断处理子程序后,重新装和初值,如此循环下去。 而在上例中其装入的初值并非FC18(64536),而是FC17(64535)。我想大概认为其计数范围在065565的原因吧,我也想过这个问题,是用216-计数初值=中断间隔呢,还是用(216-1)-计数初值=中断间隔呢? 随手查了几本书, 说法不一,不过用前者的较多, 我自己也认为前者比较合理, 因为在计算机中16位的二进制不能表示65536, 在各位均为1时表示的值为65535, 即65535H=1111111111111111B, 也可以说65536是溢出得到的。而何时响应中断就成了关键,拿上例

23、来说,如设初值为64535(FC17),则计数到65535时,已经计数为1000个,即1ms,但此时并未发生溢出,因此也没有触发中断。而是在下一个计数后才发生。确切值应为1001us。若初值为64536(FC18),则恰好为所需值,所以上例中的初值应该用FC18而不是FC17。这仅仅是我自己的一点看法,至于是不是这样,还有待进一步考证。最终下载到实验板上结果:#补充#用Proteus仿真结果如下(某一状态的截图):该电路段码是按与板上接法对应的,即按前面的段码表次序连接。另外这个八位的仿真数码管最左端是第一位,最右端是第八位,与板上的顺序相反,所以接为了统一,该图以板为准连接。上图不加上拉电阻也可仿真出结果,只是P0口高电平显示为灰,即高阻。引用地址:

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

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