AT89S8253片内EEPROM字节读、字节写、页读、页写驱动代码、注意事项及注释

2 篇文章 0 订阅
1 篇文章 0 订阅

在编写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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值