📄 vi2c_24a.inc
字号:
;--------------------------------------------------------------------------------------------------------
; MCS-51单片机模拟I2C软件包(24系列EEPROM专用)
; 文件名:VI2C_24A.INC
; 功能说明:本模拟I2C软件包包含了I2C操作的底层子程序,使用前要定义
;好SCL和SDA。在标准8051模式(12 Clock)下,对主频要求是不高于12MHz(即1个
;机器周期1us);若Fosc>12MHz则要增加相应的NOP指令数。(总线时序符合I2C标
;准模式,100Kbit/S)
; 版本说明:本版本是针对24系列EEPROM专门设置的,用此软件包进行EEPR
;OM读写时,用户不必考虑页写问题,及16位存储器地址的问题。
; 更新时间:2002.06.05
;--------------------------------------------------------------------------------------------------------
;启动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字节数据(24系列EEPROM专用)
;入口参数: 器件从地址SLA、器件子地址SUBA 、发送数据缓冲区MTD、发送字节数NUMBYTE
;占用:A 、R0 、R1 、R2、R3 、CY
;说明:以8字节为1页的方式计算,防止页写的翻转问题。即你写入数据是不用考虑页写入问
; 题,即本子程序会帮你转页。本子程序是以8字节为一页进行换页,调用此子程序会
; 更改SUBA和[SUBA1]的值。
IWRNBYTE: MOV A,NUMBYTE
MOV R3,A
LCALL START ;起动总线
MOV A,SLA
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
$IF(SUBA16) ;若是使用16位存储地址,则发送高8位地址
MOV A,SUBA1 ;如24WC32、64、128、256就是16位存储地址
LCALL WRBYTE
LCALL CACK
$ENDIF
MOV A,SUBA ;指定子地址
LCALL WRBYTE
LCALL CACK
;开始发送数据
MOV R1,#MTD
WRDA: MOV A,@R1
LCALL WRBYTE ;开始写入数据
LCALL CACK
JNB ACK,IWRNBYTE
;发送完1字节后,马上判断是否页满,若是则结束总线,并等待写周期结束。
;然后重新启动总线,再次发送从地址,子地址,写数据。
INC SUBA ;子地址更新
$IF(SUBA16)
MOV A,SUBA
JNZ WRDA_L1
INC SUBA1 ;若是16位子地址,且SUBA有进位,则要对SUBA1进行更改
$ENDIF
WRDA_L1: MOV A,SUBA
ANL A,#0FH
JZ WRDA_L3 ;若已经到页首,重新进行页定位
CJNE A,#08H,WRDA_L4 ;若SUBA=08H(页首),重新进行页定位
WRDA_L3: LCALL STOP
MOV R2,#0 ;等待页写完成,延时10mS
DELAY10: NOP
ACALL DELAY40NOP
NOP
DJNZ R2,DELAY10
;页写完成,重新启动总线
LCALL START ;起动总线
MOV A,SLA
LCALL WRBYTE ;发送器件从地址
LCALL CACK
JNB ACK,RETWRN ;无应答则退出
$IF(SUBA16) ;若是使用16位存储地址,则发送高8位地址
MOV A,SUBA1 ;如24WC32、64、128、256就是16位存储地址
LCALL WRBYTE
LCALL CACK
$ENDIF
MOV A,SUBA ;指定子地址
LCALL WRBYTE
LCALL CACK
WRDA_L4: INC R1
DJNZ R3,WRDA ;判断写完没有
RETWRN: LCALL STOP
RET
;延时40uS
;NOP的机器码为00H
DELAY40NOP:
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H
RET
;向器件指定子地址读取N字节数据(24系列EEPROM专用)
;入口参数: 器件从地址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
$IF(SUBA16) ;若是使用16位存储地址,则发送高8位地址
MOV A,SUBA1 ;如24WC32、64、128、256就是16位存储地址
LCALL WRBYTE
LCALL CACK
$ENDIF
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。
; 在你的程序里要做以下定义:
; 1、定义变量: SLA 器件从地址 SUBA器件子地址 [SUBA1器件子地址低8位] NUMBYTE读/写的字
; 节数 ,位变量ACK
; 2、定义常量: SDA SCL 总线位 MTD 发送数据缓冲区首址 MRD 接收数据缓冲区首址
;
; (ACK为调试/测试位,ACK为0时表示无器件应答或总线出错)
;
; 在使用本软件包时,请在你的程序的未尾加入$INCLUDE (VI2C_24A.INC)即可。VI2C_24A.INC文件
;复制到IDE包含文件所要求的目录(如:工作目录或INC目录)
; 若没有定义SUBA16,则软件包是使用8位节子地址SUBA,若你定义了SUBA16则是使用16位的子地址,
;还要定义变量SUBA1,即使用24WC32、64、128、256时要这样定义$SET (SUBA16)
; 用户可以对"用户接口子程序"进行裁减,即把自已不使用的接口子程序删掉,以节省程序空间。
;**********************************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -