📄 i2c.asm
字号:
INCLUDE "637XX.INC"
SET_WP: EQU 02H
CLR_WP: EQU FDH
SET_SCL: EQU 01H ;P10
CLR_SCL: EQU FEH
SET_SDA: EQU 01H ;P00
CLR_SDA: EQU FEH
;**********************************************************
;FUNCTION: I2CSTART
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
I2CSTART:
CALL SDA_HIGH
CALL SCL_HIGH
CALL SDA_LOW
CALL SCL_LOW
RET
;**********************************************************
;FUNCTION: I2CSTOP
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
I2CSTOP:
CALL SDA_LOW
CALL SCL_HIGH
CALL SDA_HIGH
CALL DELAY_60
CALL SCL_LOW
RET
;**********************************************************
;FUNCTION: WAITACK
;INTPUT:
;OUTPUT: ACC=OK: ACK正确; ACC=NOK: ACK错误
;USEAGE: REC_TEMP
;CALL:
;**********************************************************
WAITACK:
CALL SDA_HIGH
CALL SCL_HIGH
IORD PORT0
AND A,SET_SDA
JZ ACK_OK
MOV A,NOK
MOV [REC_TEMP],A
JMP WAITACK_RET
ACK_OK:
MOV A,OK
MOV [REC_TEMP],A
WAITACK_RET:
CALL SCL_LOW
MOV A,[REC_TEMP]
OR A,0
RET
;**********************************************************
;FUNCTION: SENDACK
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
SENDACK:
CALL SDA_LOW
CALL SCL_HIGH
CALL SCL_LOW
CALL SDA_HIGH
RET
;**********************************************************
;FUNCTION: SENDNAK
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
SENDNAK:
CALL SDA_HIGH
CALL SCL_HIGH
CALL SCL_LOW
CALL SDA_LOW
RET
;**********************************************************
;FUNCTION: I2CSENDBYTE
;INTPUT: ACC:要发送的数据
;OUTPUT:
;USEAGE: R5
;CALL:
;**********************************************************
I2CSENDBYTE:
RRC ;先往右移动一位,后续循环处理方便
MOV [SEND_TEMP],A
MOV A,8
MOV [R5],A
I2CSENDBYTE_LOOP:
MOV A,[SEND_TEMP]
RLC
MOV [SEND_TEMP],A
AND A,80H
JNZ SEND_HIGH_BIT
CALL SDA_LOW
CALL SCL_HIGH
CALL SCL_LOW
JMP SEND_NXT_BIT
SEND_HIGH_BIT:
CALL SDA_HIGH
CALL SCL_HIGH
CALL SCL_LOW
SEND_NXT_BIT:
DEC [R5]
JNZ I2CSENDBYTE_LOOP
RET
;**********************************************************
;FUNCTION: I2CRECEIVEBYTE,I2C读一个字节
;INTPUT: none
;OUTPUT: ACC
;USEAGE:
;CALL:
;**********************************************************
I2CRECEIVEBYTE:
MOV A,0
MOV [REC_TEMP],A
CALL SDA_HIGH
MOV A,8
MOV [R5],A
I2CRECEIVEBYTE_LOOP:
CALL SCL_HIGH
IORD PORT0
AND A,SET_SDA
JNZ REC_HIGH_BIT
MOV A,[REC_TEMP]
ASL
AND A,FEH
JMP REC1
REC_HIGH_BIT:
MOV A,[REC_TEMP]
ASL
OR A,1
REC1:
MOV [REC_TEMP],A
CALL SCL_LOW
DEC [R5]
JNZ I2CRECEIVEBYTE_LOOP
MOV A,[REC_TEMP]
RET
;**********************************************************
INITI2C:
CALL WP_HIGH
CALL SCL_LOW
CALL SDA_LOW
RET
;**********************************************************
;FUNCTION: READEEPROM:从EEPROM读若干个字节;
;INTPUT: DPTR: EEPROM 地址
; R0: 数据在RAM中的地址
; R2: 长度
;OUTPUT: NONE; 读出的数据在R0指定的RAM中
;USEAGE: R0--R2,R5,REC_TEMP
;CALL:
;FUNCTION: READEEPROM_1BYTE:从EEPROM读1个字节
;INTPUT: DPTR: EEPROM 地址
;OUTPUT: NONE; 读出的数据在ACC中
;USEAGE: R1--R2,R5,REC_TEMP
;CALL:
;**********************************************************
N_BYTE_FLAG: EQU FFH
READEEPROM:
MOV A,N_BYTE_FLAG
MOV [R1],A ;R1保存读若干字节的标志
JMP READEEPROM_ALL
READEEPROM_1BYTE:
MOV A,0
MOV [R1],A
READEEPROM_ALL:
CALL I2CSTART
MOV A,A0H
CALL I2CSENDBYTE ;SEND DEVICE ADDRESS
CALL WAITACK
JNZ I2CREADERROR
MOV A,[DPH]
CALL I2CSENDBYTE ;SEND ADDRESS HIGH
CALL WAITACK
JNZ I2CREADERROR
MOV A,[DPL]
CALL I2CSENDBYTE ;SEND ADDRESS LOW
CALL WAITACK
JNZ I2CREADERROR
CALL I2CSTART
MOV A,A1H ;READ BIT=1
CALL I2CSENDBYTE ;SEND DEVICE ADDRESS
CALL WAITACK
JNZ I2CREADERROR
MOV A,[R1]
CMP A,N_BYTE_FLAG
JNZ READ_1BYTE
MOV X,[R0]
READEEPROM_LOOP:
CALL I2CRECEIVEBYTE
MOV [X+0],A
INC X
DEC [R2]
JZ READEEPROM_NAK
CALL SENDACK
JMP READEEPROM_LOOP
READ_1BYTE:
CALL I2CRECEIVEBYTE
MOV [R2],A ;R2保存单字节读的结果
READEEPROM_NAK:
CALL SENDNAK
CALL I2CSTOP
MOV A,[R2]
JMP READEEPROM_RET
I2CREADERROR:
CALL I2CSTOP
READEEPROM_RET:
RET
;**********************************************************
;FUNCTION: WRITEEEPROM 往EEPROM中写若干字节
;INTPUT: DPHDPL:EEPROM 地址
; R0: 数据在RAM中的地址
; R2: 长度
;OUTPUT: ACC=0:OK; ACC<>0: ERROR
;USEAGE: R0--R3,R5,使用4级堆栈, R0不改变
;CALL:
;NOTICE: 不能跨页,长度不能超过(32:AT24C64; 64: AT24C128/256; 128: AT24C512)
; 若写出错,堆栈不平衡
;**********************************************************
WRITEEEPROM:
WR_N_BYTE:
MOV A,[DPH]
PUSH A
MOV A,[DPL]
PUSH A
MOV A,[R0]
PUSH A ;入口参数全部进栈
MOV A,[R2]
PUSH A
CALL WP_LOW
WRITEEEPROM_LOOP:
CALL I2CSTART
MOV A,A0H
CALL I2CSENDBYTE ;SEND DEVICE ADDRESS
CALL WAITACK
JNZ I2CWRITEERROR0
MOV A,[DPH]
CALL I2CSENDBYTE ;SEND ADDRESS HIGH
CALL WAITACK
JNZ I2CWRITEERROR0
MOV A,[DPL]
CALL I2CSENDBYTE ;SEND ADDRESS LOW
CALL WAITACK
JNZ I2CWRITEERROR0
MOV A,[DPL]
AND A,(PAGESIZE-1)
MOV [R1],A
MOV A,PAGESIZE
SUB A,[R1]
MOV [R1],A ;R1=当前地址到当前页末的字节数
MOV A,[R2]
SUB A,[R1]
JC LAST_PAGE ;剩余总长度<当前地址到当前页末的字节数,
MOV [R2],A ;R2=后若干页的长度,R1=当前页要写的字节数
JMP WRITE_PAGE
LAST_PAGE:
MOV A,[R2]
MOV [R1],A ;R1=当前页要写的长度
MOV A,0
MOV [R2],A ;R2(剩余长度)=0
WRITE_PAGE:
MOV X,[R0]
WRITE_PAGE_LOOP:
MOV A,[X+0]
CALL I2CSENDBYTE ;写第一页
CALL WAITACK
JNZ I2CWRITEERROR0
INC X
INC [R0] ;RAM地址+1
CALL INC_DPTR ;EEPROM地址+1
DEC [R1]
JNZ WRITE_PAGE_LOOP
CALL I2CSTOP
POLL_ACK:
CALL I2CSTART ;查询是否写完
MOV A,A0H
CALL I2CSENDBYTE
CALL WAITACK
JNZ POLL_ACK
MOV A,[R2]
OR A,0
JNZ WRITEEEPROM_LOOP
POP A
MOV [R3],A
POP A
MOV [R0],A
POP A
MOV [DPL],A
POP A
MOV [DPH],A
COMP_LOOP:
CALL READEEPROM_1BYTE ;写后读 USE R1,R2
MOV X,[R0]
CMP A,[X+0]
JNZ I2CWRITEERROR
INC [R0] ;RAM的地址+1
CALL INC_DPTR ;EEPROM的地址+1
DEC [R3]
JNZ COMP_LOOP
CALL WP_HIGH
MOV A,OK
JMP WRITEEEPROM_RET
I2CWRITEERROR0:
POP A
POP A
POP A
POP A ;退栈,使栈平衡
I2CWRITEERROR:
CALL I2CSTOP
CALL WP_HIGH
CALL DELY_10MS
MOV A,NOK
WRITEEEPROM_RET:
OR A,0
RET
;**********************************************************
;FUNCTION: SCL_HIGH
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
SCL_HIGH: ;10 TIME=72/12=6US; T=12US
IORD PORT1 ;5
OR A,SET_SCL ;4
IOWR PORT1 ;5
IOWR WATCHDOG ;5 此条指令必须执行,否则可能复位
RET ;8
;**********************************************************
;FUNCTION: SCL_LOW
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
SCL_LOW:
IORD PORT1
AND A,CLR_SCL
IOWR PORT1
IOWR WATCHDOG ; [5]
RET
;**********************************************************
;FUNCTION: SDA_HIGH
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
SDA_HIGH:
IORD PORT0
OR A,SET_SDA
IOWR PORT0
IOWR WATCHDOG ; [5]
RET
;**********************************************************
;FUNCTION: SDA_LOW
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
SDA_LOW:
IORD PORT0
AND A,CLR_SDA
IOWR PORT0
IOWR WATCHDOG ; [5]
RET
;**********************************************************
;FUNCTION: WP_HIGH
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
WP_HIGH:
IORD PORT1
OR A,SET_WP
IOWR PORT1
CALL DELAY_60
RET
;**********************************************************
;FUNCTION: SDA_LOW
;INTPUT:
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
WP_LOW:
IORD PORT1
AND A,CLR_WP
IOWR PORT1
CALL DELAY_60
RET
;**********************************************************
;FUNCTION: DPTR+1
;INTPUT: NONE
;OUTPUT:
;USEAGE:
;CALL:
;**********************************************************
INC_DPTR:
INC [DPL]
JNZ INC_DPTR_RET
INC [DPH]
INC_DPTR_RET:
RET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -