找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11083|回复: 37
收起左侧

编写的一个8个数码管显示的数字时钟 但不能正常运行 求大神帮忙看看

[复制链接]
ID:125657 发表于 2016-6-7 15:17 | 显示全部楼层 |阅读模式
编写的一个8个数码管显示的数字时钟可调闹钟  但不能正常运行   程序还没编完!!  
#include<reg51.h>
sbit KEY1=P1^0;
sbit KEY2=P1^1;
sbit KEY3=P1^2;
sbit LED=P2^2;
code unsigned char tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char StrTab[8];
unsigned char minute=19,hour=23,second;
void delay(unsigned int cnt)
{
    while(--cnt);
}
void displaypro(void)
{
    StrTab[0]=tab[hour/10];
    StrTab[1]=tab[hour%10];  
    StrTab[2]=0x40;  
    StrTab[3]=tab[minute/10];  
    StrTab[4]=tab[minute%10];  
    StrTab[5]=0x40;  
    StrTab[6]=tab[second/10];  
    StrTab[7]=tab[second%10];  
}
main()
{
    TMOD=0x01;  //定时器0 10ms
    TH0=0xd8; //初始值
    TL0=0xf0;
    ET0=1;
    TR0=1;
    TMOD=0x10; //定时器1 动态扫描
    TH1=0xf8;
    TL1=0xf0;
    ET1=1;
    TR1=1;
    EA=1;
    displaypro();
    while(1)
    {
    if(!KEY3)
        {
delay(10000);
if(!KEY3)
        {
          hour++;
          if(hour==24)
          hour=0;
          displaypro();
        }
        }
     if(!KEY2)
    {
    delay(10000);
    if(!KEY2)
      {
      minute++;
        if(minute==60)
   minute=0;
   displaypro();
       }
     }
        if(!KEY1)
    {
    delay(10000);
    if(!KEY1)
      {
      second++;
        if(second==60)
   second=0;
   displaypro();

   }
}
}
}
//定时器1中断//
void time1_isr(void)interrupt 3 using 0
{
    static unsigned char num;
    TH1=0xf8;
    TL1=0xf0;
      switch(num)
      {
        case 0:P3=0xfe;P0=StrTab[num];break;
     case 1:P3=0xfd;P0=StrTab[num];break;
     case 2:P3=0xfb;P0=StrTab[num];break;
     case 3:P3=0xf7;P0=StrTab[num];break;
     case 4:P3=0xef;P0=StrTab[num];break;
     case 5:P3=0xdf;P0=StrTab[num];break;
     case 6:P3=0xbf;P0=StrTab[num];break;
     case 7:P3=0x7f;P0=StrTab[num];break;
     default:break;
      }
      num++;
      if(num==8)
          num=0;
}
//定时器0//
void time(void)interrupt 1 using 1
{
  static unsigned char count;
  TH0=0xd8;
  TL0=0xf0;
  count++;
  switch(count)
  {
    case 0:
    case 20:
    case 40:
    case 60:
    case 80:displaypro();break;
    case 50:P1=~P1;break;   //半秒 LED 闪烁
    default:break;
  }
  if(count==100)
  {
    count=0;
    second++;
    if(second==60)
      {
      second=0;
      minute++;
      if(minute==60)
        {
minute=0;
hour++;
if(hour==24)
   hour=0;
     }
      }
   }
}

回复

使用道具 举报

ID:125657 发表于 2016-6-7 15:25 来自手机 | 显示全部楼层
正常显示是12-12-12这样  但是运行后确实这样显示
UC_Photo_001.jpg
回复

使用道具 举报

ID:125657 发表于 2016-6-7 15:25 来自手机 | 显示全部楼层
而且也不能正常计时
回复

使用道具 举报

ID:123289 发表于 2016-6-7 16:56 | 显示全部楼层
图不清楚
回复

使用道具 举报

ID:123289 发表于 2016-6-7 16:57 | 显示全部楼层
写程序习惯不好,没有注释。
回复

使用道具 举报

ID:123289 发表于 2016-6-7 17:40 | 显示全部楼层
1、取8个RAM单元(编号X0至X7)对应存放8个LED的显示内容(译码后的LED段显示值)。
2、取一个单元做计数器K,从0至7循环计数,分别对应指示显示8个LED。
3、时间中断只用一个,考虑到8个LED扫描显示,中断时常数取5ms,中断后做下列事件:
3.1、处理一下计数器(屏上显示的数字,如时间年月日时分秒,或计数值等)……
3.2、先关所有LED显示,防止切换闪动;
3.3、将K+1(注:当K=8时清K=0。),将K所指示的Xn(当然需要将对应需要显示的时钟位,译成LED码后再送入Xn)送入显示数据口,再打开K所指定的LED。
要点:每次中断只显示一个LED,且先关后显示。
回复

使用道具 举报

ID:125692 发表于 2016-6-7 17:55 | 显示全部楼层
重点需要强调出来, 别人能够很容易看懂
回复

使用道具 举报

ID:125657 发表于 2016-6-8 08:12 来自手机 | 显示全部楼层
yzwzfyz 发表于 2016-6-7 17:40
1、取8个RAM单元(编号X0至X7)对应存放8个LED的显示内容(译码后的LED段显示值)。
2、取一个单元做计数 ...

能不能帮我修改下程序   看哪里错了  
回复

使用道具 举报

ID:123289 发表于 2016-6-8 10:03 | 显示全部楼层
先将各行的注释加上去,让别人知道你的目的,再看你错在哪里。
也许:当你完成注释时,自己就已经明白了。
回复

使用道具 举报

ID:123289 发表于 2016-6-8 10:14 | 显示全部楼层
要点:每次中断只显示一个LED,且先关后显示!!!
回复

使用道具 举报

ID:123289 发表于 2016-6-8 10:50 | 显示全部楼层
     case 0:P3=0xfe;P0=StrTab[num];break;
     case 1:P3=0xfd;P0=StrTab[num];break;
     case 2:P3=0xfb;P0=StrTab[num];break;
     case 3:P3=0xf7;P0=StrTab[num];break;
     case 4:P3=0xef;P0=StrTab[num];break;
     case 5:P3=0xdf;P0=StrTab[num];break;
     case 6:P3=0xbf;P0=StrTab[num];break;
     case 7:P3=0x7f;P0=StrTab[num];break;
这是T1中断所做的事,虽然每次切换了LED,但显示的内容却是相同的StrTab[num],这就必须保证,在每次中断之前,StrTab[num]已被刷新,仅改变num是不够的,因为显示的不是num,而是StrTab[num]!
如果某一次中断前未刷新,则轮显示的LED必定是上一轮的LED值,如此就混淆了。
你用两个时间中断的目的是什么?能保证正确地刷新LED数据么?
回复

使用道具 举报

ID:125657 发表于 2016-6-8 15:20 | 显示全部楼层
#include<reg51.h>
sbit KEY1=P1^0;        //定义端口参数
sbit KEY2=P1^1;
sbit KEY3=P1^2;
sbit LED=P2^2;        //定义指示灯

code unsigned char tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};  //共阴极数码管0-9
unsigned char StrTab[8]; //定义缓冲区
unsigned char minute=19,hour=23,second;        //定义初始化

void delay(unsigned int cnt)
{
    while(--cnt);
}

void displaypro(void)
{
    StrTab[0]=tab[hour/10];         //显示小时
    StrTab[1]=tab[hour%10];  
    StrTab[2]=0x40;                   //显示-
    StrTab[3]=tab[minute/10];  //显示分钟
    StrTab[4]=tab[minute%10];  
    StrTab[5]=0x40;                          //显示-
    StrTab[6]=tab[second/10];          //显示秒
    StrTab[7]=tab[second%10];  
}
main()
{
    TMOD |=0x01;  //定时器0 10ms 用于计时
    TH0=0xd8;        //初始值
    TL0=0xf0;
    ET0=1;
    TR0=1;

    TMOD |=0x10;        //定时器1 动态扫描
    TH1=0xf8;
    TL1=0xf0;
    ET1=1;
    TR1=1;
    EA=1;
    displaypro();  //调用显示处理函数

    while(1)
    {
    if(!KEY3)
        {
        delay(10000);
        if(!KEY3)          //按键3去抖以及动作
               {
                 hour++;
                 if(hour==24)
                 hour=0;
                 displaypro();
               }
        }

     if(!KEY2)           //按键2去抖以及动作
    {
    delay(10000);
    if(!KEY2)
      {
      minute++;
        if(minute==60)
          minute=0;
          displaypro();
       }
     }

               if(!KEY1)
    {
    delay(10000);
    if(!KEY1)           //按键1去抖以及动作
      {
      second++;
        if(second==60)
          second=0;
          displaypro();


   }
}
}
}

//定时器1中断//
void time1_isr(void)interrupt 3 using 0          //定时器1动态扫描
{
    static unsigned char num;
    TH1=0xf8;
    TL1=0xf0;
      switch(num)

      {
        case 0:P3=0xfe;P0=StrTab[num];break;  //分别调用缓冲区的值进行扫描
            case 1:P3=0xfd;P0=StrTab[num];break;
            case 2:P3=0xfb;P0=StrTab[num];break;
            case 3:P3=0xf7;P0=StrTab[num];break;
            case 4:P3=0xef;P0=StrTab[num];break;
            case 5:P3=0xdf;P0=StrTab[num];break;
            case 6:P3=0xbf;P0=StrTab[num];break;
            case 7:P3=0x7f;P0=StrTab[num];break;
            default:break;
      }

      num++;           //扫描8次,使用8个数码管
      if(num==8)
          num=0;
}

//定时器0//
void time(void)interrupt 1 using 1
{
  static unsigned char count;  //定义内部局部变量
  TH0=0xd8;
  TL0=0xf0;
  count++;
  switch(count)
  {
    case 0:
    case 20:
    case 40:
    case 60:
    case 80:displaypro();break;                 //隔一定时间调用显示处理显示处理
    case 50:P1=~P1;break;          //半秒 LED 闪烁
    default:break;
  }
  if(count==100)
  {
    count=0;
    second++;
    if(second==60)
      {
      second=0;
      minute++;
      if(minute==60)
        {
        minute=0;
        hour++;
        if(hour==24)
          hour=0;
            }
      }
   }
}

     
回复

使用道具 举报

ID:125657 发表于 2016-6-8 15:22 | 显示全部楼层

电路

电路



回复

使用道具 举报

ID:125657 发表于 2016-6-8 15:25 | 显示全部楼层
yzwzfyz 发表于 2016-6-8 10:50
case 0:P3=0xfe;P0=StrTab[num];break;
     case 1:P3=0xfd;P0=StrTab[num];break;
     case 2:P3 ...

我上传了标注的程序和电路图了      他上面不是定义了    StrTab[0]=tab[hour/10];
    StrTab[1]=tab[hour%10];  
    StrTab[2]=0x40;  
    StrTab[3]=tab[minute/10];  
    StrTab[4]=tab[minute%10];  
    StrTab[5]=0x40;  
    StrTab[6]=tab[second/10];  
    StrTab[7]=tab[second%10];  

改变NUM就好了     
回复

使用道具 举报

ID:125657 发表于 2016-6-8 15:35 | 显示全部楼层
linlin2222 发表于 2016-6-7 17:55
重点需要强调出来, 别人能够很容易看懂

已经标注了  大神帮我看看吧
回复

使用道具 举报

ID:111634 发表于 2016-6-8 19:09 | 显示全部楼层
参考一下楼上的5种电子钟电路、程序和仿真
回复

使用道具 举报

ID:111634 发表于 2016-6-8 19:09 | 显示全部楼层
楼上的5种电子钟摘自张志良编著《单片机实验实训100例》 ISBN 978-7-5124-1603-1,北航社出版
回复

使用道具 举报

ID:111634 发表于 2016-6-8 19:11 | 显示全部楼层
读懂了别人正确有效的电路和程序,才能找出自己电路和程序的错误。
回复

使用道具 举报

ID:111634 发表于 2016-6-8 19:12 | 显示全部楼层
张志良编著《单片机实验实训100例》每个案例程序均有详细分析,每条语句均有注释。
回复

使用道具 举报

ID:111634 发表于 2016-6-8 19:15 | 显示全部楼层
你的程序没有定义标记和注释,别人需花多少时间才能读懂理顺,然后再帮你寻找错误,可能吗?
回复

使用道具 举报

ID:111634 发表于 2016-6-8 19:17 | 显示全部楼层
先Proteus仿真一下

模拟电子钟.jpg


以上摘自张志良编著《单片机实验实训100例》 ISBN 978-7-5124-1603-1,北航社出版
回复

使用道具 举报

ID:123289 发表于 2016-6-9 11:40 | 显示全部楼层
上图的设计不是很好的:缺点如下:
1、用了6个(U2-U7),不经济。
改进,用一个晶体管阵列(一个IC里集成有7个三极管),驱动LED的阳极(共阳)。
2、LED的选择驱动用了P1,P3两个口,不利于程序编写。
改进,只用P1口驱动,这里软件编写方便许多。
3、四个发光二极管,两两串并,一般红色压降为1.4V,两只2.8V,未经限流直接接到IO口,使得2.2V电压(5V-2.8V)加在CPU的芯片上,CPU发热大。
改进:设LED是10mA一只。两组并为20mA,串入一只电阻[R=(5V-2.8V-0.3V)/20=100欧,0.3V是IO口的压降]。
回复

使用道具 举报

ID:123289 发表于 2016-6-9 11:44 | 显示全部楼层
写书的人不一定认真。
U2-U7驱动的LED 7个段,都未限流,都是错误的做法。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:50 | 显示全部楼层
有人与我讨论电路,很高兴,首先表示感谢,并希望能交个朋友。有关问题我的看法如下:
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:50 | 显示全部楼层
本电路设计为静态显示,虽然用了6片595,但595价格低廉。用595的好处是串行传送,节省了I/O端口。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:51 | 显示全部楼层
若用动态显示,7段加6位位控,需13根I/O端口线。因为不排除剩余端口线还需其他用途。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:51 | 显示全部楼层
本帖最后由 zl2168 于 2016-6-9 18:00 编辑

用6片595的另一好处是,便于修正时钟参数。而且修正位是快速闪烁(每秒亮暗各5次),修正期间时钟继续正常运行 。你Proteus仿真一下,试试效果。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:52 | 显示全部楼层
本帖最后由 zl2168 于 2016-6-9 17:58 编辑

"驱动用了P1,P3两个口,不利于程序编写",完全没有这个问题,看你程序怎么编写。P3口是串行传送数据,P1口是位控加修正位快速闪烁。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:53 | 显示全部楼层
至于没有限流电阻,那是为了电路图面简洁,连晶振和复位电路都没画。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:53 | 显示全部楼层
实际电路应该加限流电阻,不过无论是595、还是80C51,实际流不出很大电流的,长期工作也不会使芯片过热。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 17:55 | 显示全部楼层
若仅仅是6位时钟,没有修正及修正位快速闪烁功能,电路可简单的多。
回复

使用道具 举报

ID:111634 发表于 2016-6-9 18:03 | 显示全部楼层
时钟动态显示电路,并保留时钟修正及修正位快速闪烁功能,我下一次编一个。
回复

使用道具 举报

ID:96682 发表于 2016-6-10 00:58 | 显示全部楼层
你的仿真图只能使用采用的数码管段码。
回复

使用道具 举报

ID:111634 发表于 2016-6-10 19:32 | 显示全部楼层
yzwzfyz 发表于 2016-6-9 11:40
上图的设计不是很好的:缺点如下:
1、用了6个(U2-U7),不经济。
改进,用一个晶体管阵列(一个IC里集 ...

请看一下我的回复。
回复

使用道具 举报

ID:111634 发表于 2016-6-10 22:51 | 显示全部楼层
wc86110 发表于 2016-6-10 00:58
你的仿真图只能使用采用的数码管段码。

这个当然!电路与程序是相配的,程序是根据电路和功能编写的,任何案例都是如此。
回复

使用道具 举报

ID:194701 发表于 2017-5-7 15:06 | 显示全部楼层
读懂了别人正确有效的电路和程序,才能找出自己电路和程序的错误
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

Powered by 单片机教程网

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