单片机电子钟汇编程序(本文来自伟纳电子论坛,经笔者修改后的成果)

;单片机电子钟汇编程序
;-----------------------------------
HOU_S BIT  P2.7;时十位
HOU_G BIT  P2.6;时个位
MIN_S BIT  P2.5;分十位
MIN_G BIT  P2.4;分个位
SEC_S BIT  P2.3;秒十位
SEC_G BIT  P2.2;秒个位
H_KEY BIT  P3.4;时调整键
M_KEY BIT  P3.5;分调整键
LEDBUS EQU  P0;显示数据总线
SECOND EQU  30H;秒寄存器
MINUTE EQU  31H;分寄存器
HOUR   EQU  32H;时寄存器
TIM_1  EQU  33H;定时器0中断次数
TIM_2  EQU  34H;定时器1中断次数
;-----------------------------------
ORG   0000H
LJMP  INIT
ORG   000BH
LJMP  TIMER0
ORG   30H
;-----------------------------------
;单片机初始化
INIT:
      MOV  SECOND,#0;秒置0
   MOV  MINUTE,#0;分置0
   MOV  HOUR,#0;开机后显示0
   MOV  TIM_1,#10;中断10次为0.5秒
   MOV  TIM_2,#2;0.5*2=1秒
   MOV  SP,#5FH;堆栈指针指向5FH
   MOV  TMOD,#01H;定时器0为模式1
   MOV  TH0,#03CH
   MOV  TL0,#0B0H;50MS初值(晶振12M)
   SETB ET0
   SETB TR0
   SETB EA
;------------------------------------
;主程序
MAIN:
     JNB  H_KEY,HT;时调整键按下转到HT
  JNB  M_KEY,MT;分调整键按下转到MT
  ACALL DISP;调用子程序
  AJMP MAIN;转到LOOP继续检测控制键的状态
;--------------------------------------
;时间调整
;---------------分调整------------------
MT:
   ACALL  DISP;调用显示子程序
   JNB  M_KEY,MT;判断按键是否松开
   INC  MINUTE;分加一
   MOV  A,MINUTE
   CJNE A,#60,MAIN;判断是否加到60
   MOV  MINUTE,#0;分到60变为0
   MOV  SECOND,#0;秒置0
   AJMP MAIN
;----------------时调整------------------
HT:
   ACALL  DISP;调用显示子程序
   JNB  H_KEY,HT;判断按键是否松开
   INC  HOUR;时加1 
   MOV  A,HOUR
   CJNE A,#24,MAIN
   MOV  HOUR,#0;判断时是否到24,到24后清0
   AJMP  MAIN
;-----------------------------------------
;显示子程序
DISP:
     MOV  DPTR,#LEDTAB;数码管显示首地址送DPTR
  MOV  A,SECOND ;秒放入ACC
  MOV  B,#10  
  DIV  AB
  MOVC A,@A+DPTR
  MOV  LEDBUS,A
  CLR  SEC_S
  ACALL D1MS
  SETB SEC_S
  MOV  A,B
  MOVC A,@A+DPTR
  MOV  LEDBUS,A
  CPL  SEC_G
  ACALL D1MS
  SETB SEC_G
  MOV  A,MINUTE;分放入ACC
  MOV  B,#10;B放入10
  DIV  AB;A/B,商在A里,余数在B里
  MOVC A,@A+DPTR;查表取分十位段码
  MOV  LEDBUS,A;段码送LEDBUS显示
  CLR  MIN_S;打开分十位显示
  ACALL D1MS;延迟1MS
  SETB MIN_S;关闭分十位显示
  MOV  DPTR,#LEDTAB2
  MOV  A,B
  MOVC A,@A+DPTR;查表取分个位段码
  MOV  LEDBUS,A
  CLR  MIN_G;打开分个位显示
  ACALL D1MS;延迟1MS
  SETB MIN_G;关闭分十位显示
  MOV  A,HOUR
  MOV  B,#10
  DIV  AB;拆分小时的十位和个位
  JZ  DISP0;十位为0,不显示十位
  MOV DPTR,#LEDTAB
  MOVC A,@A+DPTR
  MOV  LEDBUS,A
  CLR  HOU_S;打开时十位显示
  ACALL D1MS
  SETB HOU_S
DISP0:
     MOV  DPTR,#LEDTAB2
  MOV  A,B
  MOVC A,@A+DPTR
  MOV  LEDBUS,A
  CLR  HOU_G;打开时个位显示
  ACALL D1MS
  SETB HOU_G;关闭时个位显示
  RET
;--------------------------------------
;定时器0中断服务程序
TIMER0:
       PUSH ACC;入栈保护ACC和PSW
    PUSH PSW
       MOV  A,#0B0H;定时器0中断服务子程序
    ADD  A,TL0;同步修正
    MOV  TL0,A
    MOV  TH0,#03CH;重装定时器0初值
    DJNZ TIM_1,RETI_1
    MOV  TIM_1,#10;中断10次为0.5秒
    DJNZ TIM_2,RETI_1
    MOV  TIM_2,#2;1秒时间到
    INC  SECOND;秒加一
    MOV  A,SECOND
    CJNE A,#60,RETI_1
    MOV  SECOND,#0;秒到60变0
    INC  MINUTE;分加1
    MOV  A,MINUTE
    CJNE A,#60,RETI_1
    MOV  MINUTE,#0;分到60变0
    INC  HOUR;时加1
    MOV  A,HOUR
    CJNE A,#24,RETI_1
    MOV  HOUR,#0;时到24变0
RETI_1:
       POP PSW
    POP ACC
    RETI
;----------------------------------------
;延迟子程序
D1MS:
     MOV R7,#2;延迟1MS子程序
D_1:
     MOV R6,#250;延迟时间估算250*2*2=1000微秒
  DJNZ R6,$
  DJNZ R7,D_1
  RET
;----------------------------------------
;数码管段码表
LEDTAB:  ;不带点的数码管字码表
       DB  0C0H,0F9H,0A4H,0B0H,99H;0,1,2,3,4
    DB  92H,82H,0F8H,80H,90H;5,6,7,8,9
LEDTAB2:  ;带点的数码管字码表
        DB  40H,79H,24H,30H,19H;0,1,2,3,4
  DB  12H,02H,78H,00H,10H;5,6,7,8,9
END

 

 

 

 

 

 

 

注释:

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

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

废话太多——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                     ;开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)中的值和初始值相加后一并送入定时/计数器中,此时定时/计数器中的值即为动态同步修正后的准确值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值