找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3002|回复: 10
打印 上一主题 下一主题
收起左侧

求助 数码管做个简单单片机时钟的秒数问题

[复制链接]
跳转到指定楼层
楼主
ID:284781 发表于 2018-2-22 16:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 imlwg 于 2018-2-22 16:16 编辑

德飞莱hc6800-es v2.0单片机,八位数码管做个简单时钟,1毫秒中断,运行后发现一秒的时间和现实相差太多,以下是代码,请教各位大虾是哪儿出了问题。

  1. #include<reg52.h>
  2. #include<intrins.h>

  3. #define duanxian P0

  4. sbit led138c=P2^4;
  5. sbit led138b=P2^3;
  6. sbit led138a=P2^2;
  7. unsigned char  duan[11]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x80};

  8. void timeinit();
  9. void displayinit();
  10.   void display();
  11.   void dely(unsigned int dat){while(dat--);}


  12. unsigned long int cnt=0;
  13. unsigned int sec=0,min=0,hour=0;
  14. unsigned char temp,b=0x00;

  15. void main()
  16. {        
  17.            timeinit();         
  18.     displayinit();
  19.    
  20.     while(1);
  21.         

  22.   
  23.   }
  24.   
  25.   void timeinit()
  26.   {
  27.           TMOD |=0X01;
  28.         TH0=0XFC;
  29.         TL0=0X18;
  30.         ET0=1;
  31.         EA=1;
  32.         TR0=1;
  33.   }        
  34.   
  35.   void displayinit()
  36.   {
  37.           unsigned int n=0;
  38.          do
  39.                 {        for(n=0;n<8;n++)
  40.                     {
  41.                     switch(n)
  42.                         {
  43.                                    case(0): led138c=0;led138b=0;led138a=0;duanxian=duan[0];break;
  44.                                    case(1): led138c=0;led138b=0;led138a=1;duanxian=duan[0];break;
  45.                               case(2): led138c=0;led138b=1;led138a=0;duanxian=0x80;break;
  46.                     case(3): led138c=0;led138b=1;led138a=1;duanxian=duan[0];break;
  47.                     case(4): led138c=1;led138b=0;led138a=0;duanxian=duan[0];break;
  48.                     case(5): led138c=1;led138b=0;led138a=1;duanxian=0x80;break;
  49.                     case(6): led138c=1;led138b=1;led138a=0;duanxian=duan[0];break;
  50.                     case(7): led138c=1;led138b=1;led138a=1;duanxian=duan[0];break;
  51.                 };
  52.                dely(100);
  53.                duanxian=0x00;
  54.                    };
  55.             }while(TF0==0);
  56.   }

  57.   void time0() interrupt 1
  58.   {
  59.    
  60.           TH0=0XFC;
  61.         TL0=0X18;
  62.         cnt++;
  63.         display();
  64.         if(cnt==100)
  65.         {
  66.                 cnt=0;
  67.                 sec++;
  68.                 temp=duan[10];
  69.             duan[10]=b;
  70.             b=temp;

  71.         };
  72.         if(sec==60){sec=0;min++;};
  73.         if(min==60){min=0;hour++;}
  74.         if(hour==24)hour=0;
  75.   }

  76.   void display()
  77.   {
  78.   
  79.         unsigned int a;
  80.    for(a=0;a<8;a++)
  81.         {
  82.       switch(a)
  83.           {case(0): led138c=0;led138b=0;led138a=0;duanxian=duan[sec%10];break;
  84.            case(1): led138c=0;led138b=0;led138a=1;duanxian=duan[sec/10%10];break;
  85.            case(2): led138c=0;led138b=1;led138a=0;duanxian=duan[10];break;
  86.            case(3): led138c=0;led138b=1;led138a=1;duanxian=duan[min%10];break;
  87.            case(4): led138c=1;led138b=0;led138a=0;duanxian=duan[min/10%10];break;
  88.            case(5):led138c=1;led138b=0;led138a=1;duanxian=duan[10];break;
  89.            case(6): led138c=1;led138b=1;led138a=0;duanxian=duan[hour%10];break;
  90.            case(7): led138c=1;led138b=1;led138a=1;duanxian=duan[hour/10%10];break;
  91.            };
  92.           dely(100);
  93.            duanxian=0x00;
  94.            };
  95.          
  96.            

  97.   }
复制代码


HC6800-ES V2.0.pdf

404.98 KB, 下载次数: 6

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:243146 发表于 2018-2-22 17:03 | 只看该作者
试试 TL0=0X66;
回复

使用道具 举报

板凳
ID:213173 发表于 2018-2-22 17:51 | 只看该作者
你的中断周期设置1ms,可是中断服务任务内容需要近8ms才能完成,时间怎么可能正确?
回复

使用道具 举报

地板
ID:123289 发表于 2018-2-22 18:19 | 只看该作者
普通晶振,如果程序写得好,日差可以做到一秒之内。
楼主用1ms中断,一般程序可以做到是日差是:
一天有86400000个1ms,每次中断会有±0.5时基脉冲的误差。
例:用12M,标准51的时基是1us。
则不可控日误差是:86400000*1us=86.4秒。
而要达成日差一秒之内,必须改变中断参数,初学者能做到百秒以内也可以了。
回复

使用道具 举报

5#
ID:284781 发表于 2018-2-23 19:40 | 只看该作者
wulin 发表于 2018-2-22 17:51
你的中断周期设置1ms,可是中断服务任务内容需要近8ms才能完成,时间怎么可能正确?

谢谢,你说的很对,后来我把显示放在了主程序while循环中,秒显示改善很多,但还不够精准,大约一分钟慢了一秒半的样子。还请教是哪的问题。

  1. #include<reg52.h>
  2. #include<intrins.h>

  3. #define duanxian P0

  4. sbit led138c=P2^4;
  5. sbit led138b=P2^3;
  6. sbit led138a=P2^2;
  7. unsigned char  duan[11]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x80};

  8. void timeinit();
  9. void displayinit();
  10.   void display();
  11.   void dely(unsigned int dat){while(dat--);}


  12. unsigned long int cnt=0;
  13. unsigned int sec=0,min=0,hour=0;
  14. unsigned char temp,b=0x00;

  15. void main()
  16. {       
  17.            timeinit();         
  18.     displayinit();
  19.    
  20.     while(1){        display();};
  21.        

  22.   
  23.   }
  24.   
  25.   void timeinit()
  26.   {
  27.           TMOD |=0X01;
  28.         TH0=0XFC;
  29.         TL0=0X18;
  30.         ET0=1;
  31.         EA=1;
  32.         TR0=1;
  33.   }       
  34.   
  35.   void displayinit()
  36.   {
  37.           unsigned int n=0;
  38.          do
  39.                 {        for(n=0;n<8;n++)
  40.                     {
  41.                     switch(n)
  42.                         {
  43.                                    case(0): led138c=0;led138b=0;led138a=0;duanxian=duan[0];break;
  44.                                    case(1): led138c=0;led138b=0;led138a=1;duanxian=duan[0];break;
  45.                               case(2): led138c=0;led138b=1;led138a=0;duanxian=0x80;break;
  46.                     case(3): led138c=0;led138b=1;led138a=1;duanxian=duan[0];break;
  47.                     case(4): led138c=1;led138b=0;led138a=0;duanxian=duan[0];break;
  48.                     case(5): led138c=1;led138b=0;led138a=1;duanxian=0x80;break;
  49.                     case(6): led138c=1;led138b=1;led138a=0;duanxian=duan[0];break;
  50.                     case(7): led138c=1;led138b=1;led138a=1;duanxian=duan[0];break;
  51.                 };
  52.                dely(100);
  53.                duanxian=0x00;
  54.                    };
  55.             }while(TF0==0);
  56.   }

  57.   void time0() interrupt 1
  58.   {
  59.    
  60.           TH0=0XFC;
  61.         TL0=0X18;
  62.         cnt++;
  63. //        display();
  64.         if(cnt==1000)
  65.         {
  66.                 cnt=0;
  67.                 sec++;
  68.                 temp=duan[10];
  69.             duan[10]=b;
  70.             b=temp;

  71.         };
  72.         if(sec==60){sec=0;min++;};
  73.         if(min==60){min=0;hour++;}
  74.         if(hour==24)hour=0;
  75.   }

  76.   void display()
  77.   {
  78.   
  79.         unsigned int a;
  80.    for(a=0;a<8;a++)
  81.         {
  82.       switch(a)
  83.           {case(0): led138c=0;led138b=0;led138a=0;duanxian=duan[sec%10];break;
  84.            case(1): led138c=0;led138b=0;led138a=1;duanxian=duan[sec/10%10];break;
  85.            case(2): led138c=0;led138b=1;led138a=0;duanxian=duan[10];break;
  86.            case(3): led138c=0;led138b=1;led138a=1;duanxian=duan[min%10];break;
  87.            case(4): led138c=1;led138b=0;led138a=0;duanxian=duan[min/10%10];break;
  88.            case(5):led138c=1;led138b=0;led138a=1;duanxian=duan[10];break;
  89.            case(6): led138c=1;led138b=1;led138a=0;duanxian=duan[hour%10];break;
  90.            case(7): led138c=1;led138b=1;led138a=1;duanxian=duan[hour/10%10];break;
  91.            };
  92.           dely(100);
  93.            duanxian=0x00;
  94.            };
  95.           
  96.           

  97.   }
复制代码

回复

使用道具 举报

6#
ID:284781 发表于 2018-2-23 19:50 | 只看该作者
yzwzfyz 发表于 2018-2-22 18:19
普通晶振,如果程序写得好,日差可以做到一秒之内。
楼主用1ms中断,一般程序可以做到是日差是:
一天有8 ...

谢谢,这样的话用中断做时钟微调中断参数只有用实践来检验程序的可用性了,感觉心里怪怪的。用ds1302能做精准吗?我目前还没学到1302.
回复

使用道具 举报

7#
ID:284781 发表于 2018-2-23 20:31 | 只看该作者
中断改为10毫秒效果好了很多。
回复

使用道具 举报

8#
ID:213173 发表于 2018-2-24 12:02 | 只看该作者
本帖最后由 wulin 于 2018-2-24 15:35 编辑
imlwg 发表于 2018-2-23 19:50
谢谢,这样的话用中断做时钟微调中断参数只有用实践来检验程序的可用性了,感觉心里怪怪的。用ds1302能做 ...

定时器用8位自动重装模式,周期250us,调整TH0、TL0值粗调,调整中断计数微调,精度可以控制在日秒内。
#include<reg52.h>
#include<intrins.h>
#define duanxian P0
sbit led138c=P2^4;
sbit led138b=P2^3;
sbit led138a=P2^2;
unsigned char  duan[11]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x80};
void timeinit();
void displayinit();
void display();
unsigned int cnt250us=0;
unsigned char sec=0,min=0,hour=12;
unsigned char temp,b=0x00;
bit ms_flag=0;
//void dely(unsigned int dat){while(dat--);}

void main()
{        
        timeinit();         
//        displayinit();//此函数没有意义
        while(1)
        {        

                display();
        }
}
void timeinit()                //250微秒@12.000MHz
{
        TMOD |= 0x02;                //设置定时器模式
        TL0 = 0x06;                //设置定时初值                +-粗调
        TH0 = 0x06;                //设置定时重载值  +-粗调
        TR0 = 1;                //定时器0开始计时
        ET0=1;
        EA=1;
}
/*
void displayinit()
{
        unsigned int n=0;
        do
        {        
                for(n=0;n<8;n++)
                {
                        switch(n)
                        {
                                case(0): led138c=0;led138b=0;led138a=0;duanxian=duan[0];break;
                                case(1): led138c=0;led138b=0;led138a=1;duanxian=duan[0];break;
                                case(2): led138c=0;led138b=1;led138a=0;duanxian=0x40;break;
                                case(3): led138c=0;led138b=1;led138a=1;duanxian=duan[0];break;
                                case(4): led138c=1;led138b=0;led138a=0;duanxian=duan[0];break;
                                case(5): led138c=1;led138b=0;led138a=1;duanxian=0x40;break;
                                case(6): led138c=1;led138b=1;led138a=0;duanxian=duan[0];break;
                                case(7): led138c=1;led138b=1;led138a=1;duanxian=duan[0];break;
                        }
                        dely(100);
                        duanxian=0x00;
                }
        }while(TF0);
}
*/
void time0() interrupt 1
{
        cnt250us++;
        if(cnt250us%4==0)
                ms_flag=1;
        if(cnt250us>=4000)//+-可以微调
        {
                cnt250us=0;
                sec++;
                temp=duan[10];
                duan[10]=b;
                b=temp;
        }
        if(sec>=60){sec=0;min++;};
        if(min>=60){min=0;hour++;}
        if(hour>=24)hour=0;
}

void display()
{
        static unsigned char a=0;
//        for(a=0;a<8;a++)
//        {
        if(ms_flag==1)//1ms循环显示1位
        {
                ms_flag=0;
                duanxian=0x00;
                switch(a)
                {
                        case(0): led138c=0;led138b=0;led138a=0;duanxian=duan[sec%10];a++;break;
                        case(1): led138c=0;led138b=0;led138a=1;duanxian=duan[sec/10%10];a++;break;
                        case(2): led138c=0;led138b=1;led138a=0;duanxian=duan[10];a++;break;
                        case(3): led138c=0;led138b=1;led138a=1;duanxian=duan[min%10];a++;break;
                        case(4): led138c=1;led138b=0;led138a=0;duanxian=duan[min/10%10];a++;break;
                        case(5): led138c=1;led138b=0;led138a=1;duanxian=duan[10];a++;break;
                        case(6): led138c=1;led138b=1;led138a=0;duanxian=duan[hour%10];a++;break;
                        case(7): led138c=1;led138b=1;led138a=1;duanxian=duan[hour/10%10];a=0;break;
                }
        //        dely(100);
        //        duanxian=0x00;
        }
}
回复

使用道具 举报

9#
ID:284781 发表于 2018-2-25 07:33 来自触屏版 | 只看该作者
wulin 发表于 2018-2-24 12:02
定时器用8位自动重装模式,周期250us,调整TH0、TL0值粗调,调整中断计数微调,精度可以控制在日秒内。
...

谢谢,我上机试试。
回复

使用道具 举报

10#
ID:284781 发表于 2018-2-25 07:43 来自触屏版 | 只看该作者
wulin 发表于 2018-2-24 12:02
定时器用8位自动重装模式,周期250us,调整TH0、TL0值粗调,调整中断计数微调,精度可以控制在日秒内。
...

谢谢,我上机试试
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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