📄 24c02.asm
字号:
ACK BIT 20H
SLA EQU 30H
SUBA DATA 31H
NUMBYTE DATA 32H
MTD EQU 40H
MRD EQU 50H
SCL EQU 0B0H
SDA EQU 0B1H
EEROM02 EQU 0A0H
ORG 0000H
AJMP MAIN
ORG 0030H
MAIN : MOV SP,#60H
MOV A,#55H
MOV R0,#MTD
MOV R1,#08H
LOOP1: MOV @R0,A
INC R0
INC A
DJNZ R1,LOOP1
WR24C02: MOV SLA,#EEROM02
MOV SUBA,#00H
MOV NUMBYTE,#08H
LCALL IWRNBYTE
LCALL DELAY
NOP
NOP
RD24C02: MOV SLA,#EEROM02
MOV SUBA,#00H
MOV NUMBYTE,#08H
LCALL IRDNBYTE
LCALL DELAY
MOV DPTR,#7000H
MOV R0,#MRD
MOV R1,#08H
LOOP2: MOV A,@R0
MOVX @DPTR,A
INC DPTR
INC R0
DJNZ R1,LOOP2
NOP
SJMP $
;--------------------------------------------------------------------------------------------------------
;VI2C_ASM.ASM
;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。在标准80C51模式
;(12 Clock)下,对主频要求是不高于12MHz(1个机器周期1us);若Fosc>12MHz
;则要增加相应的NOP指令数。在使用本软件包时,请在你的程序的未尾加入
;INCLUDE (VI2C_ASM.ASM)即可。
;--------------------------------------------------------------------------------------------------------
;启动I2C总线子程序
DY: MOV R7,#1H
DJNZ R7,$
RET
DELAY: MOV R3,#10H
DELAY0: MOV R4,#0F0H
DJNZ R4,$
DJNZ R3,DELAY0
RET
;启动I2C总线子程序
START: SETB SDA
NOP
SETB SCL ;起始条件建立时间大于4.7us
LCALL DY
CLR SDA
LCALL DY
CLR SCL ;钳住总线,准备发数据
NOP
RET
;结束总线子程序
STOP: CLR SDA
NOP
SETB SCL ;发送结束条件的时钟信号
LCALL DY
SETB SDA ;结束总线
LCALL DY
RET
;发送应答信号子程序
MACK: CLR SDA ;将SDA置0
NOP
NOP
SETB SCL
LCALL DY
CLR SCL
NOP
NOP
RET
;发送非应答信号
MNACK: SETB SDA ;将SDA置1
NOP
NOP
SETB SCL
LCALL DY
CLR SCL
NOP
NOP
RET
; 检查应答位子程序
; 返回值,ACK=1时表示有应答
CACK: SETB SDA
NOP
NOP
SETB SCL
CLR ACK
NOP
NOP
MOV C,SDA
JC CEND
SETB ACK ;判断应答位
CEND: NOP
CLR SCL
NOP
RET
;发送字节子程序
;字节数据放入ACC
;每发送一字节要调用一次CACK子程序,取应答位
WRBYTE:; PUSH 00H
MOV R0,#08H
WLP: RLC A ;取数据位
JC WR1
SJMP WR0 ;判断数据位
WLP1: DJNZ R0,WLP
NOP
RET
WR1: SETB SDA ;发送1
NOP
SETB SCL
LCALL DY
CLR SCL
SJMP WLP1
WR0: CLR SDA ;发送0
NOP
SETB SCL
LCALL DY
CLR SCL
SJMP WLP1
; POP 00H
RET
;读取字节子程序
;读出的值在ACC
;每取一字节要发送一个应答/非应答信号
RDBYTE: ;PUSH 00H
MOV R0,#08H
RLP: SETB SDA
NOP
SETB SCL ;时钟线为高,接收数据位
NOP
NOP
MOV C,SDA ;读取数据位
MOV A,R2
CLR SCL ;将SCL拉低,时间大于4.7us
RLC A ;进行数据位的处理
MOV R2,A
NOP
NOP
NOP
DJNZ R0,RLP
;POP 00H ;未够8位,再来一次
RET
; 无子地址器件写字节数据
; 入口参数: 数据为ACC、器件从地址SLA
; 占用: A、R0、CY
IWRBYTE: ;PUSH 00H
PUSH ACC
IWBLOOP: LCALL START ;起动总线
MOV A,SLA
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETWRB ;无应答则跳转
POP ACC ;写数据
LCALL WRBYTE
LCALL CACK
LCALL STOP
RET
RETWRB: POP ACC
LCALL STOP
;POP 00H
RET
;无子地址器件读字节数据
;入口参数: 器件从地址SLA
;出口参数: 数据为ACC
;占用 A 、R0、R2 、CY
IRDBYTE:
LCALL START
MOV A,SLA ;发送器件从地址
INC A
LCALL WRBYTE
LCALL CACK
JNB ACK,RETRDB
LCALL RDBYTE ;进行读字节操作
LCALL MNACK ;发送非应信号
RETRDB: LCALL STOP ;结束总线
RET
;向器件指定子地址写N个数据
;入口参数: 器件从地址SLA、器件子地址SUBA 、发送数据缓冲区MTD、发送字节数NUMBYTE
; 占用: A 、R0 、R1 、R3 、CY
IWRNBYTE: PUSH 00H
PUSH 01H
PUSH 03H
MOV A,NUMBYTE
MOV R3,A
LCALL START ;起动总线
MOV A,SLA
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV A,SUBA ;指定子地址
LCALL WRBYTE
LCALL CACK
MOV R1,#MTD
WRDA: MOV A,@R1
LCALL WRBYTE ;开始写入数据
LCALL CACK
JNB ACK,IWRNBYTE
INC R1
DJNZ R3,WRDA ;判断写完没有
RETWRN: LCALL STOP
POP 03H
POP 01H
POP 00H
RET
;向器件指定子地址读取N个数据
;入口参数: 器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE
;出口参数: 接收数据缓冲区MTD
;占用:A、 R0、 R1、 R2、 R3、 CY
IRDNBYTE: ;PUSH 00H
;PUSH 01H
;PUSH 03H
MOV R3,NUMBYTE
LCALL START
MOV A,SLA
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETRDN
MOV A,SUBA ;指定子地址
LCALL WRBYTE
LCALL CACK
LCALL START ;重新起动总线
MOV A,SLA
INC A ;准备进行读操作
LCALL WRBYTE
LCALL CACK
JNB ACK,IRDNBYTE
MOV R1,#MRD
RDN1: LCALL RDBYTE ;读操作开始
MOV @R1,A
DJNZ R3,SACK
LCALL MNACK ;最后一字节发非应答位
RETRDN: LCALL STOP
; POP 03H
; POP 01H
;POP 00H ;并结束总线
RET
;********************************
SACK: LCALL MACK
INC R1
SJMP RDN1
RET
;*********************************************************************************************
; 请注意
;
;占用内部资源: R0,R1,R2,R3,ACC,Cy。
; 在你的程序里要做以下定义:
;使用前须定义变量: SLA 器件从地址 SUBA器件子地址 NUMBYTE读/写的字节数 ,位变量ACK
;使用前须定义常量: SDA SCL 总线位 MTD 发送数据缓冲区首址 MRD 接收数据缓冲区首址
;(ACK为调试/测试位,ACK为0时表示无器件应答)
;
;*************************
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -