📄 i2ctoser.asm
字号:
;;;;;;;;MCU晶振33.177MHZ,I2C速度设定为40~100KHZ (每个周期I2C包含82个单周期指令)
ORG 0000H
AJMP MAIN
ORG 0030H
MAIN:
MOV SP,#60H
MOV PMR,#01011011B ;SETB DME0 ;设置允许访问片上SRAM
;;;开启定时器2为串口通讯的波特率发生器
SETB RCLK
SETB TCLK
MOV TH2,#0FFH
MOV TL2,#0F7H ;#93H ;设置串口通讯的波特率为115200bps(baud=fosc/2*16*[65536-(RCAP2H、RCAP2L)])
MOV RCAP2H,#0FFH
MOV RCAP2L,#0F7H
SETB TR2
MOV SCON,#50H ;置串行接口工作于方式1
;;;;;;;;;;;;;;;;;;;;;
ACK EQU 01H
SCL EQU P3.6
SDA EQU P3.7
I2CRTD DATA 30H
I2CRRD DATA 31H
I2CADDR DATA 32H
I2CADDRH DATA 33H
I2CADDRL DATA 34H
I2CNUMBYTE DATA 35H
MOV I2CRTD,#14H
MOV I2CRRD,#0D4H
;MOV I2CADDR,#0A0H
MOV I2CADDRH,#04H
MOV I2CADDRL,#05H
SETB RS1
SETB RS0
MOV R0,#19H
RRDD:
LCALL I2CRDPG
MOV A,I2CRRD
CLR TI
MOV SBUF,A
CTI:JNB TI,CTI
MOV A,I2CADDRL
INC A
MOV I2CADDRL,A
SETB RS1
SETB RS0
DJNZ R0,RRDD
AJMP MAIN
I2CRDPG: ;根据定义的16位地址和数据发送、接收缓冲区,进行单次单字节的数据传输
SETB RS1
CLR RS0
MOV I2CNUMBYTE,#01H
MOV R3,I2CNUMBYTE
LCALL START
MOV A,I2CADDR
LCALL WRBYTE ;发送器件从地址(器件物理地址)
LCALL CACK
JNB ACK,RETRDN
MOV A,I2CADDRH ;指定子地址高8位
LCALL WRBYTE
LCALL CACK
JNB ACK,RETRDN
MOV A,I2CADDRL ;指定子地址低8位
LCALL WRBYTE
LCALL CACK
LCALL START ;重新启动总线
MOV A,I2CADDR
INC A ;准备进行读操作
LCALL WRBYTE
LCALL CACK
JB ACK,I2CRDPG ;没有确认信号,则重新尝试读一次
MOV R1,#I2CRTD
RDN1:
LCALL RDBYTE ;读操作开始
MOV @R1,A
DJNZ R3,SACK
LCALL MNACK ;最后一字节发非应答位
RETRDN:
LCALL STOP
CLR RS1
CLR RS0 ;寄存器还原为寄存器0
RET
SACK:
LCALL MACK
INC R1
SJMP RDN1
LCALL I2CSOLOWR
AJMP MAIN
;;启动I2C总线
START:
SETB SDA
NOP
NOP
NOP
SETB SCL ;起始条件建立时间大于××s
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
CLR SDA ;起始条件锁定时间大于××s
NOP
NOP
NOP
NOP
NOP
NOP
NOP
CLR SCL ;钳住总线,准备发数据
NOP
NOP
RET
;结束总线子程序
STOP:
CLR SDA
NOP
NOP
NOP
SETB SCL ;发送结束条件的时钟信号
NOP ;结束总线时间大于××s
NOP
NOP
NOP
NOP
NOP
SETB SDA ;结束总线
NOP ;保证一个中止信号和起始信号的空闲时间对于××s
NOP
NOP
NOP
RET
;发送应答信号子程序
MACK:
CLR SDA ;将SDA置0
NOP
NOP
SETB SCL
NOP ;保持数据时间,即SCL为高电平时间大于**us
NOP
NOP
NOP
NOP
CLR SCL
NOP
NOP
RET
;发送非应答信号
MNACK:
SETB SDA ;将SDA置1
NOP
NOP
SETB SCL
NOP ;保持数据时间,即SCL为高电平时间大于**us
NOP
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:
SETB RS1
CLR RS0
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:
SETB RS1
CLR RS0
MOV R0,#08H
RLP:
SETB SDA
NOP
SETB SCL ;时钟线为高,接收数据位
NOP
NOP
MOV C,SDA ;读取数据位
MOV A,R2
CLR SCL ;将SCL拉低,时间大于**us
RLC A ;进行数据位的处理
MOV R2,A
NOP
NOP
NOP
DJNZ R0,RLP ;未够8位再来一次
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2CSOLOWR: ;根据定义的16位地址和数据发送、接收缓冲区,进行单次单字节的数据传输
MOV I2CNUMBYTE,#01H
MOV A,I2CNUMBYTE
SETB RS1
CLR RS0
MOV R3,A
LCALL START ;启动总线
MOV A,I2CADDR
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV A,I2CADDRH
LCALL WRBYTE
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV A,I2CADDRL
LCALL WRBYTE
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV R1,#I2CRRD
WRDA:
MOV A,@R1
LCALL WRBYTE ;开始写入数据
LCALL CACK
JB ACK,I2CSOLOWR ;无应答则重新写一遍
INC R1
DJNZ R3,WRDA ;判断写完没有
RETWRN:
LCALL STOP
CLR RS1
CLR RS0 ;还原为寄存器0
RET
END
;向器件指定子地址读1个数据
;入口参数:器件从地址I2CADDR,器件子地址I2CADDRH、I2CADDRL,发送数据缓冲区I2CTD,发送字节数I2CNUMBYTE。
;占用:A,R0,R1,R2,R3,CY
I2CRDPG: ;根据定义的16位地址和数据发送、接收缓冲区,进行单次单字节的数据传输
SETB RS1
CLR RS0
MOV I2CNUMBYTE,#01H
MOV R3,I2CNUMBYTE
LCALL START
MOV A,I2CADDR
LCALL WRBYTE ;发送器件从地址(器件物理地址)
LCALL CACK
JNB ACK,RETRDN
MOV A,I2CADDRH ;指定子地址高8位
LCALL WRBYTE
LCALL CACK
JNB ACK,RETRDN
MOV A,I2CADDRL ;指定子地址低8位
LCALL WRBYTE
LCALL CACK
LCALL START ;重新启动总线
MOV A,I2CADDR
INC A ;准备进行读操作
LCALL WRBYTE
LCALL CACK
JB ACK,I2CRDPG ;没有确认信号,则重新尝试读一次
MOV R1,#I2CRTD
RDN1:
LCALL RDBYTE ;读操作开始
MOV @R1,A
DJNZ R3,SACK
LCALL MNACK ;最后一字节发非应答位
RETRDN:
LCALL STOP
CLR RS1
CLR RS0 ;寄存器还原为寄存器0
RET
SACK:
LCALL MACK
INC R1
SJMP RDN1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I2CSOLOWR: ;根据定义的16位地址和数据发送、接收缓冲区,进行单次单字节的数据传输
MOV I2CNUMBYTE,#01H
MOV A,I2CNUMBYTE
SETB RS1
CLR RS0
MOV R3,A
LCALL START ;启动总线
MOV A,I2CADDR
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV A,I2CADDRH
LCALL WRBYTE
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV A,I2CADDRL
LCALL WRBYTE
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
MOV R1,#I2CRRD
WRDA:
MOV A,@R1
LCALL WRBYTE ;开始写入数据
LCALL CACK
JB ACK,I2CSOLOWR ;无应答则重新写一遍
INC R1
DJNZ R3,WRDA ;判断写完没有
RETWRN:
LCALL STOP
CLR RS1
CLR RS0 ;还原为寄存器0
RET
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -