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

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


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


废话太多——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  


 

文章评论2条评论)

登录后参与讨论

shenzhenghao1984_379129130 2010-4-29 20:30

受教了,希望您以后能多来我的博客,多多指导

12864_944456583 2010-4-29 08:49

博主同志,这个中断,中断后,你去清除和计数前,还是在跑着的。换句话说,中断的时间,不受你去清除计数的几个us控制的。只要你在下次中断前清除了,就不会影响精度。 你所说的多长时间校准是不错的注意。每个产品可能会不同,这个数值你装在EEPROM里,上电调用,定时弥补即可。并且这个参数是手动设置的。

用户1547904 2007-12-13 15:21

强!!!支持支持!!

用户741296 2007-12-12 09:51

牛啊!
相关推荐阅读
shenzhenghao1984_379129130 2016-04-08 23:11
大师教你如何制作一个简单的16位CPU
如何制作一个简单的16位CPU,首先我们要明确CPU是做什么的,想必各位都比我清楚,百度的资料也很全。。。。。 如果想要制作一个CPU,首先得明白下计算机的组成结构(或者计算机的替代品,因为并不是只...
shenzhenghao1984_379129130 2016-04-08 23:11
揭秘:三极管开关电路设计详细过程
三极管除了可以当做交流信号放大器之外,也可以做为开关之用。严格说起来,三极管与一般的机械接点式开关在动作上并不完全相同,但是它却具有一些机械式开关所没有的特点。 图1所示,即为三极管电子开关的基本电...
shenzhenghao1984_379129130 2016-02-19 22:45
写给电子小白:ADC和DAC常用的56个技术术语
采集时间 采集时间是从释放保持状态(由采样-保持输入电路执行)到采样电容电压稳定至新输入值的1 LSB范围之内所需要的时间。采集时间(Tacq)的公式如下: 混叠 根据采样定理,超过奈奎斯特频率...
shenzhenghao1984_379129130 2016-02-08 22:56
基于STM32的家庭服务机器人系统设计
引言   随着人工智能和传感器技术的发展,机器人已从工厂的结构化环境进入人们的日常生活环境,机器人不仅能自主完成工作,还能与人共同协作完成任务或在人的指导下完成任务。家庭服务机器人是智能家居系统的一个...
shenzhenghao1984_379129130 2016-02-07 01:03
AVR微控制器处理正交编码器信号只需不到1μs的时间
高速读取正交编码器信号(比如1MHz,或1m/s,分辨率是1μm)通常需要专用硬件。本设计实例展示了一种简单的方案,它只使用了一个型号为ATtiny2313A的AVR微控制器就能实现这个功能(图)。当...
shenzhenghao1984_379129130 2016-01-12 21:57
工程师必看:深扒《星球大战7》五款最牛飞船机械结构
《星球大战:原力觉醒》(Star Wars: The Force Awakens)是科幻电影《星球大战》系列的第七部,由J·J·艾布拉姆斯执导,黛茜·雷德利、约翰·波耶加、哈里森·福特、奥斯卡·伊萨克...
我要评论
2
7
关闭 站长推荐上一条 /2 下一条