在编写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字节读、字节写、页读、页写驱动代码、注意事项及注释相关推荐

  1. python中指定变量为1byte_Python读字节某一位的值,设置某一位的值,二进制位操作...

    Python读字节某一位的值,设置某一位的值,二进制位操作 ??在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...

  2. 在Java里怎将字节数转换为我们可以读懂的格式?

    问题:在Java里怎将字节数转换为我们可以读懂的格式? 在Java里怎将字节数转换为我们可以读懂的格式 像1024应该变成"1 Kb",而1024*1024应该变成"1 ...

  3. python获取二进制bit位_Python读字节某一位的值,设置某一位的值,二进制位操作...

    Python读字节某一位的值,设置某一位的值,二进制位操作 在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fals ...

  4. 《STM32从零开始学习历程》——I2C向EEPROM写入一字节数据(I2C硬件)

    <STM32从零开始学习历程>@EnzoReventon I2C向EEPROM写入一字节数据(I2C硬件) 相关链接: I2C物理层介绍 I2C协议层介绍 I2C固件库介绍 STM32的I ...

  5. Python读字节某一位的值,设置某一位的值,二进制位操作

    Python读字节某一位的值,设置某一位的值,二进制位操作   在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...

  6. python写文件读文件-python--文件流读写

    在讲述fileinput模块之前,首先说一下python内置的文件API-open()函数以及与其相关的函数. 我这里主要讲讲其中四个比较重要和常用的方法,更多的方法,可以参考:菜鸟教程http:// ...

  7. 顶级c程序员之路 选学篇-1 深入理解字节,字节序与字节对齐

     深入理解字节,字节序与字节对齐 一 总述 作为一个职业的coder玩家,首先应该对计算机的字节有所了解. 我们经常谈到的2进制流,字节(字符)流,数据类型流(针对编程),结构流等说法,2进制流,0和 ...

  8. nand读寿命_Nand Flash的擦写次数与使用寿命

    Nand Flash的擦写次数与使用寿命 作者: 来源: 发布时间:2019-09-04 20:28:27   浏览:2086 Nand Flash因为其电气特性,读和写是按页来读取的,而擦除是按照块 ...

  9. 文件底层I/O基本操作——东写西读南开北关中位移_莫韵乐的Linux英雄传

    文件I/O基本操作--东写西读南开北关中位移 Linux王国曾经有那么一个风起云涌的年代,而在那一个年代里就有那么五位人中龙凤掀起无数的波澜,人们称他们为东写西读南开北关中位移 在Linux的文件操作 ...

最新文章

  1. 人为「刷」论文引用量,IEEE高级会员被终身“禁赛”,奖项被撤销
  2. 通过apt自动生成建造者模式单线程版代码(一)
  3. python期末考试题及答案翻译-[译]Python面试中8个必考问题
  4. leetcode 1310. 子数组异或查询(位运算)
  5. java基本命令_java基础篇 快捷键 常见Dos命令等等
  6. NYOJ-非洲小孩(贪心)
  7. 移动App 网络优化细节探讨
  8. Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析(5)
  9. 文件上传2-搭建uploads靶场
  10. 怎样在线将图片转换成icon图标
  11. 是男人就闯到99关 【安卓软件】
  12. 计算机应用基础数制试题及答案,计算机应用基础试题及答案1.doc
  13. 当代著名国际摄影师相关网站大集合
  14. 拿到天使投资是一种怎样的体验
  15. 贝叶斯网专题11:参数学习之极大似然估计
  16. php upush 友盟 推送_react-native集成友盟推送
  17. Linux下编译cscope,Linux cscope命令
  18. 政考网:省考上岸,2021国考有希望吗?
  19. Win10解决能Ping通但不能访问局域网主机的问题
  20. 关闭新版360浏览器广告流氓行为

热门文章

  1. Lumen (Laravel子框架) 简介及分析
  2. 电脑蓝屏黑屏无法开机.BIOS更新.进不去系统只能重装?驱动人生解决方案
  3. RRD_rrdtool的介绍和使用
  4. appium java常用函数_AppiumLibrary常用关键字
  5. PhantomJS将网页保存为图片
  6. AI巨头们建造的“新世界”,进展如何?
  7. JConsole:Java监视与管理控制台
  8. 常见神经系统疾病的临床诊断及处理原则题库【1】
  9. Vue的MVVM(model、view、viewmodel)
  10. html里a标签的鼠标效果,html如何实现鼠标悬停提示A标签内容