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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章