找回密码
 立即注册

QQ登录

只需一步,快速开始

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

数码管时钟走时太快

  [复制链接]
ID:99130 发表于 2016-4-26 22:29 | 显示全部楼层 |阅读模式
这是我从管理员提供的链接那里找的资料,做出来和文章说明一样,走时过快。请问该如何修改?我才入门,是个小白,希望指正。谢谢那位作者和管理员的奉献。roteus仿真截图
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wpsA5D2.tmp.png



/*****************************************************************************
程序名称:六位数码管时钟表
编译器:Keil uVision 4
程序功能:上电后,程序按初始时间开始时钟演示,时间显示按24小时制。
    时间调整:按A键,显示加1,按B键,显示减1,按C键,清零
MCU:AT89C51
晶振:11.0592M
外围部件:
键盘:4按键A、B、C、D分别接在P1.0、P1.1、P1.2和P1.3上,低电平有效
     A、B、C键分别控制时、分、秒的选择,D键铵下进行时间调整。
显示:4位共阴极LED,P0口送显示数据,P1口低四位位选
内部资源:
使用定时计数器1中断,用于定时及显示
警告:
1. 按键未加防抖动程序
2. 此程序经过编译并通过Proteus仿真,未通过实物检验。
作者:花落水流红,空寂萧然山——萧然
完成日期:2012/6/11
============================================================================*/
#include <reg51.h>   //包含必要头文件
//定义按键
sbit HourAdjust = P1^0;   //时调整选择键
sbit MinuteAdjust = P1^1;  //分调整选择键
sbit SecondAdjust = P1^2;  //秒选择选择键
sbit Adjust = P1^3;    //调整键  
//定义标志位
bit SecondFlag = 0;    //秒标志   
bit FlashFlag = 0;    //秒闪标志
bit Second10Flag = 0;   //10秒标志
bit HourAdjustFlag = 0;   //时调整标志,A键按下置1,10秒后清0
bit MinuteAdjustFlag = 0;   //分调整标志,A键按下置1,10秒后清0  
bit SecondAdjustFlag = 0;   //秒调整标志,A键按下置1,10秒后清0  

unsigned char Led1,Led2,Led3,Led4,Led5,Led6;  //定义缓存
int TimeCount,Second10Count;   //定义计数器
unsigned char code LedTab[]=  //定义共阴极数码管表,0x00用于清除显示
   {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
void Delay100us(int Times);    //定义延时函数

//*****************************定时器中断服务程序******************************r
//程序功能:动态驱动数码管,同时完成定时功能。
void timer() interrupt 3 using 2
{
TR1 = 0;
TL1 = 0x13; TH1 = 0x2C; //重新赋值
P0 = 0x00;    //显示小时
P2 = 0xfe;
P0 = LedTab[Led1];
Delay100us(1);
P0 = 0x00;
P2 = 0xfd;
if(FlashFlag)   //秒显(1秒显,1秒隐)分前小数点
  P0 = LedTab[Led2] | 0x80;
else
  P0 = LedTab[Led2] & 0x7f;
Delay100us(1);   
P0 = 0x00;    //显示分
P2 = 0xfb;
P0 = LedTab[Led3];
Delay100us(1);
P0 = 0x00;
P2 = 0xf7;
if(FlashFlag)   //秒显秒前小数点
  P0 = LedTab[Led4] | 0x80;
else
  P0 = LedTab[Led4] & 0x7f;
Delay100us(1);
P0 = 0x00;    //显示秒
P2 = 0xef;
P0 = LedTab[Led5];
Delay100us(1);
P0 = 0x00;
P2 = 0xdf;
P0 = LedTab[Led6];
Delay100us(1);
TR1 = 1;

if(TimeCount < 100)  //秒计数器
  TimeCount++;
else
{
  TimeCount = 0x00;
  SecondFlag = 1;  //置位秒标志
  if(Second10Flag) //10秒计数器
   if(Second10Count < 20)
    Second10Count++;
   else
   {
    Second10Count = 0x00;  //10秒计数器清0
    Second10Flag = 0;   //清除10s标志
    HourAdjustFlag = 0;   //清除调整标志位
    MinuteAdjustFlag = 0;
    SecondAdjustFlag = 0;
   }
}
}
//============================================================================
main(void)
{
//初始化
int Second = 30;  //初始化时间
int Minute = 12;
int Hour = 20;
Led1 = 0x00;   //清除显存
Led2 = 0x00;
Led3 = 0x00;
Led4 = 0x00;
Led5 = 0x00;
Led6 = 0x00;
SecondFlag = 0;
TimeCount = 0x00;
//设置定时器中断
TMOD = 0x10f;   //GATE=0             01010001
       //C/T=0--定时/计数器1工作于定时方式
       //M1=1;M0=0--选择工作模式1,构成最大定时器
       //T0:在此程序不使用
TL1 = 0x13; TH1 = 0x2C; //指定定时时间为50ms  65536-50/(11.0592/12)=11283=2C13h
EA = 1;     //开总中断
TF1 = 0;
ET1 = 1;    //开定时器中断
TR1 = 1;    //开始计时
while(1)
{
//*****************************************************************************
//对时间进行调整程序
  if(SecondFlag)
  {
   if(Second%2 == 0)
    FlashFlag = 1;
   else
    FlashFlag = 0;
   if(Second < 59)
    Second++;
   else
   {
    if(Minute < 59)
     Minute++;
    else
    {
     if(Hour < 23)
      Hour++;
     else
      Hour = 0;
     Minute = 0;
    }
   Second = 0;
   }  
  SecondFlag = 0;  
  }
//-----------------------------------------------------------------------------
//*****************************************************************************
//时间调整程序
  if(HourAdjustFlag)   //调整时程序
   if(Second10Flag)
    if(FlashFlag)  //时秒显
    {
     Led1 = 0x0a; //时隐
     Led2 = 0x0a;
    }
    else
    {
     Led1 = Hour/10; //时显
     Led2 = Hour%10;
    }
   else
   {
    Led1 = Hour/10;
    Led2 = Hour%10;
   }
  else
  {
   Led1 = Hour/10;
   Led2 = Hour%10;
  }
  if(MinuteAdjustFlag)  //调整分程序
   if(Second10Flag)
    if(FlashFlag)  //分秒显
    {
     Led3 = 0x0a;
     Led4 = 0x0a;
    }
    else
    {
     Led3 = Minute/10;
     Led4 = Minute%10;
    }
   else
   {
    Led3 = Minute/10;
    Led4 = Minute%10;
   }
  else
  {
   Led3 = Minute/10;
   Led4 = Minute%10;
  }
  if(SecondAdjustFlag)  //调整秒程序,控制秒显
   if(Second10Flag)
    if(FlashFlag)
    {
     Led5 = 0x0a;
     Led6 = 0x0a;
    }
    else
    {
     Led5 = Second/10;
     Led6 = Second%10;
    }
   else
   {
    Led5 = Second/10;
    Led6 = Second%10;
   }
  else
  {
   Led5 = Second/10;
   Led6 = Second%10;
  }
  
  
  if(!HourAdjust)    //时调整按键按下
  {
   while(!HourAdjust);  //等待松开
   HourAdjustFlag = 1;  //置位时标志位
   MinuteAdjustFlag = 0; //清除分标志位
   SecondAdjustFlag = 0; //清除秒标志位
   Second10Flag = 1;  //置位10秒标志位
  }
  if(!MinuteAdjust)   //分调整键按下
  {
   while(!MinuteAdjust);
   MinuteAdjustFlag = 1;
   HourAdjustFlag = 0;
   SecondAdjustFlag = 0;
   Second10Flag = 1;
  }
  if(!SecondAdjust)   //秒调整键按下
  {
   while(!SecondAdjust);
   SecondAdjustFlag = 1;
   HourAdjustFlag = 0;
   MinuteAdjustFlag = 0;
   Second10Flag = 1;
  }
  if(!Adjust)     //调整键按下
  {
   while(!Adjust);
   if(HourAdjustFlag)  //调整时,加1
    if(Hour < 23)
    {
     Hour++;
     Second10Count = 0;
    }
    else
     Hour = 0;
   if(MinuteAdjustFlag) //调整分,加1
    if(Minute < 59)
    {
     Minute++;
     Second10Count = 0;
    }
    else    //调整秒,清零
     Minute = 0;
   if(SecondAdjustFlag)
    Second = 0;
  }
}
}
//********************************延时程序************************************
void Delay100us(int Times)
{
Times = Times * 100;
while(Times--);
}
//必要说明,定时器中断函数是经过计算的50ms,但在使用Proteus仿真时时间不准确。
//比实际表要快。对此不进行调整,因为中断函数是经过硬件检验通过的。









以上是程序全部内容,请高手解答

回复

使用道具 举报

ID:99130 发表于 2016-4-26 23:19 | 显示全部楼层
上面的内容说的是秒走得太快。
于是我把TMOD=0x10f;修改为TMOD = 0x01;,秒过快解决了,但是,最后一位秒的亮度变亮了,其他5位数码管变暗了一些,这个问题又该怎么解决?
回复

使用道具 举报

ID:7485 发表于 2016-4-27 09:47 | 显示全部楼层
本帖最后由 ahshmj 于 2016-4-27 09:53 编辑

“TL1 = 0x13; TH1 = 0x2C; //指定定时时间为50ms  65536-50/(11.0592/12)=11283=2C13h” 这个公式有误。
应为65536-50000*11.0592/12



回复

使用道具 举报

ID:104472 发表于 2016-4-27 09:53 | 显示全部楼层
时钟不准,因为是直接从时钟芯片里面找数据,软件只是读写,不参与时间,所以,最主要的问题,不是软件,而是硬件,时钟芯片附近的硬件电路,这个才是时钟不准的根源。
回复

使用道具 举报

ID:99130 发表于 2016-4-27 10:59 | 显示全部楼层
ahshmj 发表于 2016-4-27 09:47
“TL1 = 0x13; TH1 = 0x2C; //指定定时时间为50ms  65536-50/(11.0592/12)=11283=2C13h” 这个公式有误。
...

结果是???
回复

使用道具 举报

ID:99130 发表于 2016-4-27 10:59 | 显示全部楼层
jiajuntao 发表于 2016-4-27 09:53
时钟不准,因为是直接从时钟芯片里面找数据,软件只是读写,不参与时间,所以,最主要的问题,不是软件,而 ...

怎么改
回复

使用道具 举报

ID:99130 发表于 2016-4-27 11:01 | 显示全部楼层
800.jpg 这是电路图 在本论坛里找的
回复

使用道具 举报

ID:99130 发表于 2016-4-27 11:01 | 显示全部楼层

楼下有电路图
回复

使用道具 举报

ID:96682 发表于 2016-4-27 12:23 | 显示全部楼层
如果要做成实物的话则没必要修改,因为只要板子断电后还需重新设置修改时间有点麻烦。还是建议 LZ 换个有时钟芯片的源代码。
回复

使用道具 举报

ID:117037 发表于 2016-4-27 13:13 来自手机 | 显示全部楼层
估计是晶振问题,不是12m的
回复

使用道具 举报

ID:117039 发表于 2016-4-27 13:20 | 显示全部楼层
你把晶振换成可调的
回复

使用道具 举报

ID:99130 发表于 2016-4-27 14:12 | 显示全部楼层
17864267395 发表于 2016-4-27 13:13
估计是晶振问题,不是12m的

换成12M行吗
回复

使用道具 举报

ID:97438 发表于 2016-4-27 15:20 | 显示全部楼层
加个时钟芯片吧,ds1302或者ds3231,一般做时钟的都会加这个模块的

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:7485 发表于 2016-4-27 20:00 | 显示全部楼层
如果11.0592M的晶振偏快,换12.0000M的会更快。
回复

使用道具 举报

ID:117147 发表于 2016-4-27 20:33 | 显示全部楼层
11.0592M的晶振偏快,换12.0000M的会更快

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:7485 发表于 2016-4-27 20:53 | 显示全部楼层
不知道你是从哪里弄来的这段程序,是你自己编写的??

//设置定时器中断
TMOD = 0x10f;   //GATE=0             01010001
//你的这一句将定时起设置为13位模式,所以很快很快!低4位不能设置成F,应设置成0。应为:
TMOD = 0x10;   
       //C/T=0--定时/计数器1工作于定时方式
       //M1=1;M0=0--选择工作模式1,构成最大定时器
       //T0:在此程序不使用
TL1 = 0x13; TH1 = 0x2C; //指定定时时间为50ms  65536-50/(11.0592/12)=11283=2C13h
//这一句是错误的,应为:
TL1 = 0x00;     //这一句如果不要时钟会更准一些
TH1 = 0x4C;

EA = 1;     //开总中断
TF1 = 0;  //这一句是多余的
ET1 = 1;    //开定时器中断
TR1 = 1;    //开始计时

经过这样改动,就准确了。

评分

参与人数 1黑币 +100 收起 理由
admin + 100 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:7485 发表于 2016-4-27 20:55 | 显示全部楼层
另外,其他地方也粗略的看了一下,同样存在许多错误,令人费解。

你自己看着改吧。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:96682 发表于 2016-4-27 21:15 | 显示全部楼层
LZ,要是用软件仿真的话,仅需在最后面的延时程序那里修改为: Times = Times* 200;
就能正常秒显示。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:104472 发表于 2016-4-28 09:26 | 显示全部楼层

你用的是中断模拟时钟的,肯定不准,与晶振有关,建议你用1302,
外围器件也不多,比较准些
回复

使用道具 举报

ID:7485 发表于 2016-4-28 20:13 | 显示全部楼层
仅仅使用单片机,不使用时钟芯片也会很准的,精度取决于晶振的精度。

单片机断电以后时钟不走。同样需要加后备电源。
回复

使用道具 举报

ID:7485 发表于 2016-4-28 20:15 | 显示全部楼层
如果经过一段时间的运行,知道每日的误差,可以通过软件定时进行修正,将会比时钟芯片更准。
回复

使用道具 举报

ID:99130 发表于 2016-4-28 20:49 | 显示全部楼层
ahshmj 发表于 2016-4-28 20:15
如果经过一段时间的运行,知道每日的误差,可以通过软件定时进行修正,将会比时钟芯片更准。

我直接换了一个程序

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:99130 发表于 2016-4-28 20:50 | 显示全部楼层
ahshmj 发表于 2016-4-27 20:55
另外,其他地方也粗略的看了一下,同样存在许多错误,令人费解。

你自己看着改吧。

不用改了 直接换了程序
回复

使用道具 举报

ID:99130 发表于 2016-4-28 20:51 | 显示全部楼层
ahshmj 发表于 2016-4-27 20:53
不知道你是从哪里弄来的这段程序,是你自己编写的??

//设置定时器中断

TL1 = 0x00;     //这一句如果不要时钟会更准一些
TH1 = 0x4C;
是这两句都不要还是只有第一句不要
回复

使用道具 举报

ID:99130 发表于 2016-4-28 20:52 | 显示全部楼层
ahshmj 发表于 2016-4-27 20:53
不知道你是从哪里弄来的这段程序,是你自己编写的??

//设置定时器中断

程序是坛子里找的
回复

使用道具 举报

ID:7485 发表于 2016-5-1 16:42 | 显示全部楼层
越快乐越堕落 发表于 2016-4-28 20:51
TL1 = 0x00;     //这一句如果不要时钟会更准一些
TH1 = 0x4C;
是这两句都不要还是只有第一句不要

TL1 = 0x00;     //这一句不要。

只能是=0x00是可以不要。否则不可省略。

因为当定时器溢出后,后自动进位到0x0000,经过中断跳转,到本语句时,一般将经过4个时钟周期以上,TL1应该=4以上,这个时候你在设置成“0”,反而不准了。
回复

使用道具 举报

ID:153199 发表于 2016-12-17 11:25 | 显示全部楼层
看一下晶振频率
回复

使用道具 举报

ID:155166 发表于 2016-12-18 00:54 | 显示全部楼层
觉得是晶振不匹配
回复

使用道具 举报

ID:57657 发表于 2016-12-18 11:06 | 显示全部楼层
本帖最后由 npn 于 2016-12-18 11:09 编辑

晶振频率选择不当或定时器中断的计数延迟程序有问题,加入gps或gsm模块或互联网、低频长波等类型的授时模块,随时原子钟永久免费同步时间,亿年误差不会超过1秒。
回复

使用道具 举报

ID:150126 发表于 2016-12-18 14:33 | 显示全部楼层
换个12M的晶振试试
回复

使用道具 举报

ID:74784 发表于 2016-12-18 16:23 | 显示全部楼层
数字种最好选用6或12或24MHz的晶振~~~~~~~~~~~
回复

使用道具 举报

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

时钟走得太快,肯定是程序有误!
时钟走得稍快,多数是晶振不准。市场销售的硬件时钟不准,都是晶振不准,晶振32768Hz决定时钟精准度,包括1302,1302本身正确应用不会有误差。
proteus仿真时钟走得稍快,是因为proteus有自己的运行时钟,会产生累计误差。网友可以将proteus仿真时钟运行几个小时看看,都会有误差。
回复

使用道具 举报

ID:143871 发表于 2016-12-18 18:01 | 显示全部楼层
可用校时程序修改
回复

使用道具 举报

ID:111634 发表于 2016-12-18 20:58 | 显示全部楼层
yangglong 发表于 2016-12-18 18:01
可用校时程序修改

提高单片机控制的时钟精度,与单片机本身的晶振频率无关,而应提高时钟芯片外接晶振频率(一般为32768Hz)的精准度。一般不宜用校时程序修正,时钟芯片外接晶振的频率有一定误差和发散性,校时程序只能对某一晶振频率特定误差进行校时修正,另外换一个晶振,原来的校时修正程序无用。
回复

使用道具 举报

ID:155754 发表于 2016-12-18 22:13 | 显示全部楼层
一同学习了
回复

使用道具 举报

ID:104472 发表于 2016-12-23 18:06 | 显示全部楼层
回复

使用道具 举报

ID:149771 发表于 2016-12-23 18:27 | 显示全部楼层
可以调时间的
回复

使用道具 举报

ID:153199 发表于 2016-12-25 17:05 | 显示全部楼层
请问那楼主解决了吗,求分享经验
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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