AT89S8253片内EEPROM字节读、字节写、页读、页写驱动代码、注意事项及注释
在编写AT89S8253片内EEPROM读写驱动程序时,要特别注意数据读写指令MOVX;
当EECON寄存器的EEMEN位置位时,MOVX访问EEPROM;
当EECON寄存器的EEMEN位清零时,MOVX访问外部RAM;
一般情况下,我们定义的用来写入EEPROM的数据或保存EEPROM读取的数据都用外部RAM;代码具体分析如下:
C语言页写入代码:
unsigned char W_EEPROM_PAGE(unsigned int paddr, unsigned char *pdat)
{
unsigned char temp;
EECON |= EEMEN;
EECON |= EEMWE;
...
For(temp = 0; temp < 32; temp++)
XBYTE[paddr+temp] = pdat[temp];
...
EECON &= ~EEMEN;
EECON &= ~EEMWE;
}
此代码逻辑清晰,容易理解,可是编译器没有那么智能;编译器知道pdat指针指向的数据在外部RAM中,用MOVX指令可以读取;编译器也知道paddr表示的是要写入EEPROM的地址,页用MOVX指令访问;于是,编译器就将代码翻译成如下汇编指令:
ORL EECON,#08H
ORL EECON,#010H
...
?C0045:
; XBYTE[paddr+temp]= pdat[temp]; //将前31字节写入页写缓冲区
; SOURCE LINE # 242
MOV DPTR,#pdat?663
MOVX A,@DPTR
MOV R3,A
INC DPTR
MOVX A,@DPTR
MOV R2,A
INC DPTR
MOVX A,@DPTR
MOV R1,A
MOV DPL,R7
MOV DPH,#00H
LCALL?C?CLDOPTR
MOV R6,A
MOV A,R7
MOV R5,A
MOV DPTR,#paddr?662+01H
MOVX A,@DPTR
ADD A,R5
MOV R5,A
MOV DPTR,#paddr?662
MOVX A,@DPTR
ADDC A,#00H
MOV DPL,R5
MOV DPH,A
MOV A,R6
MOVX @DPTR,A
INC R7
MOV A,R7
CJNE A,#01FH,?C0045
...
ANL EECON,#0E7H
红色部分代码是读取pdat数组里的数据,存入R6中,蓝色部分代码是将R6中的数据写入paddr表示的EEPROM的地址中去;乍一看,完全符合逻辑,可是MOVX指令的访问目标没有考虑,在EEPROM使能情况下,MOVX访问的一直是EEPROM,在上面的代码中,EEPROM始终保持使能状态,而我们的待写入数据,是保存在外部RAM中的,始终没有被读取;这样的代码,其实是将EEPROM中的某页数据复制另一页,而没有将按照我们的意愿将外部RAM中的数据写入EEPROM;因此,编译器曲解了我们的C语言代码。
到目前为止,直接编写汇编成了唯一可以解决此BUG的方法,于是乎,我们可以修改编译器汇编好的代码,在要读取外部RAM数据时,关闭EEPROM使能,获取数据,在准备写入EEPROM时,再打开EEPROM使能;于是乎,我们在频繁的打开关闭EEPROM使能;于是乎,EEPROM就不正常工作了,写入失败;
我们可以参考ATMEL官方给出的例程,编写汇编代码;例程中,写入数据是从宝贵的DATA段获取的,使用MOV指令就可以轻松得到,不用考虑MOVX访问区域的限制。
至于此,我们只有拿出32字节(EEPROM一页数据大小)宝贵的DATA段空间,用于缓存待写入数据和读出数据,才能实现正确的数据读写,实现代码如下:
;定义全局共享数据读写缓冲区(32字节)
RSEG ?DT?AT89S8253_EEPROM_drv
buff: DS 32
RSEG ?C_INITSEG
DB020H
DB020H
DBbuff
DB000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H
...
; unsigned char W_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
RSEG ?PR?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv
_W_EEPROM_PAGE:
USING0
;将待写入数据从XDATA段转储到DATA段缓冲区
MOV R4, #0H
MOV DPH, R2
MOV DPL, R1
w_p_dat_read:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOVX A, @DPTR
MOV @R0, A
INC DPTR
INC R4
CJNE R4, #020H, w_p_dat_read
;使能EEPROM
ORL EECON,#018H
;检查电压是否达到写EEPROM要求
MOV A,EECON
ANL A,#02H
MOV r0,A
jzw_p_ERROR
;等待EEPROM状态转为闲
w_p_rdy1:
MOV A,EECON
ANL A,#02H
MOV r0,A
jzw_p_rdy1
;打开页写缓冲区
ORL EECON,#020H
;向页写缓冲区中写入一页前31字节
MOVR4, #0H
MOV DPL,R7
MOV DPH,R6
w_p_buff:
MOVA,#LOW(buff)
ADDA, R4
MOVR0, A
MOVA, @R0
MOVX @DPTR,A
INCDPTR
INCR4
CJNER4, #01FH,w_p_buff
;关闭页写缓冲区
ANL EECON,#0DFH
;写入一页的最后一个数据,启动页写周期
MOVA,#LOW(buff)
ADDA, R4
MOVR0, A
MOVA, @R0
MOVX @DPTR,A
;等待硬件响应页写
w_p_busy:
MOV A,EECON
ANL A,#02H
MOV r5,A
jnzw_p_busy
;等待写入完成
w_p_rdy2:
MOV A,EECON
ANL A,#02H
MOV r5,A
jzw_p_rdy2
;从DATA缓冲区读取写入的最后一个字节,存于R5中
MOVA, @R0
MOVR5, A
;将写入EEPROM的最后一个字节从EEPROM中读取出来,暂存于累加器A中
MOVX A, @DPTR
;用相减后零标志位来判断写入是否正确
SUBBA, R5
JNZw_p_ERROR
;写入成功,准备返回1,表示成功
MOV R7,#01H
JMPw_p_complete
;写入失败,准备返回0,表示失败
w_p_ERROR:
MOVR7, #0H
;页写完成,关闭EEPROM使能
w_p_complete:
ANL EECON,#0E7H
; } ; SOURCE LINE # 66
?C0004:
RET
; END OF _W_EEPROM_PAGE
以下为完整代码,包括字节读、字节写、页读、页写四个部分
$NOMOD51
NAME AT89S8253_EEPROM_drv
EA BIT 0A8H.7
EECON DATA 96H ; watchdog and memory control register
EEMEN EQU 00001000B ; EEPROM access enable bit
EEMWE EQU 00010000B ; EEPROM write enable bit
EELD EQU 00100000B ; EEPROM page load enable bit
WRTINH EQU 00000001B ; EEPROM WRTINHbit
RDY EQU 00000010B ; EEPROM RDY/BSYbit
?PR?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?PR?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?PR?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?PR?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT CODE
?XD?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv SEGMENT XDATA OVERLAYABLE
?C_INITSEG SEGMENT CODE
?DT?AT89S8253_EEPROM_drv SEGMENT DATA
PUBLIC buff
PUBLIC _W_EEPROM_PAGE
PUBLIC _W_EEPROM_BYTE
PUBLIC _R_EEPROM_PAGE
PUBLIC _R_EEPROM_BYTE
RSEG ?XD?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv
?_W_EEPROM_PAGE?BYTE:
paddr?345: DS 2
ORG 2
pdat?346: DS 3
RSEG ?XD?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv
?_R_EEPROM_BYTE?BYTE:
addr?040: DS 2
RSEG ?XD?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv
?_W_EEPROM_BYTE?BYTE:
addr?243: DS 2
ORG 2
dat?244: DS 1
RSEG ?XD?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv
?_R_EEPROM_PAGE?BYTE:
paddr?141: DS 2
ORG 2
pdat?142: DS 3
RSEG ?DT?AT89S8253_EEPROM_drv
buff: DS 32
RSEG ?C_INITSEG
DB 020H
DB 020H
DB buff
DB 000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H,000H,000H,000H,000H,000H,000H,000H,000H,000H
DB 000H
; /********************************************************************
; * 文件名:AT89S8253_EEPROM_drv_V0.6.c
; * 文件内容:AT89S8253 EEPROM字节写,字节读代码及相关测试代码
; * 创作人: 付伟龙
; * 创作时间:2013年07月11日
; * 修改时间:2013年07月20日
; * 修改内容:修改页写页读代码,修改测试代码,此版本代码能正确运行,读写EEPROM
; * 版本: v1.0
; ********************************************************************/
;
;
; unsigned char data buff[32] = {0};
;
; /*******************************************************************
; * 函数原型:unsigned char R_EEPROM_BYTE(unsigned int addr)
; * 函数功能:EEPROM字节读函数
; * 输入参数: unsigned int addr 读基地址
; * 输出参数: 无
; * 返回值: 读取到的数据
; *******************************************************************/
; unsigned char R_EEPROM_BYTE(unsigned int addr)//读一地址,返回所读值
RSEG ?PR?_R_EEPROM_BYTE?AT89S8253_EEPROM_drv
_R_EEPROM_BYTE:
USING 0
; SOURCE LINE # 21
; MOV DPTR,#addr?040
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; {
; SOURCE LINE # 22
orl EECON, #EEMEN ; enable EEPROM accesses ]
r_b_rdy:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz r_b_rdy
mov DPH, R6
mov DPL, R7
movx A, @dptr ; read EEPROM
xrl EECON, #EEMEN ; disable EEPROM accesses
; SOURCE LINE # 23
MOV R7,A
; }
; SOURCE LINE # 24
?C0001:
RET
; END OF _R_EEPROM_BYTE
;
; /*******************************************************************
; * 函数原型:void R_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
; * 函数功能:EEPROM页读函数
; * 输入参数: unsigned int paddr 读基地址
; * unsigned char * pdat 数据保存指针
; * 输出参数: pdat 读取数据保存地址
; * 返回值: 无
; *******************************************************************/
; void R_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
RSEG ?PR?_R_EEPROM_PAGE?AT89S8253_EEPROM_drv
_R_EEPROM_PAGE:
; SOURCE LINE # 34
; MOV DPTR,#paddr?141
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; INC DPTR
; MOV A,R3
; MOVX @DPTR,A
; INC DPTR
; MOV A,R2
; MOVX @DPTR,A
; INC DPTR
; MOV A,R1
; MOVX @DPTR,A
; {
orl EECON, #EEMEN
r_p_rdy:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz r_p_rdy
mov r4, #0h
mov DPH, R6
mov DPL, R7
r_p_next:
movx A, @dptr ; read EEPROM
mov r5, A
MOV A,#LOW (buff)
ADD A, R4
MOV R0, A
MOV @R0, AR5
INC DPTR
INC R4
CJNE R4, #020H, r_p_next
ANL EECON,#0F7H
MOV R4, #0H
MOV DPH, R2
MOV DPL, R1
r_p_save:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOV A, @R0
MOVX @DPTR, A
INC DPTR
INC R4
CJNE R4, #020H, r_p_save
; }
; SOURCE LINE # 37
RET
; END OF _R_EEPROM_PAGE
;
; /*******************************************************************
; * 函数原型:unsigned char W_EEPROM_BYTE(unsigned int addr ,unsigned char dat)
; * 函数功能:EEPROM字节写函数
; * 输入参数: unsigned int addr 写基地址
; * unsigned char dat 待写入数据
; * 输出参数: 无
; * 返回值: 1 写入成功
; * FALSE 写入失败
; *******************************************************************/
; unsigned char W_EEPROM_BYTE(unsigned int addr ,unsigned char dat)
RSEG ?PR?_W_EEPROM_BYTE?AT89S8253_EEPROM_drv
_W_EEPROM_BYTE:
USING 0
; SOURCE LINE # 48
; MOV DPTR,#addr?243
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; INC DPTR
; MOV A,R5
; MOVX @DPTR,A
; {
ORL EECON,#018H
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_b_ERROR
w_b_rdy1:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_b_rdy1
MOV DPL,R7
MOV DPH,R6
MOV A,R5
MOVX @DPTR,A
w_b_busy:
MOV A,EECON
ANL A,#02H
MOV r0,A
jnz w_b_busy
w_b_rdy2:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_b_rdy2
MOVX A, @DPTR
SUBB A, R5
JNZ w_b_ERROR
MOV R7,#01H
JMP w_b_complete
w_b_ERROR:
MOV R7, #0H
w_b_complete:
ANL EECON,#0E7H
; }
; SOURCE LINE # 51
?C0003:
RET
; END OF _W_EEPROM_BYTE
;
; /*******************************************************************
; * 函数原型:W_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
; * 函数功能:EEPROM页写函数
; * 输入参数: unsigned int paddr 写基地址(必须是页大小的整数倍,
; * 若不是整数倍,写入此地址所在页)
; * unsigned char * pdat 待写入数据指针
; * 输出参数: 无
; * 返回值: 1 写入成功
; * FALSE 写入失败
; *******************************************************************/
; unsigned char W_EEPROM_PAGE(unsigned int paddr, unsigned char * pdat)
RSEG ?PR?_W_EEPROM_PAGE?AT89S8253_EEPROM_drv
_W_EEPROM_PAGE:
USING 0
; SOURCE LINE # 63
; MOV DPTR,#paddr?345
; MOV A,R6
; MOVX @DPTR,A
; INC DPTR
; MOV A,R7
; MOVX @DPTR,A
; INC DPTR
; MOV A,R3
; MOVX @DPTR,A
; INC DPTR
; MOV A,R2
; MOVX @DPTR,A
; INC DPTR
; MOV A,R1
; MOVX @DPTR,A
; {
MOV R4, #0H
MOV DPH, R2
MOV DPL, R1
w_p_dat_read:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOVX A, @DPTR
MOV @R0, A
INC DPTR
INC R4
CJNE R4, #020H, w_p_dat_read
ORL EECON,#018H
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_p_ERROR
w_p_rdy1:
MOV A,EECON
ANL A,#02H
MOV r0,A
jz w_p_rdy1
ORL EECON,#020H
MOV R4, #0H
MOV DPL,R7
MOV DPH,R6
w_p_buff:
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOV A, @R0
MOVX @DPTR,A
INC DPTR
INC R4
CJNE R4, #01FH,w_p_buff
ANL EECON,#0DFH
MOV A,#LOW(buff)
ADD A, R4
MOV R0, A
MOV A, @R0
MOVX @DPTR,A
w_p_busy:
MOV A,EECON
ANL A,#02H
MOV r5,A
jnz w_p_busy
w_p_rdy2:
MOV A,EECON
ANL A,#02H
MOV r5,A
jz w_p_rdy2
MOV A, @R0
MOV R5, A
MOVX A, @DPTR
SUBB A, R5
JNZ w_p_ERROR
MOV R7,#01H
JMP w_p_complete
w_p_ERROR:
MOV R7, #0H
w_p_complete:
ANL EECON,#0E7H
; } ; SOURCE LINE # 66
?C0004:
RET
; END OF _W_EEPROM_PAGE
END
AT89S8253片内EEPROM字节读、字节写、页读、页写驱动代码、注意事项及注释相关推荐
- python中指定变量为1byte_Python读字节某一位的值,设置某一位的值,二进制位操作...
Python读字节某一位的值,设置某一位的值,二进制位操作 ??在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...
- 在Java里怎将字节数转换为我们可以读懂的格式?
问题:在Java里怎将字节数转换为我们可以读懂的格式? 在Java里怎将字节数转换为我们可以读懂的格式 像1024应该变成"1 Kb",而1024*1024应该变成"1 ...
- python获取二进制bit位_Python读字节某一位的值,设置某一位的值,二进制位操作...
Python读字节某一位的值,设置某一位的值,二进制位操作 在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fals ...
- 《STM32从零开始学习历程》——I2C向EEPROM写入一字节数据(I2C硬件)
<STM32从零开始学习历程>@EnzoReventon I2C向EEPROM写入一字节数据(I2C硬件) 相关链接: I2C物理层介绍 I2C协议层介绍 I2C固件库介绍 STM32的I ...
- Python读字节某一位的值,设置某一位的值,二进制位操作
Python读字节某一位的值,设置某一位的值,二进制位操作 在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...
- python写文件读文件-python--文件流读写
在讲述fileinput模块之前,首先说一下python内置的文件API-open()函数以及与其相关的函数. 我这里主要讲讲其中四个比较重要和常用的方法,更多的方法,可以参考:菜鸟教程http:// ...
- 顶级c程序员之路 选学篇-1 深入理解字节,字节序与字节对齐
深入理解字节,字节序与字节对齐 一 总述 作为一个职业的coder玩家,首先应该对计算机的字节有所了解. 我们经常谈到的2进制流,字节(字符)流,数据类型流(针对编程),结构流等说法,2进制流,0和 ...
- nand读寿命_Nand Flash的擦写次数与使用寿命
Nand Flash的擦写次数与使用寿命 作者: 来源: 发布时间:2019-09-04 20:28:27 浏览:2086 Nand Flash因为其电气特性,读和写是按页来读取的,而擦除是按照块 ...
- 文件底层I/O基本操作——东写西读南开北关中位移_莫韵乐的Linux英雄传
文件I/O基本操作--东写西读南开北关中位移 Linux王国曾经有那么一个风起云涌的年代,而在那一个年代里就有那么五位人中龙凤掀起无数的波澜,人们称他们为东写西读南开北关中位移 在Linux的文件操作 ...
最新文章
- 人为「刷」论文引用量,IEEE高级会员被终身“禁赛”,奖项被撤销
- 通过apt自动生成建造者模式单线程版代码(一)
- python期末考试题及答案翻译-[译]Python面试中8个必考问题
- leetcode 1310. 子数组异或查询(位运算)
- java基本命令_java基础篇 快捷键 常见Dos命令等等
- NYOJ-非洲小孩(贪心)
- 移动App 网络优化细节探讨
- Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析(5)
- 文件上传2-搭建uploads靶场
- 怎样在线将图片转换成icon图标
- 是男人就闯到99关 【安卓软件】
- 计算机应用基础数制试题及答案,计算机应用基础试题及答案1.doc
- 当代著名国际摄影师相关网站大集合
- 拿到天使投资是一种怎样的体验
- 贝叶斯网专题11:参数学习之极大似然估计
- php upush 友盟 推送_react-native集成友盟推送
- Linux下编译cscope,Linux cscope命令
- 政考网:省考上岸,2021国考有希望吗?
- Win10解决能Ping通但不能访问局域网主机的问题
- 关闭新版360浏览器广告流氓行为
热门文章
- Lumen (Laravel子框架) 简介及分析
- 电脑蓝屏黑屏无法开机.BIOS更新.进不去系统只能重装?驱动人生解决方案
- RRD_rrdtool的介绍和使用
- appium java常用函数_AppiumLibrary常用关键字
- PhantomJS将网页保存为图片
- AI巨头们建造的“新世界”,进展如何?
- JConsole:Java监视与管理控制台
- 常见神经系统疾病的临床诊断及处理原则题库【1】
- Vue的MVVM(model、view、viewmodel)
- html里a标签的鼠标效果,html如何实现鼠标悬停提示A标签内容