来源:电子技术网 作者: 该数字钟采用AT89C51单片机设计,以下程序为完整版,已通过调试测试通过。 该数字钟可实现精度误差≤ 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 ;完毕,返回 |