萬用電路板

--Do It Yourself

« 年末收到北斗星网友的点阵屏【图】单片机课程设计之自动打铃系统 »

改进版8位数码管汇编数字钟

        几天前帮同学课程设计写的那个数字钟(51单片机简洁版汇编数字钟),由于时间紧,随便搞了两下。那个程序不怎么好,用两个按钮分别调时调分,而且只能增加,不小心按到按钮便调动了时间,不能用于实际产品。恰巧我自己的单片机课程设计题目是“自动打铃器”,也是建立在电子钟的基础上的,同样要求用汇编写,于是我对那个数字钟程序作了大的改进。

        显示格式依然是23-59-59(同样是小时十位如果为0则不显示),调整时间增加了一只按钮,通过调整选择键SET_KEY选择调整位,选中位开始闪烁,此时再按增加键ADD_KEY或减少键DEC_KEY调整选中位,如果长按ADD_KEY或DEC_KEY,系统识别后则进行调时快进,此时停止闪烁,方便人眼观察。同时还增加了调秒功能:如果选中位是秒,则按增加键或减少键都是将秒清零。

        演示视频:

        硬件电路如图(点击放大):

汇编程序设计:

/**************************************************************
程序名称:51单片机8位数码管数字钟汇编程序
简要说明:实现24小时制电子钟,8位数码管显示,显示时分秒
    显示格式:23-59-59(小时十位如果为0则不显示)
    通过3只按键来调整时间
    调整选择键SET_KEY:P1.0;通过选择键选择调整位,选中位闪烁
    增加键ADD_KEY:P1.1;按一次使选中位加1
    减少键DEC_KEY;P1.2;按一次使选中位减1
    如果长按ADD_KEY或DEC_KEY,识别后则进行调时快进,此时停止闪烁
    如果选中位是秒,则按增加键或减少键都是将秒清零
    P0口输出数码管段选信号,P2口输出数码管位选信号。晶振12M
编    写:JiangX.net
最后更新:08/12/31晚
**************************************************************/
  ORG 0000H   ;程序入口地址
  LJMP START
  ORG 000BH   ;定时器0中断入口地址
  LJMP TIMER_0

  ORG 0300H

/*****程序开始,初始化*****/  
START:
  SETB 48H   ;使用一个bit位用于调时闪烁标志
  SETB 47H   ;使用一个bit位用于产生脉冲用于调时快进时基
  MOV R1,#0   ;调整选择键功能标志:0正常走时、1调时、2调分、3调秒

  MOV 20H,#00H  ;用于控制秒基准时钟源的产生
  MOV 21H,#00H  ;清零秒寄存器
  MOV 22H,#00H  ;清零分寄存器
  MOV 23H,#00H  ;清零时寄存器
  MOV 24H,#00H  ;用于控制调时闪烁的基准时钟的产生
 
  MOV IP,#02H   ;IP,IE初始化
  MOV IE,#82H
  MOV TMOD,#01H  ;设定定时器0工作方式1
  MOV TH0,#3CH
  MOV TL0,#0B0H  ;赋定时初值,定时50ms   
  SETB TR0   ;启动定时器0
  MOV SP,#40H   ;重设堆栈指针

/*****主程序*****/  
MAIN:
  LCALL DISPLAY   ;调用显示子程序
  LCALL KEY_SCAN   ;调用按键检测子程序
  JZ MAIN    ;无键按下则返回重新循环
  LCALL SET_KEY   ;调用选择键处理子程序
  JB 46H,MAIN   ;如果已进行长按调整(调时快进),则不再执行下面的单步调整    
  LCALL ADD_KEY  ;调用增加键处理子程序,加一
  LCALL DEC_KEY  ;调用减少键处理子程序,减一
  LJMP MAIN    ;重新循环
 
/*****定时器中断服务程序*****/
TIMER_0:
  PUSH ACC    
  PUSH PSW    ;保护现场
  MOV TH0,#3CH
  MOV TL0,#0B0H   ;重新赋定时初值
  CPL 47H    ;产生脉冲用于调时快进时基
  INC 24H
  MOV A,24H        
  CJNE A,#10,ADD_TIME ;产生0.5秒基准时钟,用于调时闪烁
  CPL 48H    ;取反调时闪烁标志位
  MOV 24H,#00H

ADD_TIME:     ;走时
  INC 20H    
  MOV A,20H
  CJNE A,#20,RETI1 ;产生1秒基准时钟
  MOV 20H,#00H   ;一秒钟时间到,清零20H
  MOV A,21H
  ADD A,#01H
  DA A     ;作十进制调整
  MOV 21H,A
  CJNE A,#60H,RETI1
  MOV 21H,#00H   ;一分钟到
  MOV A,22H
  ADD A,#01H
  DA A
  MOV 22H,A
  CJNE A,#60H,RETI1
  MOV 22H,#00H   ;一小时到
  MOV A,23H
  ADD A,#01H
  DA A
  MOV 23H,A
  CJNE A,#24H,RETI1
  MOV 23H,#00H   ;到24点,清零小时
 
RETI1:
  POP PSW    
  POP ACC    ;恢复现场
  RETI     ;中断返回

/*****显示处理*****/
DISPLAY:
  MOV A,21H    ;秒
  ANL A,#0FH
  MOV 2FH,A   ;转换出秒个位,存入2FH
  MOV A,21H
  ANL A,#0F0H
  SWAP A
  MOV 2EH,A   ;转换出秒十位,存入2EH
  JB 46H,MIN   ;如果长按按键(调时快进),则跳过闪烁处理程序
  CJNE R1,#3,MIN  ;如果R1为3,闪烁秒位待调整
  JB 48H,MIN
  MOV 2FH,#0AH  ;使该位为10,查表得到使该位不显示的输出
  MOV 2EH,#0AH

MIN:
  MOV A,22H    ;分
  ANL A,#0FH
  MOV 2DH,A   ;转换出分个位,存入2DH
  MOV A,22H
  ANL A,#0F0H
  SWAP A
  MOV 2CH,A   ;转换出分十位,存入2CH
  JB 46H,HOUR   ;如果长按按键(调时快进),则跳过闪烁处理程序
  CJNE R1,#2,HOUR  ;如果R1为2,闪烁分位待调整
  JB 48H,HOUR
  MOV 2DH,#0AH  ;使该位为10,查表得到使该位不显示的输出
  MOV 2CH,#0AH

HOUR:
  MOV A,23H    ;时
  ANL A,#0FH 
  MOV 2BH,A   ;转换出时个位,存入2BH
  MOV A,23H
  ANL A,#0F0H
  SWAP A
  MOV 2AH,A   ;转换出时十位,存入2AH
  JB 46H,DISP   ;如果长按按键(调时快进),则跳过闪烁处理程序
  CJNE R1,#1,DISP  ;如果R1为1,闪烁时位待调整
    JB 48H,DISP
  MOV 2BH,#0AH  ;使该位为10,查表得到使该位不显示的输出
  MOV 2AH,#0AH

/*****数码管动态扫描显示*****/
DISP:
  MOV DPTR,#TABLE
  MOV A,2FH
  MOVC A,@A+DPTR
  MOV P0,A
  CLR P2.7
  LCALL DELAY
  SETB P2.7   ;显示秒个位

  MOV A,2EH
  MOVC A,@A+DPTR
  MOV P0,A
  CLR P2.6
  LCALL DELAY
  SETB P2.6   ;显示秒十位

  MOV A,#0BFH
  MOV P0,A
  CLR P2.5
  LCALL DELAY
  SETB P2.5   ;显示“-”

  MOV A,2DH
  MOVC A,@A+DPTR
  MOV P0,A
  CLR P2.4
  LCALL DELAY
  SETB P2.4   ;显示分个位

  MOV A,2CH
  MOVC A,@A+DPTR
  MOV P0,A
  CLR P2.3
  LCALL DELAY
  SETB P2.3   ;显示分十位

  MOV A,#0BFH
  MOV P0,A
  CLR P2.2
  LCALL DELAY
  SETB P2.2   ;显示“-”

  MOV A,2BH
  MOVC A,@A+DPTR
  MOV P0,A
  CLR P2.1
  LCALL DELAY
  SETB P2.1   ;显示时个位

  MOV DPTR,#TABLE1 ;该位使用TABLE1以消除前置0
  MOV A,2AH
  MOVC A,@A+DPTR
  MOV P0,A
  CLR P2.0
  LCALL DELAY
  SETB P2.0   ;显示时十位
  RET
  
/*****按键检测子程序*****/
KEY_SCAN:
  CLR 46H    ;关闭长按调整(调时快进)标志
  MOV P1,#0FFH   ;将P1口设置成输入状态
  MOV A,P1
  CPL A
  ANL A,#07H   ;P1口低3位连接3个按键,只判断该3位
  JZ EXIT_KEY   ;无键按下则返回
  LCALL DELAY   ;延时去抖动
  MOV A,P1   ;重新判断
  CPL A
  ANL A,#07H
  JZ EXIT_KEY   ;键盘去抖动
  MOV R5,A    ;临时将键值存入R5
  MOV R4,#00H   ;用于控制调时快进速度
  ;设置为00H是为了在进入长按处理前加长延时区分用户的长按与短按,防止误快进
  
LOOP:      ;进入长按处理
  LCALL DISPLAY  ;使长按时显示正常 
  MOV A,P1
  CPL A
  ANL A,#07H
  JB 47H,LOOP1
  INC R4    ;调时快进间隔时间基准加1

LOOP1:
  CJNE R1,#03H,LOOP2 ;如果调秒时长按,则不处理
  LJMP LOOP3

LOOP2:
  CJNE R4,#99H,LOOP3 
  MOV R4,#70H   ;确认用户长按后,重新设定起始值,加快调时快进速度
  SETB 46H   ;长按调整(调时快进)标志   
  LCALL ADD_KEY
  LCALL DEC_KEY

LOOP3:
  JNZ LOOP    ;等待键释放
  MOV A,R5   ;输出键值
  RET   

EXIT_KEY:
  RET

/*****延时子程序*****/
DELAY:  
  MOV R7,#150 
  DJNZ R7,$
  RET
  
/*****选择键处理子程序*****/
SET_KEY:
  CJNE R5,#01H,EXIT ;选择键键值
  INC R1    ;调整选择功能标志加一
  CJNE R1,#4,EXIT
  MOV R1,#0
  MOV 24H,#00H  ;调时闪烁基准清零
  RET

/*****增加键处理子程序*****/
ADD_KEY:
  CJNE R5,#02H,EXIT ;增加键键值
  CJNE R1,#01H,NEXT1 ;选择键功能标志为1,调时,否则跳出
  MOV A,23H
  ADD A,#01H
  DA A
  MOV 23H,A
  CJNE A,#24H,EXIT
  MOV 23H,#00H

NEXT1:
  CJNE R1,#02H,NEXT2 ;选择键功能标志为2,调分,否则跳出
  MOV A,22H
  ADD A,#01H
  DA A
  MOV 22H,A
  CJNE A,#60H,EXIT
  MOV 22H,#00H

NEXT2:
  CJNE R1,#03H,EXIT ;选择键功能标志为3,调秒,否则跳出
  MOV 21H,#00H  ;如增加键按下直接清零秒
  RET

/*****减少键处理子程序*****/
DEC_KEY:
  CJNE R5,#04H,EXIT ;减少键键值
  CJNE R1,#01H,NEXT3 ;选择键功能标志为1,调时,否则跳出
  MOV A,23H
  ADD A,#99H
  DA A
  MOV 23H,A
  CJNE A,#99H,EXIT
  MOV 23H,#23H
 
NEXT3:
  CJNE R1,#02H,NEXT4 ;选择键功能标志为2,调分,否则跳出
  MOV A,22H
  ADD A,#99H
  DA A
  MOV 22H,A
  CJNE A,#99H,EXIT
  MOV 22H,#59H

NEXT4:
  CJNE R1,#03H,EXIT ;选择键功能标志为3,调秒,否则跳出
  MOV 21H,#00H  ;如较少键按下直接清零秒
  RET

/*****万用返回子程序*****/  
EXIT:
  RET

/*****数码管字形编码表*****/
TABLE:
  DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0FFH ;字形显示编码

TABLE1:
  DB 0FFH,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0FFH ;小时位的十位数编码,该位如果为0则不显示

  END     ;程序结束

原创作品如转载,请注明:转载自萬用電路板 [ http://www.jiangx.net/ ]

  • quote 1.iamvican
  • 请问如果是共阴的数码管,那么小时位的十位数编码该如何计算呢??
    jiangx 于 2009-1-8 21:49:01 回复
    把表中的第一个元素改成00H
    iamvican 于 2009-1-8 22:10:00 回复
    非常感谢!
    iamvican 于 2009-1-8 22:12:20 回复
    我是新手,能解释下如何计算的吗?
    jiangx 于 2009-1-9 13:56:53 回复
    不显示就是所有的笔画都是低电平,即00H
  • 2009-1-8 21:17:34 回复该留言
  • quote 2.jevin
  • 请问这个时钟的误差度会大吗?
    一天大概误差几秒?
    还有就是我把这个程式抄进写程式的软体
    然后组合程式了之后,我去view port
    结果发现p2.0那边只要经过几秒之后就会闪了哦
    p2.0那边不是小时的位置吗?
    不是要经过59分以后才会跳吗?
    做么只是经过几秒以后就会跳了?
    jiangx 于 2009-3-5 21:39:18 回复
    误差肯定是会有的。因为单片机定时器的定时精度受晶振质量,环境温度等因素影响,加之写程序时定时器初值计算可能不蛮精准,如果要使这个作品可以实际使用,那还需进一步调试,你可以通过修改定时器初值寄存器TH、TL来校正走时误差。
    至于其它问题我就不是很清楚了,因为这是为同学做的课程设计,我设计好软件下载到实际的单片机硬件里面是可行的,我就没再深入去查找bug了。
    jevin 于 2009-3-6 16:46:50 回复
    要改那里一行程式?
  • 2009-3-5 15:51:39 回复该留言
  • quote 3.jevin
  • 校正走时误差要修改那里一行程式?
    jiangx 于 2009-3-9 9:53:38 回复
    MOV TH0,#3CH
    MOV TL0,#0B0H ;赋定时初值,定时50ms

    以及

    MOV TH0,#3CH
    MOV TL0,#0B0H ;重新赋定时初值

    #号后面便是定时器初值。
  • 2009-3-8 14:00:45 回复该留言
  • quote 5.APOLLO
  • 你好,这个我已经做出成品,首先指出两个问题:1,延时程序时间过短,无法点亮led,建议改为2ms延时立即可行。2,进入确认长按的时间太长,并且快进一点都不快,即LOOP2:
    CJNE R4,#99H,LOOP3
    MOV R4,#70H ;
    建议将#99H和#70H改为#99和#90,效果明显。再鸡蛋里面挑骨头说硬件,开关最好接上拉电阻,led的限流电阻330可能小了点,我0.36寸led用1k的电阻都很亮
    再请教两个问题:1,判断一分钟到和一小时到为什么是CJNE A,#60H,RETI1
    ,而不是#60,我试着改成#60,答案告诉我#60H才是对的。2,三极管肯定是按你那么接的,我硬件也是这样接,但是我protues仿真的时候却不行,偶然把c和e接反了反而行了,换了几个pnp的管都是一样,解释不通
    再提点一点意见,加个定时闹钟功能。
  • 2009-4-1 18:26:44 回复该留言
  • quote 6.springvirus
  • 呵呵,昨天做了个,效果很棒啊!!
    jiangx 于 2009-6-22 22:48:21 回复
    呵呵
  • 2009-6-22 11:42:35 回复该留言

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

赞助商广告

最近发表

热文排行

最新评论及回复

广告

图标汇集

  • 留言板
  • 订阅本站的 ATOM 1.0 新闻聚合
  • 订阅本站的 RSS 2.0 新闻聚合

Powered By Z-Blog 1.8

Copyright 2008 JiangX.net 萬用電路板 All Rights Reserved.
鄂ICP备08003060号 [login]