📄 i2c存储器读写实验.asm
字号:
;;; I2C存储器读写实验
;;; MCU:89S51 COLCK:11.0592MHZ
;;;
;;; 实验目的: 1. 通过实验了解I2C的工作原理和用软件模拟I2C总线的编程方法
;;; 2. 通过实验了解数据存入I2C E2PROM的过程,实现数据掉电保存.
;;; 实验内容:把数据存入E2PROM中的指定的地址,而后在把指定地址
;;; 的数据读出来比较,如相等表示数据读写正常,rxd1发光提示,反之没提示.
;;; 而后把读到的数据送入电脑显示
;;;
;;; ***********************************************************************
;;; 接线说明:
;;; J10(25x2双排插针)第6脚(SD0)和第18脚(CPU的P1.1)连
;;; J10(25x2双排插针)第8脚(SC0)和第316脚(CPU的P1.0)连
;;; 接上串口线,打开"串口监视软件",波特率设为19200
;;;***********************************************************************
rxd1 BIT P3.0
SCL BIT p1.0 ; SCL I2C总线位
SDA BIT p1.1 ;SDA I2C总线位
SLA DATA 37H ;SLA 器件从地址
SUBA DATA 38H ;SUBA器件子地址
MRD DATA 40H ;MRD 接收数据缓冲区首址
MTD DATA 48H ;MTD 发送数据缓冲区首址
ACK BIT 30H ;ACK为调试/测试位,ACK为0时表示无器件应答
NUMBYTE DATA 36H ;NUMBYTE读/写的字节数
ORG 0000H
AJMP MAIN
ORG 0080H
MAIN: ACALL A200MS
MOV R1,#04
MOV R0,#MTD
MOV A,#30h;00H
DELETE0: ;发送缓冲区赋值分别为00H-03H
MOV @R0,A
INC R0
INC A
DJNZ R1,DELETE0
;存储空间的首地址:B是高地址A 是低地址如把数据存到高于255地址的存储空间如288(120H)
;那B=01H,A=20H ,如把数据存到不高于255地址存储空间如28,那B=0H,A=14H
DELETE1: MOV A,#20H
MOV B,#00H
; I2C(24XX 存储器)
MOV SLA,#10100000B
MOV SUBA, A ;指定子地址
MOV A,B
RL A
ADD A,SLA
MOV SLA,A ;器件从地址
MOV NUMBYTE, #04h ;接收字节数NUMBYTE
nop
ACALL IWRNBYTE ;调用I2C写程序
ACALL A200MS ;
;;;;;;;;;;;
MOV R0,#MRD
MOV R2,#04H
CLRR: CLR A ;接受数据缓冲区清零
MOV @R0,A
INC R0
DJNZ R2,CLRR
;存储空间的首地址:B是高地址A 是低地址
KEYBJASM1: MOV A,#20H
MOV B,#00H
; 读数据 I2C(24XX 存储器)
MOV SLA,#10100000B
MOV SUBA, A ;指定子地址
MOV A,B
RL A
ADD A,SLA
MOV SLA,A ;器件从地址
MOV NUMBYTE, #04h ;接收字节数NUMBYTE
nop
LCALL IRDNBYTE ;向I2C(24XX)器件指定子地址读N个数据
;;; 数据比较
MOV R2,#04H ;赋要比较数据的个数
MOV R0,#MTD ;发送数据缓冲区首地址
MOV R1,#MRD ;接受数据缓冲区首地址MRD
BJMD1: MOV A,@R0
XRL A,@R1 ;两个数据比较(用异或来比较是否相等)
JNZ BJMD0 ;不相等就转BJMD0
INC R0 ;数据缓冲区首地址+1
INC R1
DJNZ R2,BJMD1 ;数据没比较完就继续
CLR rxd1 ;两组数据相等rxd1发光提示
; 串行口发送到电脑显示 波特率为19200.
; 串行口发送到电脑显示 波特率为19200.
RS232: MOV TMOD,#20H ;设定T1为定时方式2
MOV TH1,#0FDH ;定时初值
MOV TL1,#0FDH ;
MOV PCON,#80H ;波特率为19200
SETB TR1 ;;;;;启动定时器
MOV SCON,#50H ;串口方式1
MOV R0,#MRD ;#BLK1;;数据地址指针
MOV R7,#4H ;数据长度
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
AAA0: MOV A,@R0
ANL A,#0F0H
SWAP A
MOV DPTR,#CARDASCII
MOVC A,@A+DPTR ;把数据转换成ASCII显示
MOV SBUF,A ;发送一个数据
MOV A,@R0
ANL A,#0FH
AAA1: JBC TI,AAA2;;;
SJMP AAA1;;;;
AAA2: MOV DPTR,#CARDASCII
MOVC A,@A+DPTR ;把数据转换成ASCII显示
MOV SBUF,A ;发送一个数据
AAA3: JBC TI,AAA4;;;
SJMP AAA3;;;;
AAA4: MOV A,#16
MOV DPTR,#CARDASCII
MOVC A,@A+DPTR ;把数据转换成ASCII显示
MOV SBUF,A ;发送一个数据
AAA5: JBC TI,AAA6;;;
SJMP AAA5;;;;
AAA6: MOV A,#17
MOV DPTR,#CARDASCII
MOVC A,@A+DPTR ;把数据转换成ASCII显示
MOV SBUF,A ;发送一个数据
INC R0 ;数据地址指针加1
AAA7: JBC TI,AAA8;;;
SJMP AAA7;;;;
AAA8: DJNZ R7,AAA0
;;;;;;
jb p1.0,$
ajmp KEYBJASM1
AJMP $
BJMD0: SETB rxd1 ;两组数据不相等
AJMP RS232
A200MS: ;200MS延时
MOV R6,#00
A200MS1: MOV R7,#0EFH
A200MS2: NOP
DJNZ R7,A200MS2
DJNZ R6,A200MS1
RET
;;;;;;;;;
CARDASCII :DB 30H,31H,32H,33H,34H,35H,36H,37H,38H,39H,41H,42H,43H,44H,45H,46H,48H,20H
;HEX:00H,01H,02H,03H,04H,05H,06H,07H,08H,09H,0AH,0BH,0CH,0DH,0EH,0FH,0HH,空格.
;--------------------------------------------------------------------------------------------------------
;VI2C_ASM.ASM
;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。在标准80C51模式
;(12 Clock)下,对主频要求是不高于12MHz(1个机器周期1us);若Fosc>12MHz
;则要增加相应的NOP指令数。在使用本软件包时,请在你的程序的未尾加入
;$INCLUDE (VI2C_ASM.ASM)即可。
;--------------------------------------------------------------------------------------------------------
;启动I2C总线子程序
START: SETB SDA
NOP
SETB SCL ;起始条件建立时间大于4.7us
NOP
NOP
NOP
NOP
NOP
CLR SDA
NOP ;起始条件锁定时大于4us
NOP
NOP
NOP
NOP
CLR SCL ;钳住总线,准备发数据
NOP
RET
;结束总线子程序
STOP: CLR SDA
NOP
SETB SCL ;发送结束条件的时钟信号
NOP ;结束总线时间大于4us
NOP
NOP
NOP
NOP
SETB SDA ;结束总线
NOP ;保证一个终止信号和起始信号的空闲时间大于4.7us
NOP
NOP
NOP
RET
;发送应答信号子程序
MACK: CLR SDA ;将SDA置0
NOP
NOP
SETB SCL
NOP ;保持数据时间,即SCL为高时间大于4.7us
NOP
NOP
NOP
NOP
CLR SCL
NOP
NOP
RET
;发送非应答信号
MNACK: SETB SDA ;将SDA置1
NOP
NOP
SETB SCL
NOP
NOP ;保持数据时间,即SCL为高时间大于4.7us
NOP
NOP
NOP
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: MOV R0,#08H
WLP: RLC A ;取数据位
JC WR1
SJMP WR0 ;判断数据位
WLP1: DJNZ R0,WLP
NOP
RET
WR1: SETB SDA ;发送1
NOP
SETB SCL
NOP
NOP
NOP
NOP
NOP
CLR SCL
SJMP WLP1
WR0: CLR SDA ;发送0
NOP
SETB SCL
NOP
NOP
NOP
NOP
NOP
CLR SCL
SJMP WLP1
;读取字节子程序
;读出的值在ACC
;每取一字节要发送一个应答/非应答信号
RDBYTE: 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 ;未够8位,再来一次
RET
; 无子地址器件写字节数据
; 入口参数: 数据为ACC、器件从地址SLA
; 占用: A、R0、CY
IWRBYTE: 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
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: 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
RET
;向器件指定子地址读取N个数据
;入口参数: 器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE
;出口参数: 接收数据缓冲区MTD
;占用:A、 R0、 R1、 R2、 R3、 CY
IRDNBYTE: 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 ;并结束总线
RET
SACK: LCALL MACK
INC R1
SJMP RDN1
;***************************************************************************************
; 请注意 *
; *
;占用内部资源: 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 + -