新闻  |   论坛  |   博客  |   在线研讨会
基于单片机数字时钟电路程序
tvb2058 | 2007-09-12 11:23:56    阅读:4625   发布文章

该数字钟可实现精度误差≤ 1S/天的变精度时钟,并能方便地调节时钟、时间、定时时间等,秩序结构清晰,一看即懂,还可以配编附加一些功能如计数器功能等(扩展键盘)。
 
  

       led1 bit p1.0       ;LED定义
       led2 bit p1.1     
       led3 bit p1.2
       
led4 bit p1.3
       
led5 bit p1.4
       
led6 bit p1.5
       
led7 bit p1.6
       led8 bit p1.7

       s1 bit p0.0        ;数码管位数定义
       
s2 bit p0.1
       
s3 bit p0.2
       
s4 bit p0.3
       
s5 bit p0.4
       
s6 bit p0.5
       
s7 bit p0.6
       s8 bit p0.7

       led_data equ p2      ;数码管定义

       key1 bit p3.5        ;按键定义
       key2 bit p3.6
       
key3 bit p3.7
       key equ 56h

       time_h equ 57h       ;定时初值高位
       time_l equ 58h       ;低位

       t_h equ 60h        ;时分秒对应的地址
       t_s equ 61h
       
t_m equ 62h
       time equ 63h        ;时钟计数单元

       timer_h equ 64h       ;定时时单元
       timer_m equ 65h      ;定时分单元
      
       timset bit 00h       ;设置时间标志

       disstart equ 70h      ;显示单元首地址

       int_data equ 45h      ;中断数据地址
       count_data equ 44h     ;计数单元地址
       timer_data equ 43h     ;定时地址
; ************** 以上为预定义部分

; ************** 以下程序开始
       org 00h          ;程序开始地址

       jmp main          ;跳转到代码开始处

       org 1bh          ;定时器 T1 中断服务程序入口
       jmp tim1

       org 030h          ;主程序开始的地址 30H

     main:mov sp,#30h        ;首先定义堆栈
       lcall rest         ;初始化
       lcall pro_set       ;设置定时器开始工作
     lpp:lcall time_set       ;接受用户设置时间
       lcall timer        ;时钟处理

       lcall time_pro       ;时间格式处理,码型变化等

       lcall time_display     ;显示

       jmp lpp
; ************* 初始化程序
***************************
     rest:mov a,#00h         ;累加器清零

       
mov b,#00h
       mov p0,#0          ;数码管禁止显示

       mov t_h,#0         ;时单元

       mov t_m,#0         ;分单元
       mov t_s,#0         ;秒单元
       mov time,#00h       ;计数溢出次数,溢出20次为一秒
       clr timset         ;定时设置标志位,0->增加 1 ->减少

       mov timer_h,#12      ;定时器时单元,设置定时为 12:00
       mov timer_m,#00h      ;定时器分单元

       mov p2,#255        ;禁止显示数码管
       clr beep          ;禁止蜂鸣器

       ret            ;返回

; *************** 定时器 T1 中断服务程序
****
     tim1:clr tr1          ;首先停止定时操作

       mov th1,time_h       ;
       
mov tl1,time_l
       inc time          ;自增

       mov a,time         ;取得溢出次数
       cjne a,#20,retend      ;如果满20此表示到 1 秒
       cpl p1.0          ;取反p1.0,p1.1指示秒钟

       
cpl p1.1
       mov time,#00h       ;重新开始等待1秒

       inc t_s          ;秒单元加1
    retend:setb tr1          ;定时开始

       reti            ;中断返回

; ***************** 设置定时器初始化,定时时间为 50ms ****
   pro_set:mov dptr,#0000h       ;数据指针清零

       mov tmod,#10h       ;设置定时器1工作在方式
1
       mov time_h,#3ch       ;计算定时50ms需要的初值

       mov th1,time_h       ;保存高位
       mov time_l,#0c1h      ;低位
       mov tl1,time_l       ;保存低位

       setb ea          ;总的中断允许
       setb et1          ;定时器1允许

       setb tr1          ;定时器1开始运行
       ret             ;返回

; ****************** timer 程序主要完成数据的处理 **********
    timer:mov a,t_s          ;取得秒单元数据

       cjne a,#60,tend       ;秒不到60返回
       mov t_s,#00h         ;清除秒单元
       inc t_m           ;为分单元加1
       mov a,t_m          ;取得分单元数据

       cjne a,#60,tend       ;分不等于60返回
       mov t_m,#00h        ;分单元清零

       setb beep          ;整点短鸣提示

       lcall delay         ;鸣叫延时
       clr beep          ;停止蜂鸣器
       inc t_h           ;同时为时单元加1
       mov a,t_h          ;取得时单元数据

       cjne a,#24,timetest     ;如果不等于24,查看定时
       mov t_h,#00h        ;时单元清零
       jmp tend           ;返回
   timetest:cjne a,timer_h,tend    ;不等于定时的时单元,返回

       mov a,t_m         ;取得定时的分单元

       cjne a,timer_m,tend    ;当前分不等于定时的分单元,返回
       setb beep          ;定时到,蜂鸣提示
       
lcall delay
       
clr beep
       
lcall delay
       
setb beep
       
lcall delay
       clr beep          ;连续发出短音提示

     tend:ret            ;返回

; ************ time_display 程序主要为显示时间值用 *************
time_display: mov r0,#disstart      ;取得显示单元首地址

       mov r1,#01h        ;从第一个数码管开始

       mov r2,#06h        ;共6个数码管
    dislp:mov led_data,@r0      ;获得当前单元数据
       inc r0           ;指向下一个单元
       mov p0,r1          ;数码显示

       mov a,r1          ;为下一个数准备
       rl a            ;下一个单元
       mov r1,a          ;保存

       lcall delay5ms       ;为了保证数码管亮度,

                     ;但要防止闪烁,延时
5ms
       djnz r2,dislp       ;重复显示,直到全部数据刷新过

       ret             ;返回

; ******* time_pro 时间处理,主要为 bcd码转换,查表 ***********
  time_pro:lcall bcd          ;BCD码转换

       mov r0,#disstart      ;获得显示单元首地址
       mov r2,#06h         ;需要转换的个数
    prlp:mov a,@r0          ;取得当前需要转换的数据
       mov dptr,#tab_nu      ;获得表头
       movc a,@a+dptr       ;获得转换后的数据
       mov @r0,a          ;存回去
       inc r0            ;指向下一个
       djnz r2,prlp         ;重复转换,直到6个全部完成
       ret             ;返回

; **************** 码型变换 ****************************************
     bcd:mov r0,#disstart      ;获得首地址

       mov a,t_s          ;获得待转化的低位
       mov b,#10          ;转化进制,如果要进行十进制转换 改为 10
       div ab            ;计算 A/B    

       mov @r0,b          ;第一位转换完毕,保存低位转化后的数据
       inc r0            ;自增

       mov @r0,a          ;保存高位
       inc r0           ;取第二个数据地址
       mov a,t_m          ;获得第二个需要转换的数据
       mov b,#10          ;十六进制
       div ab            ;计算
       mov @r0,b          ;存低位
      
inc r0
       mov @r0,a          ;存高位

       inc r0            ;第三位
       mov a,t_h          ;获得数据
       mov b,#10          ;十六进制
       div ab           ;计算

       mov @r0,b          ;存低位
       inc r0
       mov @r0,a          ;存高位

       ret             ;完毕,返回

;***************************************************************************************
;******** time_set
设置时间 *******************************************************
; *                                        
*
; *    检测用户按键,1-> 设置时单元 2-> 设置分单元,3->设置增减方式      
*
; *    如果需要增加 时,先将方式设置为 增加(默认为减),即,按下 KEY3一下, 
*
; *    然后按 KEY1 ,如果要减少时单元,需要再次按下KEY3,然后按KEY1;     
*
; *    分的设置也是如此。                           
*
;***************************************************************************************
  time_set:mov p0,#00h         ;禁止数码管显示

       mov p2,#255         ;防止按键时闪烁
       lcall pro_key        ;查找用户按键情况
       mov a,key          ;查找键值

       jz tsend          ;如果等于0,表示没用按键,直接返回
       cjne a,#1,tset1       ;是否等于1?没有到下一个处理程序
       mov key,#00h        ;等于1,表示设置时 请零,否则会引起重复设置
       jb timset,tset10      ;时间设置标志位,1 ->减少,0->增加
       mov a,t_h          ;标志位 0 ,增加,取得时单元
       cjne a,#23,ts1       ;如果时单元不等于23,转移到增加操作

       jmp tsend          ;等于23 直接返回
     ts1:inc t_h           ;时单元增加1
       jmp tsend          ;返回

   tset10: mov a,t_h          ;这里处理为减少的情况

       jz tsend           ;如果时单元为0,直接返回
       dec t_h           ;否则,数据减1
       jmp tsend          ;返回,以下关于分的设置一样

    tset1:cjne a,#2,tset2       ;如果按键不是 2 则 转移到下一个处理

       mov key,#00h        ;是2,表示设置 分
       jb timset,tset20      ;其余同上
      
mov a,t_m
      
cjne a,#59,
      
ts2 jmp tsend
    
ts2:inc t_m
      
jmp tsend
   
tset20:mov a,t_m
      
jz tsend
      
dec t_m
      
jmp tsend
    tset2:cjne a,#3,tsend       ;等于 3 表示设置标志

       mov key,#00h        ;清零
       cpl timset         ;标志取反
    tsend:ret             ;返回
;********* 按键处理 读取键盘 *************************
;参见有关键盘查询的说明,和前面的有关程序

   pro_key:              ;键盘查询子程序
       setb key1           ;首先输出高电平,检测低电平的到来

       setb key2          ;不同电路,可能检测方式不一样

      
setb key3
       jb key1,ke1        ;如果用户没有按第一个键,到第下个处理部分,

       mov key,#1         ;表示用户按了第一个键
       lcall delay20ms       ;软件延时,防止干扰

       jmp pro_key         ;重新查询,直到用户释放按键
     ke1:jb key2,ke2        ;处理第二个按键,如果没有到下一个处理部分
       mov key,#2         ;以下和第一个处理单元相似。
       lcall delay20ms
      
jmp pro_key
    
ke2:jb key3,ke3
      
mov key,#3
      
lcall delay20ms
      
jmp pro_key
    
ke3:ret
;**************************************
;******** 定时器 T0 设置
**************
;定时器工作在方式1,为提高精度,总定时时间为50ms,

;定时器溢出20次为1秒,

  pro_timer:mov tmod,#01h        ;设置定时器为定时方式1
       mov th0,#0ffh        ;初始化定时初值

       mov tl0,#0a1h        ;
       setb ea           ;总中断允许

       setb et0           ;定时器0 允许
       setb tr0           ;开始定时
       ret              ;返回
; *****************************************
; *************** 软件延时
*************
    delay:push psw          ;保存原来的寄存器内容

       clr psw.3          ;
       clr psw.4          ;设置新的寄存器组

       mov r0,#2          ;延时参数1
       mov r1,#250         ;延时参数
2
       mov r2,#2          ;延时参数
3
     dl1:djnz r0,dl1         ;延时循环
1
       mov r0,#250        
;
     dl2:djnz r1,dl1         ;延时循环
2
       mov r0,#240         
;
       mov r1,#248        
;
     dl3:djnz r2,dl1         ;延时循环
3
       nop             ;定时精度调整

       pop psw           ;恢复原来的寄存器
       ret             ;返回
;*****************************************
;***************
键盘延时 ***************
 
delay20ms:push psw
      
clr psw.3
      
clr psw.4
      
mov r0,#250
      
mov r1,#40
    
d20:djnz r0,d20
      
mov r0,#250
      
djnz r1,d20
      
pop psw
      
ret
;**************************************
;*********** 延时
5ms ****************
  
delay5ms:push psw
      
clr psw.3
      
setb psw.4
      
mov r0,#250
      
mov r1,#10
     
d5:djnz r0,d5
      
mov r0,#250
      
djnz r1,d5
      
pop psw
      
ret
;************************************************************************************
;这是数字显示表格,其中 带小数点的数字比不带小数点的数字大
16
; 比如 0 的显示代码为 0;那么 0.的显示代码为 16;如此类推

   tab_nu:db 0c0h, 0f9h, 0a4h, 0b0h, 99h , 92h , 82h, 0f8h   ;数字0-7 不带小数点代码

       db 80h , 90h, 88h , 83h , 0c6h, 0a1h, 86h, 8eh    ;数字8-f 不带小数点代码
       db 40h , 79h, 24h , 30h , 19h , 12h , 02h, 78h    ;数字0-7 带小数点代码

       db 00h , 10h, 08h , 03h , 46h , 21h , 06h, 0eh    ;数字8-f 带小数点代码
       end ;

 

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客