C51汇编实现时间控制器+proteus仿真

电路图:
在这里插入图片描述
汇编代码:

		ORG 0000H
		LJMP MAIN	
		ORG 000BH			
		LJMP TIME	
		ORG 0100H
					
;宏定义
        ;键位
		K0	BIT 20H.0
		K1	BIT 20H.1
		K2	BIT 20H.2
		K3  BIT 20H.3
		K4	BIT 20H.4
		;暂存区
		ST  DATA 68H
		MT 	DATA 69H
		HT	DATA 6AH
		DT 	DATA 6BH
		MOUT DATA 6CH
		YLT	DATA 6DH
		YHT DATA 6EH	
		SPT DATA 21H	;移位指针
        ;时钟时间寄存区			
		S 	DATA 60H
		M 	DATA 61H
		H 	DATA 62H
		D 	DATA 63H
		MOU DATA 64H
		YL 	DATA 65H
		YH  DATA 66H
		FLAG DATA 67H
        ;闹钟时间寄存区			
		SC		DATA 50H
		MC		DATA 51H
		HC		DATA 52H
		DC		DATA 53H
		MOUC	DATA 54H
		YLC		DATA 55H
		YHC		DATA 56H
			
		;时间显示缓冲区
		//存放数码管显示16位的数据
		SDL		DATA 70H
		SDH 	DATA 71H
		POINT1 	DATA 72H
		MDL 	DATA 73H
		MDH 	DATA 74H
		POINT2 	DATA 75H
		HDL 	DATA 76H
		HDH 	DATA 77H
		DDL 	DATA 78H
		DDH 	DATA 79H
		MOUDL 	DATA 7AH
		MOUDH 	DATA 7BH
		YD0   	DATA 7CH
		YD1		DATA 7DH
		YD2		DATA 7EH
		YD3		DATA 7FH
			
//主程序
MAIN:	
		MOV TMOD,#01H		;T0工作方式1
		MOV TL0,#0B0H
		MOV TH0,#3CH		;50ms
		MOV R7,#20			;20*50ms = 1s
		MOV S,#50
		MOV M,#59
		MOV H,#11
		MOV D,#11
		MOV MOU,#12
		MOV YL,#20
		MOV YH,#20
		MOV POINT1,#10		;在TABLE中第10个对应“-”
		MOV POINT2,#10		
		MOV SPT,#1			;移位指针初始最低位为1
		SETB K0				
		CLR	 K1				;K1置1 (非暂停状态)
		CLR  K2				;K2置1  默认修改模式
		CLR  P3.5           ;默认蜂鸣器非工作状态
		CLR  P3.6           ;默认LED非工作状态
		SETB ET0			
		SETB EA
		SETB TR0			;开启定时器
		
;不断循环
GO_ON:
		LCALL CHECK_KEY
		LCALL DISPLAY
		LCALL CHECK_CLOCK	 ;闹铃
		LCALL LIGHT_ON       ;开灯
	    LCALL LIGHT_OFF      ;关灯
		SJMP GO_ON           ;跳转循环
		
;定时子程序
TIME:	
		MOV TL0,#0B0H
		MOV TH0,#3CH		
		DJNZ R7,TIME_END	
		MOV R7,#20          ;循环20次 定时1s
		LCALL TIME_INC		;跳转到计时
		LCALL SAVE0			;跳转到数据转移
		LCALL SEND_TO_DIS	;储存时间寄存器中的BCD
TIME_END:
		RETI				





;数码管显示子程序
DISPLAY:
		MOV R0,#SDL			;数据缓存区指针
		MOV DPTR,#TABLE		;七段共阴数码管0-9显示
		MOV R1,#0	        ;R1存放表示第几位的数字
		
//P0口实现片选		
NEXT:	MOV P0,R1			;显示位连接P0
		MOV A,R1
		CLR C				
		SUBB A,#8	   //实现前8个向HMS跳转,后8个向YMD跳转		
		JC	HMS				

//P2口实现年月日
DIAN1:	//先判断是否位第10位,第10位需要有小数点
		CJNE R1,#10,DIAN2    ;跳转判断DIAN2
		MOV DPTR,#TABLE1
		MOV A,@R0			;取显示数字
		MOVC A,@A+DPTR		
		MOV P2,A			;显示年月日
		LCALL DELAY			;调用延时
		MOV DPTR,#TABLE
		SJMP GO

DIAN2:	//再判断是否位第12位,第12位也需要有小数点
		CJNE R1,#12,YMD     ;若不是第10,12位,跳转YMD
		MOV DPTR,#TABLE1
		MOV A,@R0			;取显示数字
		MOVC A,@A+DPTR		
		MOV P2,A			;显示年月日
		LCALL DELAY			;调用延时
		MOV DPTR,#TABLE
		SJMP GO
		
YMD:    //正常输出没小数点的数字
		MOV A,@R0			;取显示数字
		MOVC A,@A+DPTR		
		MOV P2,A			;显示年月日
		LCALL DELAY			;调用延时
		SJMP GO

//P1口实现时分秒
HMS:	MOV A,@R0			;取显示数字
		MOVC A,@A+DPTR		
		MOV P1,A			;显示时分秒
		LCALL DELAY			;调用延时
		SJMP GO
		
GO:		INC R1				;显示位左移
		INC R0			
		CJNE R1,#16,NEXT
		RET
//共阳极,0亮1灭,共阴极,1亮0灭
TABLE:	DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,40H	;七段共阴数码管0-9
TABLE1:	DB 0BFH,86H,0DBH,0CFH,0E6H,0EDH,0FDH,87H,0FFH,0EFH,40H	;带小数点的七段共阴数码管0-9





;计时程序
TIME_INC:	
SEC:	INC S				;+1S
		MOV R6,S
		CJNE R6,#60,INC_END ;满60秒进位
		MOV R6,#0
		MOV S,R6
		SJMP MIN
MIN:	INC M				;+1M
		MOV R6,M
		CJNE R6,#60,INC_END ;满60分钟进位
		MOV R6,#0
		MOV M,R6
		SJMP HOUR
HOUR:	INC H				;+1H
		MOV R6,H
		CJNE R6,#24,INC_END ;满24小时进位
		MOV R6,#0
		MOV H,R6
DAY:	LCALL CHECK_Y       ;检查平闰年
		MOV R6,FLAG
		CJNE R6,#1,PING
		MOV DPTR,#R_YEAR    ;调用闰年月份表
		SJMP YGO
PING:	MOV DPTR,#P_YEAR	;调用平年月份表
YGO: 	MOV A,MOU
		MOVC A,@A+DPTR		
		INC A
		INC D				;+1D				
		CJNE A,D,INC_END
		MOV R6,#1
		MOV D,R6
		SJMP MOUN
MOUN:	INC MOU				;+1M
		MOV R6,MOU
		CJNE R6,#13,INC_END ;第13个月进位
		MOV R6,#0
		MOV MOU,R6
		SJMP YEAR
YEAR:	
		INC YL               ;+1Y低位
		MOV R6,YL
		CJNE R6,#100,INC_END
		MOV R6,#0
		MOV YL,R6
		INC YH               ;+1Y高位
		MOV R6,YH
		CJNE R6,#100,INC_END
		MOV R6,#0
		MOV YH,R6
INC_END:
    RET  

;检查平闰年子程序
CHECK_Y:
		MOV A,YL
		MOV B,#4
		DIV AB
		MOV A,B
		JNZ SET_FLAG
		MOV FLAG,#1
		SJMP CHECK_END
SET_FLAG:
		MOV FLAG,#0
CHECK_END:	
		RET

P_YEAR:	DB 0,31,28,31,30,31,30,31,31,30,31,30,31		;平年月份表
R_YEAR:	DB 0,31,29,31,30,31,30,31,31,30,31,30,31		;闰年月份表
	
;将暂存区中的数据转为BCD码存入显示缓冲区
SEND_TO_DIS:						
		MOV A,ST
		LCALL H2B
		MOV SDL,R4
		MOV SDH,R5					;存秒
		
		MOV A,MT
		LCALL H2B
		MOV MDL,R4
		MOV MDH,R5					;存分
		
		MOV A,HT
		LCALL H2B
		MOV HDL,R4
		MOV HDH,R5					;存时
		
		MOV A,DT
		LCALL H2B
		MOV DDL,R4
		MOV DDH,R5					;存天
		
		MOV A,MOUT
		LCALL H2B
		MOV MOUDL,R4
		MOV MOUDH,R5				;存月
		
		MOV A,YLT
		LCALL H2B
		MOV YD0,R4
		MOV YD1,R5					;存年(低位)
		
		MOV A,YHT
		LCALL H2B
		MOV YD2,R4
		MOV YD3,R5					;存年(高位)
		RET
		
;1ms延时子程序
DELAY:	
		MOV R3,#4
DEL:	MOV R2,#250
		DJNZ R2,$
		DJNZ R3,DEL
		RET

;
H2B:	MOV B,#10
		DIV AB
		MOV R5,A			;个位存到R5
		MOV R4,B			;十位存到R4
		RET
		
;查询按键子程序
CHECK_KEY:
		MOV A,P3			;读取P3按键状态
		CPL A;
		JZ CHECK_EXIT
		ACALL KEY_DELAY
		MOV A,P3			;读取P3按键状态 确认是否有键按下
		CPL A
		JZ CHECK_EXIT
		JB ACC.0,ACT0		;暂停/恢复键
		JB ACC.1,ACT1		;闹钟键
		JB ACC.2,ACT2		;换位键
		JB ACC.3,ACT3		;+
		JB ACC.4,ACT4		;-
CHECK_EXIT:	
		RET
		
;按键子程序		
ACT:
ACT0:	MOV A,P3			;检测按键是否释放
		JNB ACC.0,ACT0		;键未释放,则继续等待
		CPL K0				;K0取反,在暂停/继续中转换
		JB	K0,START
		CLR TR0				;TR0=0,停止计时
		LJMP EXIT
START:	SETB TR0			;TRO=1,开始计时
		CLR  K1				;默认回修改功能
		RET
		
;定时/修改按钮
ACT1:	MOV A,P3			;检测按键是否释放
		JNB ACC.1,ACT1		;键未释放,则继续等待
		CPL K2				;取反闹铃使能开关
		JB	K0,EXIT			;若K0未在暂停状态,则返回
		CPL K1				;K1取反,0为修改,1为闹钟定时
		RET
		
;移位按钮
ACT2:	
		MOV A,P3			;检测按键是否释放
		JNB ACC.2,ACT2		;键未释放,则继续等待
		JB	K0,EXIT			;若K0未在暂停状态,则返回
		MOV A,SPT			
		RL 	A				;SPT移动(RL循环左移,RLC带进位左移,RL不带进位)
		MOV SPT,A	
		JNB ACC.7,EXIT		;最多移到01000000
		MOV SPT,#1			
		RET
		
;加
ACT3:	MOV A,P3			;检测按键是否释放
		JNB ACC.3,ACT3		;键未释放,则继续等待
		JB	K0,EXIT			;若K0未在暂停状态,则返回
		JB 	K1,CL_INC
		SJMP UP_INC
		RET
		
CL_INC:	                     ;闹钟
		LCALL KEY_INC
		LCALL SEND_TO_DIS
		LCALL SEND1
		RET	
		
UP_INC:	LCALL SAVE0
		LCALL KEY_INC
		LCALL SEND_TO_DIS
		LCALL SEND0
		RET
		
;减	
ACT4:	MOV A,P3			;检测按键是否释放
		JNB ACC.4,ACT4		;键未释放,则继续等待
		JB	K0,EXIT			;若K0未在暂停状态,则返回
		JB 	K1,CL_DEC
		SJMP UP_DEC
		RET
		
CL_DEC:	                    ;闹钟
		LCALL KEY_DEC
		LCALL SEND_TO_DIS
		LCALL SEND1
		RET	
		
UP_DEC:	LCALL SAVE0
		LCALL KEY_DEC
		LCALL SEND_TO_DIS
		LCALL SEND0
		RET		
	
EXIT:	RET

KEY_DELAY:
		MOV R3,#24
KEY_DEL:MOV R2,#0FAH
		DJNZ R2,$
		DJNZ R3,KEY_DEL
		RET


;数据转移子程序
SAVE0:	MOV ST,S
		MOV	MT,M	
		MOV	HT,H
		MOV	DT,D
		MOV	MOUT,MOU
		MOV	YLT,YL
		MOV	YHT,YH
		RET		
;将数据传给计时数据寄存器
SEND0:  MOV S,ST
		MOV	M,MT	
		MOV	H,HT
		MOV	D,DT
		MOV	MOU,MOUT
		MOV	YL,YLT
		MOV	YH,YHT
		RET
;将数据传给闹钟数据寄存器
SEND1:	MOV SC,ST
		MOV	MC,MT	
		MOV	HC,HT
		MOV	DC,DT
		MOV	MOUC,MOUT
		MOV	YLC,YLT
		MOV	YHC,YHT
		RET
		
//按下按键年月日时分秒的加减处理		
;+按键子程序
KEY_INC:
		JB 	SPT.0,S_INC     ;未按换位键 默认更改秒
		JB	SPT.1,M_INC     ;按一次更改分
		JB  SPT.2,H_INC     ;按两次更改小时
		JB	SPT.3,D_INC     ;按三次更改日
		JB	SPT.4,MOU_INC   ;按四次更改月
		JB	SPT.5,YL_INC    ;按五次更改年的个十位
		JB	SPT.6,YH_INC    ;按六次更改年的百千位
		
S_INC:	INC ST				;+1S
		MOV R6,ST
		CJNE R6,#60,EXIT_INC
		MOV R6,#0
		MOV ST,R6
		RET
		
M_INC:	INC MT				;+1M
		MOV R6,MT
		CJNE R6,#60,EXIT_INC
		MOV R6,#0
		MOV MT,R6
		RET
		
H_INC:	INC HT				;+1H
		MOV R6,HT
		CJNE R6,#24,EXIT_INC
		MOV R6,#0
		MOV HT,R6
		RET
		
D_INC:	LCALL CHECK_Y
		MOV R6,FLAG
		CJNE R6,#1,PING1
		MOV DPTR,#R_YEAR
		SJMP YGO1
PING1:	MOV DPTR,#P_YEAR	;暂存本月天数上限
YGO1: 	MOV A,MOUT
		MOVC A,@A+DPTR		
		INC A
		INC DT				;+1D				
		CJNE A,DT,EXIT_INC
		MOV R6,#1
		MOV DT,R6
		RET
		
MOU_INC:	
		INC MOUT			;+1M
		MOV R6,MOUT
		CJNE R6,#13,EXIT_INC
		MOV R6,#1
		MOV MOUT,R6
		RET
		
YL_INC:	INC YLT              ;+1Y低位
		MOV R6,YLT
		CJNE R6,#100,EXIT_INC
		MOV R6,#0
		MOV YLT,R6
		RET
		
YH_INC:	INC YHT               ;+1Y高位
		MOV R6,YHT
		CJNE R6,#100,EXIT_INC
		MOV R6,#0
		MOV YHT,R6
		RET
		
EXIT_INC:
		RET
		
;-按键子程序
KEY_DEC:
		//根据移位指针SPT哪一位是1
		JB 	SPT.0,S_DEC       ;未按换位键 默认更改秒
		JB	SPT.1,M_DEC       ;按一次更改分
		JB  SPT.2,H_DEC       ;按两次更改小时
		JB	SPT.3,D_DEC       ;按三次更改日
		JB	SPT.4,MOU_DEC     ;按四次更改月
		JB	SPT.5,YL_DEC      ;按五次更改年的个十位
		JB	SPT.6,YH_DEC      ;按六次更改年的百千位

S_DEC:
		DEC ST                ;-1s
		MOV R6,ST
		CJNE R6,#0FFH,EXIT_DEC
		MOV R6,#59
		MOV ST,R6
		RET
M_DEC: 
		DEC MT                ;-1m
		MOV R6,MT
		CJNE R6,#0FFH,EXIT_DEC
		MOV R6,#59
		MOV MT,R6
		RET
H_DEC:	       
		DEC HT                ;-1h
		MOV R6,HT
		CJNE R6,#0FFH,EXIT_DEC
		MOV R6,#23
		MOV HT,R6
		RET
		
D_DEC:	LCALL CHECK_Y
		MOV R6,FLAG
		CJNE R6,#1,PING2
		MOV DPTR,#R_YEAR
		SJMP YGO2
PING2:	MOV DPTR,#P_YEAR	
YGO2: 	MOV A,MOUT
		MOVC A,@A+DPTR		;暂存本月天数上限
		DEC	 DT				;-1D
		MOV R6,DT
		CJNE R6,#0,EXIT_INC
		MOV R6,A
		MOV DT,R6
		RET
		
MOU_DEC:
		DEC MOUT             ;-1MO
		MOV R6,MOUT
		CJNE R6,#0,EXIT_DEC
		MOV R6,#12
		MOV MOUT,R6
		RET
YL_DEC:	                     
		DEC YLT              ;-1Y(低位)
		MOV R6,YLT
		CJNE R6,#0FFH,EXIT_DEC
		MOV R6,#99
		MOV YLT,R6
		RET
YH_DEC:	
		DEC YHT               ;-1Y(低位)
		MOV R6,YHT
		CJNE R6,#0FFH,EXIT_DEC
		MOV R6,#99
		MOV YHT,R6
		RET

EXIT_DEC:
		RET
		
;闹钟响铃子程序
CHECK_CLOCK:                   ;判断是否响铃
		MOV R0,#M			
		MOV R1,#MC
		MOV R2,#5
CHECK_NEXT:			;
		MOV	A,@R0
		SUBB A,@R1			   ;判断当前时刻是否是闹铃时刻
		CLR C
		JNZ	CLOC_EXIT
		INC R0
		INC R1
		DJNZ R2,CHECK_NEXT
		LCALL TIMEOUT			;分 时 日 月 年均满足则调用响铃程序
		RET
		
CLOC_EXIT:                  
		CLR P3.5
		RET
;响铃程序		
TIMEOUT:					
		JNB K2,BUZ_END          ;按下按键停止响铃
BUZ:	SETB P3.5           
		LCALL BUZ_DELAY
		
BUZ_DELAY:                      ;延时
		MOV R3,#250
BUZ_T:	MOV R2,#40
		DJNZ R2,$
		DJNZ R3,BUZ_T
		RET
BUZ_END:	
		CLR P3.5
		RET
		
;亮灯子程序
LIGHT_ON:
    MOV A,#12
	CJNE A,H,TTE3
	MOV A,#00
	CJNE A,M,TTE3
	MOV A,#00
	CJNE A,S,TTE3
	SETB P3.6                   ;从12:00:00开始亮 
TTE3:	
   RET
LIGHT_OFF:
    MOV A,#23;CMP_LED_START
	CJNE A,H,TTE4
	MOV A,#00
	CJNE A,M,TTE4
	MOV A,#00
	CJNE A,S,TTE4
	CLR P3.6                    ;到21:00:00关灯
TTE4:
RET


	
		END
R_YEAR:	DB 0,31,29,31,30,31,30,31,31,30,31,30,31		;

TABLE:	DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,40H	;
	
		END

猜你喜欢

转载自blog.csdn.net/weixin_44026026/article/details/111350075