注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

易拉罐的博客

心静自然凉

 
 
 

日志

 
 

转 如何使自制的单片机电子钟走时精准  

2013-01-16 21:43:18|  分类: 单片机开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

     相信有很多爱好单片机的朋友都用单片机制作过电子钟,这的确是一个很好的锻炼课题。可是当在你享受成功的快乐或是在朋友面前炫耀的时候,你会突然间发现你当初对着电视校准的电子钟的时间竟然变快或是变慢了。于是你就尝试用各种方法来调整它的走时精度,但是最终的效果还是不尽人意,只好每过一段时间手动调整一次了。渐渐的你有点烦了,不再去管它或是直接弃之不用。

我和大家一样对此深有体会,于是我开始查找翻阅资料,试图找出一个解决的好方法。终于有一天……

废话太多——stop

原因分析:

1.单片机电子钟的计时脉冲基准是由外部晶振的频率经过12分频后提供,采用内部的定时/计数器来实现计时功能。所以,外接晶振频 率精确度直接影响电子钟计时的准确性。

2. 单片机电子钟利用内部定时/计数器溢出产生中断(12M晶振一般为50ms)再乘以相应的倍率来实现秒、分、时的转换。大家都知道从定时/计数器产生中断请求到响应中断需要3-8个机器周期(如不明白请参考其它资料),定时中断子程序中的数据入栈和重装定时/计数器的初值还需要占用数个机器周期,还有从中断入口转到中断子程序也要占用一定的机器周期。    例如:

       ORG       00H

       LJMP      START

       ORG       0BH

       LJMP      TIMER                 2个机器周期

       ORG       30H

START:

       MOV      30H,       #0          

       MOV      31H,       #0

       MOV      32H,       #0

       MOV      33H,       #0

       MOV      20H,       #10        

       MOV      21H,       #2

       MOV      SP,   #40H             

       MOV      IP,   #00H

       MOV      IE,   #82H                     ;EAET0

       MOV      TMOD,   #01H              ;定时器模式1      

       MOV      TH0,       #03CH           ;50MS初裝值

       MOV      TL0,       #0B0H

       SETB      TR0                             ;启动TR0

LOOP:

       ……

 

TIMER:                                             ;定時器中断子程序

       PUSH      ACC                            2个机器周期

       PUSH      PSW                            2个机器周期

       MOV      TL0,              #0B0H+6+3          

       MOV      TH0,       #03CH

       ……

 

                            RETI

                            END      

从上面的例子大家可以看出从中断入口到定时/计数器初值的低8位装入需要占用2+2+2=6个机器周期。所以我们在编程时一般会把这8个机器周期加入定时/计数器的初值。但是从定时/计数器溢出中断请求到执行中断需要几个机器周期(3-8个机器周期)我们很难确定其准确值,因此导致了电子钟计时不准。

解决方法:

1.采用高精度晶振方案

 虽然采用高精度的晶振可以稍微提高电子钟计时的精确度,但是其并不是导致电子钟计时不准的主要因素,而且高精度的晶振价格较高,所以不必采用此方案。

2.动态同步修正方案

 从程序入手,采用动态同步修正方法给定时/计数器赋初值。动态同步修正方法:由于定时/计数器溢出后又会从0开始自动加数,固在给定时/计数器再次赋值前将定时/计数器低位(TL0)中的值和初始值相加后一并送入定时/计数器中,此时定时/计数器中的值即为动态同步修正后的准确值。例如:

                 TIMER:                                 

                 PUSH ACC

                 PUSH PSW

                 MOV  A, #0B0H

                 ADD   A, TL0                      ;初值和TL0中的数相加即为同步修正值

                 MOV  TL0,       A                  ;修正值送定时/计数器低8

                 MOV  TH0,      #03CH

                 ……

                

                 RETI

采用了此种方法后相信你的电子钟的精度已经大大提高了。别走开,后面内容更精彩。

3.自动调整方案

  采用了同步修正方案后电子钟的精度虽然提高了很多,但是由于晶振频率的偏差和一些其它未知因素(同一块电路板、同样的程序换了一片单片机后走时误差却不一样,不知是何原因)的影响,时间长了仍然会有积累误差。为此我设计出了此自动调整方案,实际也是一种容错技术。其自动调整原理为:实测出误差1秒所需的时间,然后每隔这样一段时间后就对秒进行加1或减一调整。例如:电子钟每过50小时就慢1秒,其自动调整程序如下:

                 TIMER:                                                ;定時中斷程序

                 PUSH ACC                                  ;數據保護

                 PUSH PSW

                 ……

 

T_3:

                 INC    A_1

                 MOV  A,   A_1

                 CJNE  A,   #50,       RETI_1         ;50小时了吗?

                 INC    S_1                                    ;50小时秒加1

                 MOV  A_1,      #OOH  

RETI_1:

                 POP    PSW

                 POP    ACC

                 RETI

使用此方法调整较费时间,但是效果非常好,经实验一次调整可以将月误差控制在1秒左右,如按此方法再次测出误差1秒所需的天数并进行二次调整,其精度会更高。

电子钟源程序:(修改后)修改前的源程序可以到论坛<单片机技术交流>里看我发的<简单的电子钟源程序>一文

           S_1     EQU      30H                            ;秒寄存器

           M_1    EQU      31H                            ;分寄存器

           H_1    EQU      32H                            ;時寄存器

           A_1    EQU      33H                            ;自动调整寄存器

           ORG   00H

           LJMP  START

           ORG   03H

           RETI

           ORG   0BH                                   ;定時中斷入口

           LJMP  TIMER        

           ORG   13H

           RETI

           ORG   1BH

           RETI

           ORG   30H

START:

           MOV  S_1,       #0                        ;秒、分、時寄存器清0

           MOV  M_1,      #0

           MOV  H_1,      #0

           MOV  A_1,      #0

           MOV  20H,      #10                      ;0.5秒鐘中斷次數,0.5s=500ms=50msx10

           MOV  21H,      #2                      ;20.5秒即為1

           MOV  SP,  #40H                          ;堆棧指針設置

           MOV  IE,   #82H                          ;開定時器0中斷及總中斷

           MOV  TMOD,  #01H                          ;定時器0模式1

           MOV  TH0,      #03CH                        ;50ms初值

           MOV  TL0,       #0B0H

           SETB  TR0                                   ;啟動定時器0

LOOP:

           ACALL     DISP                                  ;調用顯示

           JNB    P3.4,      MT                      ;查詢分調整鍵

           JNB    P3.5,      HT                       ;查詢時調整鍵

           AJMP LOOP

MT:                                            ;分調整

           ACALL     DISP

           JNB    P3.4,      MT                      ;鍵消抖

           INC    M_1                                   ;分加1

           MOV  A,   M_1                    

           CJNE  A,   #60,       LOOP                  ;沒到60分返回,到60分清0   

           MOV  M_1,      #0

           AJMP LOOP

HT:                                             ;時調整

           ACALL     DISP

           JNB    P3.5,      HT

           INC    H_1

           MOV  A,   H_1

           CJNE  A,   #24,       LOOP

           MOV  H_1,      #0

           AJMP LOOP

DISP:                                         ;顯示子程序

           MOV  DPTR,   #NUMTAB                        ;表地址送數據指針

           MOV  A,   M_1                            ;分送A

           MOV  B,    #10              

           DIV    AB                              ;十進制調整

           ADD   A,   R0                        ;查表偏移量調整

           MOVC      A,   @A+DPTR                        ;查表    

           MOV  P1,  A                         ;分十位送p1口顯示

           CLR    P3.2                                   ;開分十位顯示

           ACALL     D1MS                                ;延時1ms

           SETB  P3.2                                   ;關顯示

           MOV  A,   B                          ;分個位p1口顯示          

           ADD   A,   R0                

           MOVC      A,   @A+DPTR

           MOV  P1,  A

           CLR           P3.3

           ACALL     D1MS

           SETB  P3.3

           MOV  A,   H_1                            ;時送A

           MOV  B,    #10

           DIV    AB

           ADD   A,   R0

           MOVC      A,   @A+DPTR

           MOV  P1,  A                 

           CLR    P3.0                                   ;顯示時十位

           ACALL     D1MS

           SETB  P3.0

           MOV  A,   B

           ADD   A,   R0

           MOVC      A,   @A+DPTR

           MOV  P1,  A

           CLR    P3.1                                   ;顯示時個位

           ACALL     D1MS

           SETB  P3.1

           RET                                       ;返回

TIMER:                                             ;定時中斷程序

           PUSH ACC                                  ;數據保護

           PUSH PSW

           MOV  A,   #0B0H                        ;同步修正

           ADD   A,   TL0

           MOV  TL0,       A                         ;重置50ms定時值

           MOV  TH0,      #03CH

           DJNZ  20H,      RETI_1                       ;0.5秒了嗎?

           MOV  20H,      #10

           CPL    25H.0                                ;取反秒點閃爍標志位

           JNB    25H.0,   T_1                      ;標志位為0T_1

           MOV  R0,  #0                        ;查表偏移量寄存器置0(不顯示秒點)

           AJMP T_2

T_1:

           MOV  R0,  #10                      ;查表偏移量寄存器置10(顯示秒點,秒點每秒閃爍1次)

T_2:   

           DJNZ  21H,      RETI_1                       ;1秒了嗎?

           MOV  21H,      #2

           INC    S_1                             ;秒加1

           MOV  A,   S_1

           CJNE  A,   #60,       RETI_1                ;60秒了嗎?

           MOV  S_1,       #0                        ;60秒清0

           INC    M_1                                   ;分加1

           MOV  A,   M_1

           CJNE  A,   #60,       RETI_1                ;60分了嗎?

           MOV  M_1,      #0

           INC    H_1                                   ;時加1

           MOV  A,   H_1

           CJNE  A,   #24,       T_3               ;24小時了嗎?

           MOV  H_1,      #00H

T_3:                                                         ;自动调整

           INC    A_1

           MOV  A,   A_1

           CJNE  A,   #50,       RETI_1

           INC    S_1

           MOV  A_1,      #OOH  

RETI_1:

           POP    PSW

           POP    ACC

           RETI

D1MS:                                              ;1毫秒延時

           MOV  R7,  #2

D_1:

           MOV  R6,  #250

           DJNZ  R6,  $

           DJNZ  R7,  D_1

           RET

NUMTAB:

           DB      10H,0D3H,48H,41H,83H,21H,20H,53H,00H,01H;不顯示秒點

           DB      14H,0D7H,4CH,45H,87H,25H,24H,57H,04H,05H;顯示秒點

           END  

  评论这张
 
阅读(323)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017