专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

可调时钟程序(状态机)

作者:佚名   来源:本站原创   点击数:  更新时间:2010年10月01日   【字体:
/***************************************************************************************
         008.ASM
        用八位数码管显示时间,通过两个按键改变显示内容及修改时间
       接线:J15.J16短接,P0接八位数码管,P2接独立键盘
                             2010.09.06  
  ***************************************************************************************/
  ORG 0000H
    LJMP MAIN
  ORG 001BH
    LJMP INT_T1
  ORG 0040H
MAIN:
    LCALL FRIST     ;上电初始化
LOOP:        ;主循环
 LCALL KEY_READ     ;读键盘
 JBC 00H,N
 LJMP N0      ;无键,则跳到N0
N:
 LCALL CHAUNG   ;有键则去刷新显示状态
 LJMP LOOP
N0:       ;输出当前时分秒
    MOV R0,#60H 
 MOV R1,#07H
 MOV R5,#08H
 LCALL COUNT_OUTPUT  ;刷新输出
 LCALL SHOW     ;输出
 LCALL CHANG_TIME   ;按秒改变输出时间
 LJMP LOOP

FRIST:
 MOV SP,#30H   ;设置堆栈
 MOV 45H,#01H      ;设置初始状态为00H
 MOV P1,#0FFH       ;初始化P1口 
 MOV TMOD,#21H   ;设置定时器工作模式,T0为工作模式2,T1为工作模式1

 MOV 50H,#06H    ;初始化年月日 数码管显示
 MOV 51H,#00H
 MOV 52H,#09H
 MOV 53H,#00H
 MOV 54H,#00H
 MOV 55H,#01H
 MOV 56H,#00H
 MOV 57H,#02H

 MOV 46H,#14H  ;初始化年月日
 MOV 47H,#0AH
 MOV 48H,#09H
 MOV 49H,#06H 

 MOV 60H,#00H ;初始化时 分 秒 数码管显示
 MOV 61H,#00H
 MOV 62H,#08H
 MOV 63H,#05H
 MOV 64H,#02H
 MOV 65H,#02H
 MOV 66H,#00H
 MOV 67H,#00H

 MOV 58H,#16H   ;初始化时分秒
 MOV 59H,#3AH
 MOV 68H,#00H

 MOV R6,#19H  ;定时T1计数
 MOV R7,#28H

 MOV TH0,#15H     ;赋T0定时初值
 MOV TL0,#0A0H
 MOV TH1,#06H   ;赋T1定时初值
 MOV TL1,#06H
 SETB TR1

 CLR 00H        ;初始化按键标志为“0” , 即 无 键
 CLR 01H        ;初始化键值为“0”,即A
 CLR 02H        ;初始化按键长短为“0”,即短按键  
 CLR 03H         ;初始化定时T1标志
 CLR 04H         ;初始时间更改标志位(秒,分,时,日,月,年)
 CLR 05H 
 CLR 06H
 CLR 07H
 CLR 08H
 CLR 09H
 CLR 0AH
 CLR 0BH         ;01状态标志位,表示为01状态

    MOV IE,#88H    ;开定时中断
 RET

 /*输出计算子程序*/
COUNT_OUTPUT:
    JBC 04H,COUNT_S     ;秒改变,则计算出显示值送相应内存
 LJMP COUNT_M
COUNT_S:        ;否则去计算分
    MOV B,#0AH       ;秒/10。商送61H,余数送60H
 MOV A,68H
 DIV AB
 MOV 61H,A
 MOV 60H,B
COUNT_M:
 JBC 05H,COUNT_M0     ;分改变,则计算出显示值送相应内存
 LJMP COUNT_H    ;否则去计算时
COUNT_M0:
    MOV B,#0AH     ;分/10,商送63H,余数送62H
 MOV A,59H
 DIV AB
 MOV 63H,A
 MOV 62H,B
COUNT_H:
    JBC 06H,COUNT_H0   ;时改变,则计算出显示值送相应内存
 LJMP COUNT_D     ;否则去计算日
COUNT_H0:
    MOV B,#0AH     ;时/10,商送65H,余数送64H
 MOV A,58H
 DIV AB
 MOV 65H,A
 MOV 64H,B
COUNT_D:       ;日改变,则计算出显示值送相应内存
    JBC 07H,COUNT_D0    ;否则去计算月
 LJMP COUNT_MON
COUNT_D0:        ;日/10,商送51H,余数送50H
    MOV B,#0AH
 MOV A,49H
 DIV AB
 MOV 51H,A
 MOV 50H,B
COUNT_MON:
    JBC 08H,COUNT_MON0      ;月改变,则计算出显示值送相应内存
 LJMP COUNT_YL       ;否则去计算年(L)
COUNT_MON0:
    MOV B,#0AH      ;月/10,商送53H,余数送52H
 MOV A,48H
 DIV AB
 MOV 53H,A
 MOV 52H,B
COUNT_YL:
    JBC 09H,COUNT_YL0     ;年低位改变,则计算出显示值送相应内存
 LJMP COUNT_YH      ;否则去计算年(H)
COUNT_YL0:
    MOV B,#0AH       ;年(L)/10,商送55H,余数送54H
 MOV A,47H
 DIV AB
 MOV 55H,A
 MOV 54H,B
COUNT_YH:         ;年高改变,则计算出显示值送相应内存
    JBC 0AH,COUNT_YH0       ;否则子程序返回
 LJMP COUNT_RETURN
COUNT_YH0:
 MOV B,#0AH        ;年(H)/10,商送57H,余数送56H
 MOV A,46H
 DIV AB
 MOV 57H,A
 MOV 56H,B               
COUNT_RETURN:
     RET

/*时间修改子程序*/
CHAUNG:
     
STAR:
  MOV A,45H       ;读状态值
  CJNE A,#01H,CHAUNG0    ;状态值=01H,则转H_M_S0,否则进行下一个判断
  LCALL H_M_S0
  LJMP CHAUNG10
CHAUNG0:
     CJNE A,#02H,CHAUNG1    ;状态值=02H,则转H_M_S1,否则进行下一个判断
  LCALL H_M_S1
  LJMP CHAUNG10
CHAUNG1:
     CJNE A,#04H,CHAUNG3    ;状态值=04H,则转H_M_S2,否则进行下一个判断
  LCALL H_M_S2
  LJMP CHAUNG10
CHAUNG3:
     CJNE A,#03H,CHAUNG4    ;状态值=03H,则转Y_M_D0,否则进行下一个判断
  LCALL Y_M_D0
  LJMP CHAUNG10
CHAUNG4:
     CJNE A,#06H,CHAUNG5    ;状态值=06H,则转Y_M_D1,否则进行下一个判断
  LCALL Y_M_D1
  LJMP CHAUNG10
CHAUNG5:
     CJNE A,#0CH,CHAUNG6     ;状态值=0cH,则转Y_M_D2,否则进行下一个判断
  LCALL Y_M_D2
CHAUNG6:
     CJNE A,#18H,CHAUNG7     ;状态值=18H,则转Y_M_D3,否则进行下一个判断
  LCALL Y_M_D3
  LJMP CHAUNG10
CHAUNG7:
     CJNE A,#07H,CHAUNG8     ;状态值=07H,则转S_CLOCK0,否则进行下一个判断
  LCALL S_CLOCK0
  LJMP CHAUNG10
CHAUNG8:
     CJNE A,#0EH,CHAUNG9     ;状态值=0eH,则转S_CLOCK1,否则进行下一个判断
  LCALL S_CLOCK1
  LJMP CHAUNG10
CHAUNG9:
     CJNE A,#1CH,CHAUNG10    ;状态值=07H,则转S_CLOCK2,否则进行下一个判断
  LCALL S_CLOCK2
  LJMP CHAUNG10
CHAUNG10:              ;子程序返回
     JBC 0BH,STAR
     RET


/*状态01修理子程序*/
H_M_S0:
     JB 01H,S_01       ;判断A键,B键
  MOV 45H,#02H       ;A键,状态转为02H
  LJMP S_01_RETURN
S_01:           ;B键,状态转为03H
     MOV 45H,#03H
S_01_RETURN:
     SETB 0BH
  RET


/*状态02修理子程序*/
H_M_S1:
     MOV 69H,#00H        ;定时标志,定时到,回到A状态
LOOP_02:
     MOV R0,#64H        ;设置显示内容
  MOV R1,#03H
  MOV R5,#02H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_02      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_02     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_02_RETURN
S_02:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_02_0        ;长按,去判断A键B键
  JBC 01H,S_02_1        ;短按,去判断A键B键
  INC 58H         ;A键,时+1
  SETB 06H          ;置位,时改变标志
  LJMP LOOP_02
S_02_0:
     JBC 01H,S_02_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#04H        ;A键,状态转为04H
  SETB 0BH
  LJMP S_02_RETURN
S_02_1:           ;短按B键,时-1,并置位时改变标志
      DEC 58H
   SETB 06H
   LJMP LOOP_02
S_02_2:
     MOV 45H,#01H
S_02_RETURN:
     MOV 68H,#00H
  RET

/*状态04处理子程序*/
H_M_S2:
    MOV 69H,#00H        ;定时标志,定时到,回到A状态
LOOP_04:
     MOV R0,#62H        ;设置显示内容
  MOV R1,#05H
  MOV R5,#02H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_04      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_04     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_02_RETURN
S_04:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_04_0        ;长按,去判断A键B键
  JBC 01H,S_04_1        ;短按,去判断A键B键
  INC 59H         ;A键,分+1
  SETB 05H          ;置位,分改变标志
  LJMP LOOP_04
S_04_0:
     JBC 01H,S_04_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#01H        ;A键,状态转为08H
  LJMP S_04_RETURN
S_04_1:           ;短按B键,分-1,并置位分改变标志
      DEC 59H
   SETB 05H
   LJMP LOOP_04
S_04_2:
     MOV 45H,#01H
S_04_RETURN:
     MOV 68H,#00H 
  RET


/*状态03修理子程序*/
Y_M_D0:
     MOV R0,#50H
  MOV R1,#07H
  MOV R5,#08H
  LCALL  COUNT_OUTPUT 
  LCALL SHOW
  LCALL KEY_READ 
     JB 01H,S_03       ;判断A键,B键
  MOV 45H,#06H       ;A键,状态转为02H
  LJMP S_03_RETURN
S_03:           ;B键,状态转为03H
     MOV 45H,#07H
S_03_RETURN:
     SETB 0BH       
     RET


/*状态06修理子程序*/
Y_M_D1:
     MOV 69H,#00H        ;定时标志,定时到,回到A状态
LOOP_06:
     MOV R0,#54H        ;设置显示内容
  MOV R1,#03H
  MOV R5,#04H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_06      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_06     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_06_RETURN
S_06:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_06_0        ;长按,去判断A键B键
  JBC 01H,S_06_1        ;短按,去判断A键B键
  INC 47H         ;A键,年+1
  MOV A,47H
  CJNE A,#64H,S_066
  MOV 47H,#00H
  INC 46H
  SETB 0AH
S_066:
  SETB 09H          ;置位,年改变标志
  LJMP LOOP_06
S_06_0:
     JBC 01H,S_06_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#01H        ;A键,状态转为08H
  LJMP S_06_RETURN
S_06_1:           ;短按B键,年-1,并置位年改变标志
      DEC 47H
   MOV A,47H
   CJNE A,#-1,S_0666
   MOV 47H,#00H
   DEC 46H
   SETB 0AH
S_0666:
   SETB 09H
   LJMP LOOP_06
S_06_2:
     MOV 45H,#01H
S_06_RETURN:
     RET

/*状态0C修理子程序*/
Y_M_D2:
     MOV 69H,#00H        ;定时标志,定时到,回到A状态
LOOP_0C:
     MOV R0,#52H        ;设置显示内容
  MOV R1,#05H
  MOV R5,#02H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_0C      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_0C     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_0C_RETURN
S_0C:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_0C_0        ;长按,去判断A键B键
  JBC 01H,S_0C_1        ;短按,去判断A键B键
  INC 48H         ;A键,月+1
  SETB 08H          ;置位,月改变标志
  LJMP LOOP_0C
S_0C_0:
     JBC 01H,S_0C_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#01H        ;A键,状态转为08H
  LJMP S_0C_RETURN
S_0C_1:           ;短按B键,月-1,并置位月改变标志
      DEC 48H
   SETB 08H
   LJMP LOOP_0C
S_0C_2:
     MOV 45H,#01H
S_0C_RETURN:
     RET

/*状态18修理子程序*/
Y_M_D3:
     MOV 69H,#00H        ;定时标志,定时到,回到A状态
LOOP_18:
     MOV R0,#50H        ;设置显示内容
  MOV R1,#07H
  MOV R5,#02H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_18      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_18     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_18_RETURN
S_18:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_18_0        ;长按,去判断A键B键
  JBC 01H,S_18_1        ;短按,去判断A键B键
  INC 49H         ;A键,日+1
  SETB 07H          ;置位,日改变标志
  LJMP LOOP_18
S_18_0:
     JBC 01H,S_18_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#01H        ;A键,状态转为08H
  LJMP S_18_RETURN
S_18_1:           ;短按B键,日-1,并置位日改变标志
      DEC 49H
   SETB 07H
   LJMP LOOP_18
S_18_2:
     MOV 45H,#01H
S_18_RETURN:
     MOV 68H,#00H 
     RET

/*状态07修理子程序*/
S_CLOCK0:
     JB 01H,S_07       ;判断A键,B键
  MOV 45H,#01H       ;A键,状态转为02H
  LJMP S_07_RETURN
S_07:           ;B键,状态转为03H
     MOV 45H,#07H
S_07_RETURN:
     SETB 0BH       
     RET


/*状态0E修理子程序*/
S_CLOCK1:
    
LOOP_0E:
     MOV R0,#62H        ;设置显示内容
  MOV R1,#05H
  MOV R5,#02H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_0E      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_0E     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_18_RETURN
S_0E:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_0E_0        ;长按,去判断A键B键
  JBC 01H,S_0E_1        ;短按,去判断A键B键
  INC 59H         ;A键,分+1
  SETB 05H          ;置位,时改变标志
  LJMP LOOP_0E
S_0E_0:
     JBC 01H,S_0E_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#01H        ;A键,状态转为08H
  LJMP S_0E_RETURN
S_0E_1:           ;短按B键,分-1,并置位时改变标志
      DEC 59H
   SETB 05H
   LJMP LOOP_0E
S_0E_2:
     MOV 45H,#01H
S_0E_RETURN:
     MOV 68H,#00H 
     RET
   
/*状态1C修理子程序*/
S_CLOCK2:

LOOP_1C:
     MOV R0,#62H        ;设置显示内容
  MOV R1,#05H
  MOV R5,#02H
  LCALL COUNT_OUTPUT       ;计算显示数据
  LCALL SHOW         ;显示
  LCALL KEY_READ      ;读键盘
     JBC 00H,S_1C      ;有键,则去判断长按短按
  INC 69H        ;无键,定时标志+1
  MOV A,69H
  CJNE A,#0FFH,LOOP_1C     ;定时到,状态转为01H,子程序返回
  MOV 45H,#01H
  LJMP S_1C_RETURN
S_1C:
     MOV 69H,#00H       ;有按键,清零定时标志
     JBC 02H,S_1C_0        ;长按,去判断A键B键
  JBC 01H,S_1C_1        ;短按,去判断A键B键
  INC 59H         ;A键,分+1
  SETB 05H          ;置位,时改变标志
  LJMP LOOP_1C
S_1C_0:
     JBC 01H,S_1C_2        ;长按,B键,状态变为了01H,并子程序返回
  MOV 45H,#01H        ;A键,状态转为08H
  LJMP S_1C_RETURN
S_1C_1:           ;短按B键,分-1,并置位时改变标志
      DEC 59H
   SETB 05H
   LJMP LOOP_1C
S_1C_2:
     MOV 45H,#01H
S_1C_RETURN:
     MOV 68H,#00H 
     RET

 


/*时间按秒增长子程序*/
CHANG_TIME:
     JBC 03H,C_TIME      ;秒定时标志是否为1,为1则去改变时间,否则子程序返回
  LJMP C_RETURN
C_TIME:
     MOV A,68H       ;读出秒,加1,判断是否大于等于60,是则送#00H到68H,否则将秒写回68H
  INC A
  SETB 04H
  CJNE A,#3CH,S       ;仅当秒大于等于60时,才去改变分
  MOV 68H,#00H
  LJMP M0
S:
     MOV 68H,A          
  LJMP C_RETURN
M0:
     MOV A,59H         ;读出分,加1,判断是否大于等于60,是则送#00H到59H,否则将秒写回59H
  INC A
  SETB 05H
  CJNE A,#3CH,M1      ;仅当分大于等于60时,才去改变时
  MOV 59H,#00H
  LJMP H0
M1:
     MOV 59H,A
  LJMP C_RETURN
H0:
     MOV A,58H        ;读出时,加1,判断是否大于等于24,是则送#00H到58H,否则将秒写回58H
  INC A
  SETB 06H
  CJNE A,#18H,H1       ;仅当时大于等于24时,才去改变日
  MOV 58H,#00H
  LJMP DAY0
H1: 
     MOV 58H,A
  LJMP C_RETURN
DAY0:
     MOV A,49H         ;读出日,加1,判断是否大于等于31,是则送#01H到49H,否则将秒写回49H
  INC A
  SETB 07H
  CJNE A,#1EH,DAY1        ;仅当日大于等于30时,才去改变月
  MOV 49H,#01H
  LJMP MON0
DAY1:
     MOV 49H,A
  LJMP C_RETURN
MON0:
     MOV A,48H        ;读出月,加1,判断是否大于等于13,是则送#01H到48H,否则将秒写回48H
  INC A
  SETB 08H
  CJNE A,#0CH,MON1      ;仅当月大于等于13时,才去改变年
  MOV 48H,#01H
  LJMP YEARL0
MON1:
     MOV 48H,A
  LJMP C_RETURN
YEARL0:
     MOV A,47H       ;读出年(L),加1,判断是否大于等于100,是则送#00H到48H,否则将秒写回47H
  INC A
  SETB 09H
  CJNE A,#64H,YEARL1     ;仅当年(L)大于等于100时,才去改变年(H)
  MOV 47H,#00H
  LJMP YAERH0
YEARL1:
     MOV 47H,A
  LJMP C_RETURN
YAERH0:
     MOV A,46H       ;读出年(H),加1,判断是否大于等于100,是则送#00H到48H,否则将秒写回46H
  INC A
  SETB 0AH
  CJNE A,#64H,YEARH1
  MOV 46H,#00H
  LJMP C_RETURN
YEARH1:
  MOV 46H,A
                         
C_RETURN:
     RET

/*数码管显示子程序,R0存显示内容首址,R1存位选首址 ,*/


SHOW:
 MOV DPTR,#LED_DATA
S2:
 MOV A,R1
 RL A
 RL A
 MOV P2,A
 MOV A,@R0
 MOVC A,@A+DPTR
 CPL A
 MOV P0,A
 INC R0
 DEC R1
 MOV R4,#01H
 LCALL DELAY
 DJNZ R5,S2
 MOV R4,#01H
    LCALL DELAY
 RET


/*键盘扫描子程序*/

 


KEY_READ:
    JB P1.0,NEXT
 MOV R4,#64H
 LCALL DELAY
 JB P1.0,NEXT
 SETB TR0
 SETB 00H
 CLR 01H
 JNB P1.0,$
 CLR TR0
 JNB TF0,KEY_RETUN
 SETB 02H
 LJMP KEY_RETUN
NEXT:
    JB P1.2,KEY_RETUN
 MOV R4,#64H
 LCALL DELAY
 JB P1.2,KEY_RETUN
 SETB TR0
 SETB 00H
 SETB 01H
 JNB P1.2,$
 CLR TR0
 JNB TF0,KEY_RETUN
 SETB 02H
 LJMP KEY_RETUN

KEY_RETUN:
    MOV TH0,#15H     ;重赋T0定时初值
 MOV TL0,#0A0H
    CLR TF0
 RET    
    
/*定时器T1中断服务子程序*/ 
  
INT_T1:
    PUSH ACC
    DJNZ R6,INT_1
 MOV R6,#50H
 DJNZ R7,INT_1
 MOV R7,#32H 
 SETB 03H
INT_1:
 POP ACC
    RETI 
    
/*延时子程序,R2,R3为定时常数,R4为定时变量*/

DELAY:
D: MOV R2,#0AH
D0: MOV R3,#0AH
D1: DJNZ R3,D1
    DJNZ R2,D0
 DJNZ R4,D
 RET     

 

 

/*数码管显示代码,0~F*/

LED_DATA:
     DB 03H,9FH,25H,0DH,99H,49H,41H,1FH
  DB 01H,09H,11H,0C1H,63H,85H,61H,71H


  END    

关闭窗口

相关文章