一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 3630|回复: 20
收起左侧

[其他综合] 如何使自制的单片机电子钟走时精准(分享)

[复制链接]
发表于 2014-7-12 16:05 | 显示全部楼层 |阅读模式
本帖最后由 LBQ691477940 于 2014-7-12 16:10 编辑

   相信有很多爱好单片机的朋友都用单片机制作过电子钟,这的确是一个很好的锻炼课题。可是当在你享受成功的快乐或是在朋友面前炫耀的时候,你会突然间发现你当初对着电视校准的电子钟的时间竟然变快或是变慢了。于是你就尝试用各种方法来调整它的走时精度,但是最终的效果还是不尽人意,只好每过一段时间手动调整一次了。渐渐的你有点烦了,不再去管它或是直接弃之不用。
原因分析:
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                 ;开EA﹑ET0
   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               ;2个机器周期               
           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                          ;2个0.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                              ;数据保护;2个机器周期
           PUSH PSW            ;2个机器周期
     CLR    C              ;1个机器周期
           MOV      A,    #0B7H     ;同步修正本身应0B0但由于中断跳入和堆栈占了几个周期故为0B7
           ADD       A,    TL0          ;初值和TL0中的数相加即为同步修正值
           MOV      TL0, A                      ;结果赋给TL0
           MOV  A,   #03CH
     ADDC  A, TH0          ;如果产生进位连进位也加上
           MOV      TH0,  A          ;结果赋给TH0
;C语言为:
; CY = 0;
; TL0 += 0Xb7;        //同步修正本身应0B0但由于中断跳入和堆栈占了几个周期故为0B7
; TH0 = 0x3C+( unsingend char )CY
           DJNZ      20H,        RETI_1                            ;到0.5秒了吗?
           MOV      20H,        #10
           CPL        25H.0                                      ;取反秒点闪烁标志位
           JNB        25H.0,     T_1                          ;标志位为0转T_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      

点评

加分超字数了,通过串口自校准会更好  发表于 2014-7-12 17:07

评分

参与人数 3一乐金币 +42 收起 理由
antlu + 2 很给力!
liuhaob + 20 很给力!
littlebadbay + 20 我可玩不转汇编,方法可行,不过还是依赖手.

查看全部评分

发表于 2014-7-12 16:14 | 显示全部楼层
汇编写的?如果断电再上电,会不会时间归零再重新开始计时?
发表于 2014-7-12 16:30 | 显示全部楼层
还是用带后备电源的专用时钟电路才是正途, 费这么大劲计算没什么意思, 一掉电什么都没有了.
发表于 2014-7-12 16:31 | 显示全部楼层
appeng 发表于 2014-7-12 16:14
汇编写的?如果断电再上电,会不会时间归零再重新开始计时?

这是肯定的。还是RTC芯片实用
发表于 2014-7-12 18:55 来自手机 | 显示全部楼层
电子钟迷,什么类型的都有。要说精准还是用二手的GPS模块,价廉物美,一秒不差。
发表于 2014-7-12 19:26 | 显示全部楼层
我晕倒,,

难道就不考试温度对晶振产生的影响.
一月误差1S对我来说,暂时比较难实现...
 楼主| 发表于 2014-7-12 19:41 | 显示全部楼层
junyee 发表于 2014-7-12 19:26
我晕倒,,

难道就不考试温度对晶振产生的影响.

这篇文章是我多年前留下来的并非原创我只是分享,不过之前自己也有用到过这种方法效果还是相当不错的哟
发表于 2014-7-13 16:28 | 显示全部楼层
这个应该对晶振加用温度补偿电路。
发表于 2014-7-13 16:52 | 显示全部楼层
很好,谢谢分享
发表于 2014-7-14 09:59 | 显示全部楼层
这方法,误差也是比较大的,32.768K的晶体14分频后得到500MS的时钟,这个是没有软件误差的

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-5-18 11:16 , Processed in 0.075636 second(s), 48 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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