📄 24c04
字号:
;****************************************************************
;* ★★★ 24C04存储器读写实验 ★★★ *
;* (电子驿站单片机实验板、开发板配套例程,程序转载请著明出处。) *
;* E-mail: support@ourmpu.com QQ留言:451338254 476485321 *
;* 编程:ourmpu http://www.ourmpu.com/ 更多例程请登陆网站 *
;****************************************************************
;* 每次上电24C04的00H单元值自动加1,其值从00H~FFH,即从0~255 *
;* 上电次数值显示在数码管中,数码管第1位和第2位显示十六进制值 *
;* 数码管第4~6位显示的是计数值,即对应的BCD值0~255 *
;* 可以直观地看到十六进制和BCD值的对应关系 *
;* 试验时按压实验板电源开关,关闭实验板电源,再次开启电源时,数码管显示值加1 *
;* 按压复位按钮可以模拟断电过程,计数值也自动加1 *
;* 写入24C04的数据断电能够长期保存,适合用来存储系统的一些参数 *
;****************************************************************
ORG 0000H
AJMP START
ORG 0033H
START:
SDA BIT P1.1
SCL BIT P1.0
ACK BIT 00H ;24C04应答标志位
I2C_ERR BIT 01H ;I2C读写出错标志
AT24C04 EQU 0A0H ;24C04硬件地址(低256字节)
SLA EQU 30H ;器件硬件地址
SUBA EQU 31H ;器件字节地址
DANUM EQU 32H ;
NUMBYTE EQU 33H ;读/写的字节数
MTD EQU 34H ;待发送数据缓冲区指针,MTD里存储数据块首址
MRD EQU 35H ;待接收数据缓冲区指针,MRD里存储数据块首址
DIS1 EQU 36H ;
DIS2 EQU 37H
DIS3 EQU 38H
DIS4 EQU 39H
DIS5 EQU 3AH
DIS6 EQU 3BH
MOV SP,#50H
MOV P0,#0FFH
MOV P1,#0FFH
MOV P2,#0FFH
MOV P3,#0FFH
;--------- 读1字节,读出的数据在DANUM中 ----------
READ: MOV SLA,#AT24C04 ;24C04硬件地址
MOV SUBA,#00H ;24C04的00H单元
MOV MRD,#DANUM ;读出的数据存入单元
MOV NUMBYTE,#1 ;读出1位数据
ACALL IRDNBYTE ;读数操作
MOV A,DANUM ;十六进制显示第一位
SWAP A
ANL A,#00001111B
MOV DIS1,A
MOV A,DANUM ;十六进制显示第二位
ANL A,#00001111B
MOV DIS2,A
MOV A,DANUM
MOV B,#100 ;分离出百位
DIV AB
MOV DIS4,A ;上电次数百位
MOV A,#10
XCH A,B
DIV AB
MOV DIS6,B ;上电次数十位
MOV DIS5,A ;上电次数个位
MOV A,DANUM
INC A
MOV DANUM,A
;--------- 写1字节,待写入的数据在DANUM中 ----------
WRITE: MOV SLA,#AT24C04 ;24C04硬件地址(低256字节)
MOV SUBA,#00H ;数据存入24C04的00H(起始单元)
MOV MTD,#DANUM ;待存数据块首址指针
MOV NUMBYTE,#1 ;写入1位数据
ACALL IWRNBYTE ;把数据存入24C04
ACALL YS18ms ;延时18ms,等待24C04写周期结束
MAIN: MOV A,DIS1
MOV DPTR,#SGTB
MOVC A,@A+DPTR
MOV P0,A
SETB P2.0
SETB P2.1
SETB P2.2
SETB P2.3
SETB P2.4
CLR P2.5
ACALL DELAY
MOV A,DIS2
MOV DPTR,#SGTB
MOVC A,@A+DPTR
MOV P0,A
SETB P2.0
SETB P2.1
SETB P2.2
SETB P2.3
CLR P2.4
SETB P2.5
ACALL DELAY
MOV A,DIS4
MOV DPTR,#SGTB
MOVC A,@A+DPTR
CJNE A,#0C0H,NEXT
MOV A,#0FFH
NEXT: MOV P0,A
SETB P2.0
SETB P2.1
CLR P2.2
SETB P2.3
SETB P2.4
SETB P2.5
ACALL DELAY
MOV A,DIS5
MOV DPTR,#SGTB
MOVC A,@A+DPTR
MOV B,A
MOV A,DIS4
CJNE A,#00H,NEXT1
MOV A,B
CJNE A,#0C0H,NEXT2
MOV A,#0FFH
AJMP NEXT2
NEXT1: MOV A,B
NEXT2: MOV P0,A
SETB P2.0
CLR P2.1
SETB P2.2
SETB P2.3
SETB P2.4
SETB P2.5
ACALL DELAY
MOV A,DIS6
MOV DPTR,#SGTB
MOVC A,@A+DPTR
MOV P0,A
CLR P2.0
SETB P2.1
SETB P2.2
SETB P2.3
SETB P2.4
SETB P2.5
ACALL DELAY
AJMP MAIN
;-----------------------------------------------------------
;单字节十六进制整数转换成单字节BCD码整数
;入口条件:待转换的单字节十六进制整数在累加器A中。
;出口信息:转换后的BCD码整数(十位和个位)仍在累加器A中,百位在R3中。
;影响资源:PSW、A、B、R3 堆栈需求: 2字节
HBCD: MOV B,#100 ;分离出百位,存放在R3中
DIV AB
MOV DIS3,A
MOV A,#10 ;余数继续分离十位和个位
XCH A,B
DIV AB
MOV DIS4,B
MOV DIS5,A
; SWAP A
; ORL A,B ;将十位和个位拼装成BCD码
RET
;********** I2C总线24C04读写程序 ***********
;启动I2C总线子程序
STA: SETB SDA
NOP
SETB SCL ;起始条件建立时间大于4.7us
JNB SDA,X10 ;SDA=\1则有错
JNB SCL,X10 ;SCL=\1则有错
NOP
CLR SDA
NOP ;起始条件锁定时大于4us
NOP
NOP
NOP
NOP
CLR SCL ;钳住总线,准备发数据
CLR I2C_ERR ;总线正确,清出错标志
AJMP X11
X10: SETB I2C_ERR ;总线出错,置出错标志
X11: 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
;向器件指定子地址写N个数据
;入口参数: 器件从地址SLA、器件子地址SUBA 、发送数据缓冲区MTD、发送字节数NUMBYTE
; 占用: A 、R0 、R1 、R3 、CY
IWRNBYTE:
CLR EA ;关闭中断
MOV A,NUMBYTE
MOV R3,A
ACALL STA ;起动总线
MOV A,SLA
ACALL WRBYTE ;发送器件从地址
ACALL CACK
JNB ACK,WRNERR ;无应答则退出
MOV A,SUBA ;指定子地址
ACALL WRBYTE
ACALL CACK
MOV R1,MTD
WRDA: MOV A,@R1
ACALL WRBYTE ;开始写入数据
ACALL CACK
JNB ACK,IWRNBYTE
INC R1
DJNZ R3,WRDA ;判断写完没有
SJMP RETWRN ;正确写入退出
WRNERR: SETB I2C_ERR ;置出错标志
RETWRN: ACALL STOP
SETB EA ;开中断
RET
;向器件指定子地址读取N个数据
;入口参数: 器件从地址SLA、器件子地址SUBA、接收字节数NUMBYTE
;出口参数: 接收数据缓冲区MRD
;占用:A、 R0、 R1、 R2、 R3、 CY
IRDNBYTE:
CLR EA ;关中断
MOV R3,NUMBYTE
ACALL STA
MOV A,SLA
ACALL WRBYTE ;发送器件从地址
ACALL CACK
JNB ACK,RDNERR
MOV A,SUBA ;指定子地址
ACALL WRBYTE
ACALL CACK
ACALL STA ;重新起动总线
MOV A,SLA
INC A ;准备进行读操作
ACALL WRBYTE
ACALL CACK
JNB ACK,IRDNBYTE
MOV R1,MRD
RDN1: ACALL RDBYTE ;读操作开始
MOV @R1,A
DJNZ R3,SACK
ACALL MNACK ;最后一字节发非应答位
SJMP RETRDN ;读正常退出
RDNERR: SETB I2C_ERR ;置出错标志
RETRDN: ACALL STOP ;并结束总线
SETB EA ;开中断
RET
SACK: ACALL MACK
INC R1
SJMP RDN1
;************* 8位共阳数码管字型表 *****************
SGTB: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
DB 88H,83H,0C6H,0A1H,86H,8EH,89H,0A3H,8CH,0C8H
;******** 延时子程序 ********
DELAY: MOV R1,#10
Y1: MOV R2,#100
DJNZ R2,$
DJNZ R1,Y1
RET
;------------- 延时18ms -------------
YS18ms: MOV R6,#40 ;准备延时18888us
AJMP Y3 ;开始延时
YS4722U:MOV R6,#10 ;延时4722微秒
Y3: MOV R5,#216 ;[1]
DJNZ R5,$ ;[2]
DJNZ R6,Y3 ;[2]
RET ;[1]
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -