⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcf8563.asm

📁 51单片机对高精度计时芯片PCF8563的访问及数据通信程序——汇编程序
💻 ASM
字号:
; ======PCF8563初始化设置=====================================================

RTCINIT:ACALL	I2C_BG			;启始位
	MOV	A, #10100010B		;发送目的器件地址,PCF8563
	ACALL	I2C_O
	MOV	A, #00H			;准备写入控制寄存器1、2
	ACALL	I2C_O
	MOV	A, #00H			;REGISTER 1 = 00
	ACALL	I2C_O
	MOV	A, #00H			;REGISTER 2 = 00
	ACALL	I2C_O
	ACALL	I2C_ED
	CLR	C
	RET


; ======USE R0, R2, A, B=====================================================
TIME_G: ACALL	I2C_BG
	MOV	A, #10100010B		;先发送[写]命令
	ACALL	I2C_O
	MOV	A, #02			;发送秒寄存器编号
	ACALL	I2C_O

	SETB	SCL			;I2C_O返回时SCL=0,所以需要置 1
	NOP
	NOP
	ACALL	I2C_BG			;这样I2C_BG才能正常执行
	MOV	A, #10100011B		;发送读命令
	ACALL	I2C_O
	MOV	B, #07H
	MOV	R0, #RTCBUF		;取得时间,从PCF8563取得时间到缓冲区
TIME_G1:MOV	DPL, #08H		;取得一个字节
TIME_G2:SETB	SDA			;准备用 SDA 输入,所以先将其置 1。
	SETB	SCL			;SCL=1
	NOP
	NOP
	MOV	C, SDA			;SDA 已经有效,取到 C 中
	RLC	A			;C->ACC.0
	CLR	SCL			;SCL=0
	DJNZ	DPL, TIME_G2		;得到的一个字节在 ACC 中
	MOV	@R0, A
	INC	R0
	MOV	A, B
	XRL	A, #01H
	JZ	TIME_G3 		;是最后一个字节,就不发确认位
	CLR	SDA
TIME_G3:SETB	SCL			;不向 I2C 发送 ACK 位,而是一个空的时钟
	NOP
	NOP
	NOP
	CLR	SCL
	SETB	SDA
	DJNZ	B, TIME_G1		;取得不止一个字节

	ACALL	I2C_ED
	
	MOV	RTCBUF+4, RTCBUF+5	;将月临时保存到星期的位置
	MOV	RTCBUF+5, RTCBUF+6	;将年临时保存到月的位置

	ANL	RTCBUF+0, #7FH		;避免出现不合理数值
	ANL	RTCBUF+1, #7FH
	ANL	RTCBUF+2, #3FH
	ANL	RTCBUF+3, #3FH
	ANL	RTCBUF+4, #1FH
	
	RET

; ===================================================================
;	时间设定,年、月、日、时、分、秒
TIME_A: ACALL	KEYSCN
	MOV	A, R7
	XRL	A, #01H
	MOV	R6, #00H
	JZ	TIME_A2		;长时间按键(>1秒)
	MOV	A, R7
	ADD	A, #-23		;小于0.2秒 
	JC	TIME_AA		;时间太短,返回
	MOV	R6, #01H	;自动循环显示一遍时间,年月日时分秒

TIME_A2:ACALL	TIME_G		;从DS1302取得当前时间,放到缓冲区
	MOV	LCDBUF, #0BH	;'t'
	MOV	R0, #RTCBUF+5	;设定缓冲区时间, 从年开始
	MOV	R2, #1AH	;符号'n'-'S'
	MOV	R3, #00H	;保存各个上下限的表格的指针

TIME_AL:MOV	A, R3		;根据R3计算当前值的上下限
	MOV	DPTR, #TM_LH
	MOVC	A, @A+DPTR
	MOV	R4, A		;R4放下限
	MOV	A, R3
	INC	A
	MOVC	A, @A+DPTR
	MOV	R5, A		;R5放上限

	MOV	LCDBUF+1, R2
TIME_AM:MOV	A, @R0
	ACALL	BYTE_D
	ACALL	DISP
	CJNE	R6, #01H, TIME_A3
	MOV	B, #04
TIME_AN:ACALL	DELAY
	DJNZ	B, TIME_AN
	AJMP	TIME_AS

TIME_A3:JB	SETKEY, $
	ACALL	KEYSCN
	JB	F0, TIME_A3	;按键无效
	CJNE	R7,#01H,TIME_A4	;按键时间短,调整当前值
TIME_AS:INC	R2
	DEC	R0
	INC	R3
	INC	R3
	CJNE	R3, #12, TIME_AL
	CJNE	R6, #01H, TIME_A6
	AJMP	TIME_A9

TIME_A4:MOV	A, @R0
	ADD	A, #01H
	DA	A
	CJNE	A, 05H, TIME_A5
	MOV	A, R4
TIME_A5:MOV	@R0, A
	AJMP	TIME_AM

TIME_A6:MOV	RTCBUF+6, RTCBUF+5	;将年送回到正确的位置
	MOV	RTCBUF+5, RTCBUF+4	;将年送回到正确的位置
	ACALL	TIME_S		;将缓冲区时间保存到DS1302

TIME_A9:ACALL	DISP_0
	MOV	LCDBUF+3, #00H
TIME_AA:RET

;	0BH-->'t',
TM_LH:	DB	0,50H, 1,13H, 1,32H, 0,24H, 0,60H, 0,60H


; USE R7, A
KEYSCN:	ACALL	TM0_ST		;用T0计时

	MOV	R7, #30
KEYSCN0:JNB	TF0, KEYSCN1
	CLR	TF0
	DJNZ	R7, KEYSCN1
	MOV	R7, #1
KEYSCN1:JNB	SETKEY, KEYSCN0
	MOV	A, #20
	ACALL	DELAY
	JNB	SETKEY, KEYSCN0
	CLR	F0
	CJNE	R7, #30, KEYSCNE
	SETB	F0
KEYSCNE:RET

; ======USE R0, R2, R3, A, B===============================================
TIME_S: ACALL	I2C_BG			;启始位
	MOV	A, #10100010B		;发送目的器件地址,PCF8563
	ACALL	I2C_O
	MOV	A, #02H			;准备写入寄存器2-8
	ACALL	I2C_O
	
	MOV	R0, #RTCBUF
	MOV	R2, #07H
TIME_S1:MOV	A, @R0
	ACALL	I2C_O
	INC	R0
	DJNZ	R2, TIME_S1
	ACALL	I2C_ED
	RET


;======= I2C SUBROUTINE =================================================================
;	I2CD_W, I2CD_R		:LAYER 1
;	I2C_O,	I2C_I		;LAYER 2
;	I2C_BG, I2C_ED		;LAYER 3
;========================================================================================
;	向存储器写入几个字节,最多8个字节。
;	入口:DPTR 要写的EEPROM存储单元地址。
;	      R0   指向要写入字节在RAM的首地址。
;	      B    写入字节个数。
;	出口:如果 C=1,说明写出错。

I2CD_W: ACALL	I2C_BG
	MOV	A, #10100000B	;写命令
	ACALL	I2C_O
	JC	I2CD_WE 	;C=1, 未收到 ACK 位,出错,不再继续处理,直接返回

	MOV	A, DPH
	ACALL	I2C_O
	JC	I2CD_WE

	MOV	A, DPL
	ACALL	I2C_O
	JC	I2CD_WE

I2CD_WL:MOV	A, @R0
	ACALL	I2C_O
	JC	I2CD_WE
	INC	R0
	DJNZ	B, I2CD_WL

	ACALL	I2C_ED
	CLR	C
	RET
I2CD_WE:ACALL	I2C_ED
	SETB	C
	RET

;===============================================================================
;	从 EEPROM 读入几个字节
;	入口:DPTR 要读的存储单元地址。
;	      R0   指向要写入字节在RAM的首地址。
;	      B    写入字节个数。
;	出口:读到的内容在缓冲区中,如果 C=1,说明读出错。
I2CD_R: ACALL	I2C_BG
	MOV	A, #10100000B	;先发送[写]命令
	ACALL	I2C_O
	JC	I2CD_RE 	;C=1, 未收到 ACK 位,出错,不再继续处理,直接返回

	MOV	A, DPH		;发送地址低位
	ACALL	I2C_O
	JC	I2CD_RE

	MOV	A, DPL		;发送地址低位
	ACALL	I2C_O
	JC	I2CD_RE

	ACALL	I2C_BG
	MOV	A, #10100001B	;发送读命令
	ACALL	I2C_O
	JC	I2CD_RE

I2CD_IB:MOV	DPL, #08H	;取得一个字节
I2CD_IL:SETB	SDA		;准备用 SDA 输入,所以先将其置 1。
	SETB	SCL		;SCL=1
	NOP
	NOP
	MOV	C, SDA	;SDA 已经有效,取到 C 中
	RLC	A		;C->ACC.0
	CLR	SCL		;SCL=0
	DJNZ	DPL, I2CD_IL	;得到的一个字节在 ACC 中
	MOV	@R0, A
	INC	R0
	MOV	A, B
	XRL	A, #01H
	JZ	I2CD_GO 	;是最后一个字节,就不发确认位
	CLR	SDA
	NOP
I2CD_GO:SETB	SCL		;不向 EEPROM 发送 ACK 位,而是一个空的时钟
	NOP
	NOP
	NOP
	CLR	SCL
	SETB	SDA
	DJNZ	B, I2CD_IB	;取得不止一个字节

	ACALL	I2C_ED
	CLR	C
	RET
I2CD_RE:ACALL	I2C_ED
	SETB	C
	RET

;向 IIC 总线发送一个字节
I2C_O:	PUSH	B
	MOV	B, #08H
I2C_OLP:RLC	A		;ACC.7 -> C
	MOV	SDA, C
	SETB	SCL		;SCL=1
	NOP
	NOP
	NOP
	CLR	SCL		;SCL=0
	DJNZ	B, I2C_OLP
	SETB	SDA		;准备接收 ACK 位
	SETB	SCL		;SCL=1, [SDA=1]
	NOP
	NOP
	MOV	C, SDA
	CLR	SCL
	POP	B
	RET			;C=1, 未收到 ACK 位,出错, C=0, 收到 ACK 位,正常

;向 IIC 总线发送开始位
I2C_BG: SETB	SCL
	NOP
	NOP
	CLR	SDA
	NOP
	CLR	SCL
	SETB	SDA
	RET


;向 IIC 总线发送停止位
I2C_ED: CLR	SDA
	SETB	SCL
	ACALL	I2C_ED9		;5
	ACALL	I2C_ED9		;5
	SETB	SDA
	NOP
	CLR	SCL
I2C_ED9:RET

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -