找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

51单片机四位数码管计时器代码有严重的重影?

查看数: 831 | 评论数: 34 | 收藏 0
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2023-11-19 11:41

正文摘要:

遇到的问题是: 仿真结果运行异常,数码管不能正常显示。

回复

ID:332444 发表于 2023-11-21 10:46
借助这帖就说说阻塞与查询延时的转换,把代码if(++sy==0)修改while(++sy)就是阻塞延时,阻塞延时放前后都可以.
ID:1100331 发表于 2023-11-21 00:06
鹈鹕 发表于 2023-11-20 15:53
你这个程序实际上是两个错误,第一个是我12楼说的那个,第二个我昨天晚上没看出来。第一个错误会导致这个计 ...

谢谢你,目前所有的问题已经解决。确实有位选码(显示掩码)逻辑颠倒的问题。详情见我最新的置顶楼。
另外,我的中断函数里除了”timer==20“这一句有错误,也忘了令timer=0;所以后来无论怎么改timer都不影响速度(因为都是从0到255再到0)(哭笑)
ID:1100331 发表于 2023-11-20 18:54
yzwzfyz 发表于 2023-11-20 09:32
"扫屏显示的切换应当用最少的指令完成,在不多于8个LED的情况下:三条指令即可完成,对于STC的单片机,10us ...

谢谢你的分享。你讲的这个技巧看起来很惊艳,我会下来仔细琢磨并实践的
ID:1100331 发表于 2023-11-20 18:51
ydatou 发表于 2023-11-20 09:09
仿真结果和实验结果应该相差不大。
这种现象表示仿真模型和实验硬件不符。

问题已经解决了,您说得真对,确实是硬件有一些问题没注意到或者是没法注意到(哭笑)
ID:1100331 发表于 2023-11-20 18:48
tyrl800 发表于 2023-11-20 08:31
你这个消隐程序错了,改成P3=0xff,你应该把电路板原理图发上来才能解决下载后的问题

谢谢你的回复,消隐程序正反逻辑颠倒确实是问题之一
ID:1100331 发表于 2023-11-20 18:46
tyrl800 发表于 2023-11-19 19:49
板子与仿真原理图肯定不一样才这样

谢谢你的回复,我已经解决了这个问题。板子与仿真原理图不一致确实是问题之一
ID:397054 发表于 2023-11-20 15:53
你这个程序实际上是两个错误,第一个是我12楼说的那个,第二个我昨天晚上没看出来。第一个错误会导致这个计时器快10倍,我以为你所说的“重影”实际是走的快引起来显示8的原因,但早上起来我想想即使快10倍也不至于引起“重影”现象,即充其量秒的个位会因为变化快看起来像8,其他的就不会了,秒的10位肯定看得清楚因为快10倍也就是1秒一变,分钟就更加不会了。中午吃完饭没事就把你的程序复制下来稍加修改适合我的板子,上电一看果然4个8字,但凭经验看明显的不是因为跳变快引起的,这跟我前一段时间碰到的一个故障非常像,因为有这个经验仔细看了一下你的有关显示的代码,看出了问题所在,跟我的那个故障的原因虽然不完全一样,但现象确实会很像——是你把显示掩码(显示掩码,很多书上称为“位码”)的正负逻辑弄颠倒了,你的显示掩码电路肯定是负逻辑,一般的都是,而你把它当正逻辑来处理了,即display_time()函数中P3=,,,那4行右面是正逻辑01、02、04、08,这样该亮的不亮不该亮的3个同时亮,这么个扫描循环当然就乱七八糟了,所以正确的数值应该是这4个数的反码才对,或者你把他们的反码替代他们比如FE替代01等或者懒得算的话就在每个数字前面加个非号“~”即可。

之所以两个数码管时正常,那是假象,是因为只有两个数码管,它仍然遵循该亮的不亮其它都亮的规则,但这时的“其它”只有1个了,所以看上去就正常了,但这时,两位是颠倒的,即秒的10位显示的是个位数值,而个位显示的是十位。

第一个错误也要改否则的话根本就谈不上准确,且错误还不止那一句,虽然都是同一个错误。
ID:34149 发表于 2023-11-20 15:17
你的位驱动是I0口直接驱动吗?
没有原理图,确实挺难帮你分析的
ID:57657 发表于 2023-11-20 14:18
51单片机8位并行IO口一组,段码和位码不是并行发送的,所以需要消隐,16位以上不需要,新的位码送出去了,段码还是旧的,所以就出现影子了。
ID:1073939 发表于 2023-11-20 14:00
小小小初学者 发表于 2023-11-20 13:26
谢谢各位的回复,学业繁忙,我等晚上或者明天再一一回复。不过目前我越来越感觉问题不是代码,而是板子。因 ...

把板子的原理图发出来。
ID:1100331 发表于 2023-11-20 13:30
这个是老师发的原理图,单片机型号是STC 89C51RC

DIY_MCU_51_REV1.0(2015.11.06)原理图.pdf

1.08 MB, 下载次数: 3

ID:1100331 发表于 2023-11-20 13:26
谢谢各位的回复,学业繁忙,我等晚上或者明天再一一回复。不过目前我越来越感觉问题不是代码,而是板子。因为我只保留输出秒个位的代码后,在调试中,拔掉了四个位选线。接下来按道理,其中只有一个位选线能让对应的数码管闪亮,但实际情况是:每条位选线都能让数码管闪亮
这可能意味着位选线4个端总是0xff!!(即让数码管生效)
我换了我两个舍友的板子重新烧,结果是一样的,感觉同时焊错的可能性比较小....

ID:332444 发表于 2023-11-20 10:39
忘记打括号了,加的要括号,或者删除+(ls==8||ls==32?SmZiFu[10]:0)加小数点,另外6位的话删除最后2位即64和128,修改条件 if(ls==0||ls==32)
ID:272119 发表于 2023-11-20 10:10
应该很好调试的,我没有仔细看楼主的程序只看了图片,如果不是消隐反向的话,建议楼主先不要忙那么多位显示,首先调试最后一位显示1->9正常后辐射4位就简单的多,如果连一位都不能正常显示那仔细磨驱动代码吧.
ID:332444 发表于 2023-11-20 09:39
数码管动态驱动是最基本的,它的原则:消隐-送段值-送位值-延时,按这样的顺序执行和编写代码.
看仿真图片数码管应该是共阳,我这里有个简单的荔枝,显示固定的日期小数点分割,修改了一下,仿真和下载开发板试看.
  1. #include "reg52.h"
  2. unsigned char code SmZiFu[]={63,6,91,79,102,109,125,7,127,111,128,0};//共阴0-9.
  3. void main()
  4. {
  5.         unsigned char sy=0,my=0,ls=0;
  6.         while(1)
  7.         {
  8.                 if(++sy==0)
  9.                 {
  10.                         P0=255;P3=0;
  11.                         if(ls==0||ls==8)ls=1;else ls*=2;//控制4位数码管显示
  12.                         P0=255-(SmZiFu[ls==1?2
  13.                         :ls==2?0
  14.                         :ls==4?2
  15.                         :ls==8?3
  16.                         :ls==16?1
  17.                         :ls==32?1
  18.                         :ls==64?0
  19.                         :ls==128?7
  20.                         :11]+(ls==8||ls==32?SmZiFu[10]:0));
  21.                         P3=ls;
  22.                 }
  23.         }
  24. }
复制代码



ID:123289 发表于 2023-11-20 09:32
"扫屏显示的切换应当用最少的指令完成,在不多于8个LED的情况下:三条指令即可完成,对于STC的单片机,10us不到就完成了,例:8个LED哪个亮(位选)受P1控制,显示什么内容(段码)由P0决定。
要点:技巧如下!!!
先将哪个LED需要亮的参数事先准备好,放在:P1_OUT变量中,同样将这个LED需要显示的段码放在P0_OUT中。【这个做法最关键,不要直接切换操作P0、P1口,而是通过这两个变量来操作。原因是,无论你用多长时间对P1_OUT、P0_OUT进行操作,操作期间,显示不受影响。】
切换:
第一条指令:关断所有显示:P1=FFH              ;关闭所有显示
第二条指令:切换LED段码:P0=P0_OUT         ;这时显示已关,切换不会有残留,重影,闪烁了。
第三条指令:更新显示的LED管:P1=P1_OUT  ;点亮需要显示的LED,例如:11101111B
【这个做法是最优秀的扫描显示切换方法,用时最短,最合理,没有之二!!!】
重复一下关键点:事先处理准备好变量P1_OUT、P0_OUT的值。"
ID:1073939 发表于 2023-11-20 09:09
仿真结果和实验结果应该相差不大。
这种现象表示仿真模型和实验硬件不符。
ID:275826 发表于 2023-11-20 08:31
小小小初学者 发表于 2023-11-19 21:41
你好,谢谢你的回复,首先我很抱歉我的叙述可能有些混乱,因为这东西搞得我有些焦头烂额。接下来我来回复 ...

你这个消隐程序错了,改成P3=0xff,你应该把电路板原理图发上来才能解决下载后的问题
ID:1100331 发表于 2023-11-19 21:41
鹈鹕 发表于 2023-11-19 20:30
我根本就没法理解你的叙述,牛头不对马嘴的,数码管如何重影呢,它要么亮要么就不亮,总是清晰的,它就是个 ...

你好,谢谢你的回复,首先我很抱歉我的叙述可能有些混乱,因为这东西搞得我有些焦头烂额。接下来我来回复你的质疑:
1.重影或者说残影,这个是我最原本代码确实存在的问题,因为没有消影。这个问题在大家的帮助下解决了。现在在仿真上是一切正常的。
2.我在1楼说的现象是真实的,只不过造成那个现象的代码和我在9楼说的现象所使用的代码相比,做了很多修改,两者代码不一样,现象也不一样,不是一回事。
现在的问题是,即时添加了消影,数码管仍然不能正确显示(大部分时间是8,9这种多个段接通的数字)。
我尝试在代码中删除显示分钟的,保留显示秒钟的,那么烧录到机子后,将有这样的现象:显示秒钟的两位正常显示,分钟位也显示(代码中已经删去显示分钟了),并且显示的是秒钟两位个位和十位的叠加
  1. void display_time()
  2. {

  3.         P3=0X00;
  4.         DIGIT_O=segCode[seconds/10];
  5.         P3 = 0x04;
  6.         delay(5);

  7.         P3=0X00;
  8.         DIGIT_O=segCode[seconds%10];
  9.         P3 = 0x08;
  10.         delay(5);
  11. }
复制代码
ID:213173 发表于 2023-11-19 21:12
小小小初学者 发表于 2023-11-19 19:12
为了深究原因,我尝试把秒的位选代码删去,只保留分钟。发现一个奇怪的现象:在仿真里正常,高两位数码管显 ...


ID:397054 发表于 2023-11-19 20:30
我根本就没法理解你的叙述,牛头不对马嘴的,数码管如何重影呢,它要么亮要么就不亮,总是清晰的,它就是个普通物体怎么个重影法,,,,但根据你的程序看,我知道你说的“重影”是什么意思,只是用这个词实在是太词不达意了;而且另一个现象更加不可能,【如果只显示两位,即秒的部分,那么则不会出现上述问题,】——这根本不可能,4位都都显示时,决不会4位都“重影”,左面两位不“重影”,右面的两位才“重影”,右面的是秒,而你偏偏说秒正常,这完全不可能 。。。。。
ID:397054 发表于 2023-11-19 19:58
消隐并不重要,display_time函数中没有最后一行也不致引起很大的影响,几乎看不出来。
ID:397054 发表于 2023-11-19 19:54
把这行语句多看几遍,直到看出问题来:

if(timer==20){                  //到达1s
ID:275826 发表于 2023-11-19 19:49
板子与仿真原理图肯定不一样才这样
ID:36322 发表于 2023-11-19 19:26

P3 = 0x00;
DIGIT_O=segCode[seconds/10];
P3 = 0x01;
delay(5);

延时可适当加长
ID:1100331 发表于 2023-11-19 18:44
谢谢大家的回复,我重新在每个数码管显示前都添加了消隐(禁用位选,输出空段码两种方式都尝试了)
仿真结果均正常,但是烧录到机子里仍然有重影
ID:1100331 发表于 2023-11-19 18:28
Hephaestus 发表于 2023-11-19 16:37
在每条
        DIGIT_O=   ;
前面加上

谢谢,我这样试了。仿真恢复正常,但是板子仍然有重影好无奈啊
ID:1100331 发表于 2023-11-19 18:26
xianfajushi 发表于 2023-11-19 16:09
每个数码管显示前都要消隐,是每个。

谢谢,我试了试后仿真没有问题,但是烧到板子上仍然有重影,不知道是哪的问题了现在(苦),头大
ID:213173 发表于 2023-11-19 17:57
核心问题是动态扫描数码管没有消隐。
  1. #include "reg51.h"
  2. #include <intrins.h>
  3. #define uchar unsigned char
  4. #define uint unsigned int
  5. #define DIGIT_O P0//设置P0位数码管数据输出端

  6. //定义时分秒变量
  7. uchar timer,seconds,minutes,hours;        
  8. uchar timer,seconds,minutes,hours = 0;

  9. //共阳极数字码表
  10. uchar code segCode[]={
  11.                 0xc0,0xf9,0xa4,0xb0,
  12.                 0x99,0x92,0x82,0xf8,
  13.                 0x80,0x90,0x88,0x83,
  14.                 0xc6,0xa1,0x86,0x8e};
  15. //定时器中断服务程序
  16. void timer0_ISR() interrupt 1
  17. {
  18.         TH0 = 0xee;   // 设置定时初值,一次中断为5ms
  19.         TL0 = 0x00;
  20.         timer++;
  21.         if(timer==200) //到达1s
  22.         {            
  23.                 timer=0;
  24.                 seconds++;
  25.                 if (seconds == 60)
  26.                 {
  27.                         seconds = 0;
  28.                         minutes++;
  29.                         if (minutes == 60)
  30.                         {
  31.                                 minutes = 0;
  32.                                 hours++;
  33.                                 if (hours == 24)
  34.                                 {
  35.                                         hours = 0;
  36.                                 }
  37.                         }
  38.                 }
  39.         }        
  40. }
  41. void delay(uint x)   //延时xms
  42. {
  43.         uint i,j;
  44.         for(i=x;i>0;i--)
  45.                 for(j=114;j>0;j--);
  46. }

  47. //初始化硬件
  48. void init()
  49. {
  50.         TMOD = 0x01;  // 定时器0工作在模式1(16位定时器)
  51.         TH0 = 0xee;   // 设置定时初值
  52.         TL0 = 0x00;
  53.         ET0 = 1;      // 允许定时器0中断
  54.         EA = 1;       // 允许总中断
  55.         TR0 = 1;      // 启动定时器0
  56.         seconds=0;
  57.         minutes=0;
  58.         hours=0;   
  59. }
  60. // 显示时间
  61. void display_time()
  62. {
  63.         static uchar data i;
  64.         P3&=0xf0;//消隐
  65.         switch(i)
  66.         {
  67.                 case 0: DIGIT_O=segCode[minutes/10]; break;
  68.                 case 1: DIGIT_O=segCode[minutes%10]&0x7f; break;//加点
  69.                 case 2: DIGIT_O=segCode[seconds/10]; break;
  70.                 case 3: DIGIT_O=segCode[seconds%10]; break;
  71.         }
  72.         P3|=0x01<<i;
  73.         i=++i%4;
  74. }


  75. void main()
  76. {
  77.         init();
  78.         while(1)
  79.         {        
  80.                 display_time();        
  81.                 delay(1);
  82.         }
  83. }
复制代码
ID:1064915 发表于 2023-11-19 17:22
DIGIT_O=0XFF;
再复制3个
ID:883242 发表于 2023-11-19 16:37
在每条
        DIGIT_O=   ;
前面加上
        P3 = 0x0;
试试。
ID:332444 发表于 2023-11-19 16:09
每个数码管显示前都要消隐,是每个。

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表