Jste zde

Rutina komunikace se sériovou pamětí typu 24C pro x51

Rutina komunikace se sériovou pamětí typu 24C pro x51.

Při návrhu zapojení se vyskytují případy, kdy je nutno uchovat po vypnutí napájení poměrně velké množství dat. V případě malého procesoru, jako jsou AT89C1051, AT89C2051, AT90S1200 nebo dokonce AT90S2343, je nutno použít sériové paměti. Sériové paměti typu 93C jsou dostupné pouze v malé kapacitě. Při požadavku na vyšší kapacitu přicházejí v úvahu sériové paměti typu 24C (128B až 64kB), využívající komunikace pouze pomocí dvou vodičů. Jedinou výhodou těchto pamětí není pouze ušetření vývodů procesoru, ale hlavně možnost na jeden komunikační kanál (hodiny a obousměrná data) osadit až osm těchto pamětí. Začátečníka asi velmi často odradí na první pohled složitý komunikační protokol, obousměrná datová linka a nutnost generovat a kontrolovat bit zvaný ACK. 

Celý podrobný článek najdete ZDE..

Následuje výpis potřebné rutiny :
 

Pokud máte hotové podobnoé SW rutiny, které chcete publikovat, pošlete nám je pokošíme se zde vytvořit knihovnu podobných utilit. - INFORMACE PRO AUTORY

Petr Novák

;Stazeno z www.HW.cz
;                              Autorem tohoto SW je Petr Novak -  Novak@ hw.cz
;------------------------------------------------------------------------------
;                    ### POUZITE BYTY A BITY ###
;------------------------------------------------------------------------------

 AT24C32  EQU 8 ; (bit)
     ; =0 pro 24C01/02/04/08/16
     ; =1 pro 24C32/64/128/256/512
 I2C_ERROR EQU 9 ; (bit) nebyl prijat platny ACK
 I2C_END  EQU 10 ; (bit) =1 bude se cist posleni byte
 I2C_ACK  EQU 11 ; (bit) zapisovany/cteny ACK bit

 I2C_SELECT EQU 8 ; (byte) nastaveni vyberovych vstupu A0,A!,A2
 ADR_LOW  EQU 9 ; (byte) nastavena adresa rpo zapis/cteni
 ADR_HIGH EQU 10 ; (byte)
 I2C_POCET EQU 11 ; (byte) pocet zapisovenych/ctenych bytu
 I2C_TEMP EQU 12 ; (byte) ulozeni vysilane hodnoty

 I2C_SPEED EQU 10 ; konstanta

 ; prirazeni pinu
 SCL  EQU P1.0 ; CLK pro I2C
 SDA  EQU P1.1 ; DATA pro I2C

;------------------------------------------------------------------------------
;                           ### MAKRA ###
;------------------------------------------------------------------------------

; cekaci cas 2x I2C)SPEED (us)
; vstup:  I2C_SPEED - pocet cekani v (2 * us)
DELAY MACRO
  mov 13,#I2C_SPEED  ; pozadovana delka cekani
  djnz 13,$  ; a jeho vytvoreni
  ENDM
;------------------------------------------------------------------------------
;                     **** ukazkove programy ****

 TABULKA1 EQU 120 ; zapisovane hodnoty (interni RAM)
 TABULKA2 EQU 50 ; ctene hodnoty (interni RAM)

 mov sp,#100  ; zasobnik

; nastaveni pro seriovou pamet
 setb AT24C32  ; bude to 24C64
 mov I2C_SELECT,#00 ; vstupy A0,A1,A2 zapojeny na log.0
 clr I2C_ERROR ; zatim neni chyba

; zapis jedne hodnoty na danou adresu
 mov ADR_LOW,#34h ; na adresu 1234h
 mov ADR_HIGH,#12h
 mov A,#12h  ; zapis hodnotu ABh
 call WRITE_BYTE

; cteni jedne hodnoty z dane adresu
 mov ADR_LOW,#34h ; z adresy 1234h
 mov ADR_HIGH,#12h
 call READ_BYTE ; precti hodnotu do ACC

 mov C,I2C_ERROR ; stav I2C_ERROR -> Carry
 mov P1.7,C  ; Carry -> P1.7
 mov 05,A  ; ctenou hodnotu ulozit an adresu 05
 jmp $  ; konec

; zapis nekolika hodnot od dane adresy
 mov I2C_POCET,#10 ; zapis 10 bytu
 mov ADR_LOW,#34h ; od adresy 1234h
 mov ADR_HIGH,#12h
 mov R0,#TABULKA1 ; ktere jsou ulozeny v TABULKA1
 clr I2C_END  ; zatim neni konec zapisu
 mov A,@R0  ; vyzvednuti prvni hodnoty
 call WRITE_BYTES ; zapis adresy + prvni byte
 jb I2C_ERROR,WRI03 ; pokud pamet neodpovida -> chyba
 dec I2C_POCET ; jeden byte byl jiz zapsan
WRI01: djnz I2C_POCET,WRI02 ; pokud dalsi bude posledni byte
 setb I2C_END  ; tak nastav priznak konce zapisu
WRI02: inc R0  ; posun ukazatele pro cteni hodnot
 mov A,@R0  ; vyzvednuti dalsi hodnoty
 call WRITE_NEXT ; zapis dalsi hodnoty (pokud posledni -> STOP)
 jb I2C_ERROR,WRI03 ; pokud pamet neodpovida -> chyba
 jnb I2C_END,WRI01 ; jinak pokracuj dalsi hodnotou
WRI03: ; kontrola zda neni I2C_ERR

; cteni nekolika hodnot od dane adresy
 mov I2C_POCET,#10 ; cteni 10 bytu
 mov ADR_LOW,#34h ; od adresy 1234h
 mov ADR_HIGH,#12h
 mov R0,#TABULKA2 ; ktere se budou ukladat TABULKA2
 clr I2C_END  ; zatim neni konec cteni
 call READ_BYTES ; zapis adresy + cteni prvniho byte
 mov @R0,A  ; ulozeni prvni prectene hodnoty
 jb I2C_ERROR,REA03 ; pokud pamet neodpovida -> chyba
 dec I2C_POCET ; jeden byte byl jiz zapsan
REA01: djnz I2C_POCET,REA02 ; pokud dalsi bude posledni byte
 setb I2C_END  ; tak nastav priznak konce cteni
REA02: inc R0  ; posun ukazatele pro zapis hodnot
 call READ_NEXT ; cteni dalsi hodnoty (pokud posledni -> STOP)
 mov @R0,A  ; ulozeni dalsi prectene hodnoty
 jnb I2C_END,REA01 ; jinak pokracuj dalsi hodnotou
REA03: ; kontrola zda neni I2C_ERR

;----------------------------------------------------------------
;                      ### KOMUNIKACE s 24C ###
;----------------------------------------------------------------
READ_BYTE: ; vstup pro cteni jedne adresy udane v ADR_LOW a ADR_HIGH do ACC
  setb I2C_END  ; pouze tento byte
READ_BYTES: ; vstup pro cteni POCET bytu od adresy ADR_LOW a ADR_HIGH
  ; zapis adresy ze ktere se bude cist
  call I2C_START ; START na I2C
  call I2C_DEVICE_WR ; vyslani DEVICE bytu + WRITE
  jb I2C_ACK,I2C_ERR ; pokud pamet nedala ACK=0 -> CHYBA
  call I2C_ADR_WR ; zapis adresy
  jb I2C_ACK,I2C_ERR ; pokud pamet nedala ACK=0 -> CHYBA
  call I2C_STOP ; STOP na I2C
  ; zahajeni cteni
  call I2C_START ; START na I2C
  call I2C_DEVICE_RD ; vyslani DEVICE bytu + READ
  jb I2C_ACK,I2C_ERR ; pokud pamet nedala ACK=0 -> CHYBA
READ_NEXT: ; vstup pro cteni dalsicho bytu do ACC
  mov C,I2C_END ; Carry=1 pokud se bude cist posledni byte
  mov I2C_ACK,C ; pokud Carry=1 -> ACK=1 -> posledni cteni
  call I2C_IN  ; cteni bytu z I2C
  jnb I2C_END,READ_01 ; pokud to neni posledni cteny byte -> skok
  call I2C_STOP ; jinak STOP na I2C
READ_01: ret   ; navrat
;-----------------------------------------------------------------
WRITE_BYTE: ; vstup pro zapis na jednu adresu udanou ADR_LOW a ADR_HIGH z ACC
  setb I2C_END  ; pouze jedna hodnota
WRITE_BYTES: ; vstup pro zapis nekolika hodnot od ADR_LOW a ADR_HIGH, prvni v ACC
  mov I2C_TEMP,A ; uchovat vysilanou hodnotu
  ; zapis adresy na kterou se budou byty ukladat
  call I2C_START ; START na I2C
  call I2C_DEVICE_WR ; vyslani DEVICE bytu + WRITE
  jb I2C_ACK,I2C_ERR ; pokud pamet nedala ACK=0 -> CHYBA
  call I2C_ADR_WR ; zapis adresy
  jb I2C_ACK,I2C_ERR ; pokud pamet nedala ACK=0 -> CHYBA
  ; zapis vsech prijatych hodnot
  mov A,I2C_TEMP ; vyzvednou vysilanou hodnotu
WRITE_NEXT: ; vstup pro zapis da;lsi hodnoty z ACC
  call I2C_OUT  ; vyslani hodnoty
  jb I2C_ACK,I2C_ERR ; pokud pamet nedala ACK=0 -> CHYBA
  jnb I2C_END,WRITE_02 ; pokud neni posledni hodnota -> skok
  call I2C_STOP ; jinak STOP na I2C

  ; cekani na zapis (mozno zaremovat pokud se mezitim neco vykonava)
  mov B,#20  ; asi 10ms pro 12MHz (podle typu)
WRITE_01: mov A,#255  ; 0.5ms
  djnz ACC,$
  djnz B,WRITE_01

WRITE_02: ret   ; navrat

I2C_ERR: ; hlaseni chyby ze pamet neodpovida
  call I2C_STOP ; STOP na I2C
  setb I2C_ERROR ; chyba = SER. PAMET NEODPOVIDA
  ret   ; navrat pri chybe
;----------------------------------------------------------------
;                ### PODPROGRAMY PRO SERIOVE PAMETI 24C ###
;-----------------------------------------------------------------
; vytvoreni STARTu na I2C
I2C_START: push ACC  ; uchovej ACC
  clr SDA  ; SDA jde do log.0 zatim co je SCL=1 -> START
  DELAY   ; cekej
  clr SCL  ; SCL=1 (klidovy stav na I2C)
  mov A,#100  ; celej
  djnz ACC,$
  pop ACC  ; obnov ACC
  ret   ; navrat z podprogramu
;---------------------------------------------------------------
; vytvoreni STOPu na I2C
I2C_STOP: push ACC  ; uchovej ACC
  clr SDA  ; SDA=0 = klidovy stav
  mov A,#50  ; celej
  djnz ACC,$
  setb SCL  ; SCL=1 (pred zmenou SDA)
  DELAY   ; cekej
  setb SDA  ; SDA jde do log.1 zatim co je SCL=1 -> STOP
  mov A,#100  ; celej
  djnz ACC,$
  pop ACC  ; obnov ACC
  ret   ; navrat z podprogramu
;------------------------------------------------------------------
; vyslani DEVICE bytu s priznakem R/W
; (24C01/02/04/08/16),(24C32/64/128/256/512)

I2C_DEVICE_RD: ; vstup pro cteni hodnot
  mov A,#00000001b ; READ
  jmp I2C_WRITE
I2C_DEVICE_WR: ; vstup pro zapis hodnot
  mov A,#00000000b ; WRITE
I2C_WRITE: ; vstup pri zapisu
  orl A,I2C_SELECT ; nastaveni SELECTovacich pinu
  orl A,#10100000b ; DEVICE ADDRESS
  jb AT24C32,I2C_W1 ; pokud jde o 24C32/64/128/256/512 -> skok
  mov B,A  ; uschovej ACC
  mov A,ADR_HIGH ; HIGH cast adresy -> ACC
  rl A  ; posun do bitu 3,2,1
  orl A,B  ; a pricti k DEVICE ADDRESS
I2C_W1:  call I2C_OUT  ; vyslat
  ret       ; navrat z podprogramu
;--------------------------------------------------------------
; zapis adesy do ser. pameti
; (24C01/02/04/08/16),(24C32/64/128/256/512)
; vstup:  DPTR (DPL) -> adresa pro zapis do ser. pameti

I2C_ADR_WR:
  jnb AT24C32,I2CAW1 ; pokud nejde o 24C32/64/128/256 -> skok
  mov A,ADR_HIGH ; HIGH cast adresy
  call I2C_OUT  ; vyslat
  jb I2C_ACK,I2CAW2 ; pokud ACK=1 -> chyba
I2CAW1:  mov A,ADR_LOW ; LOW cast adresy
  call I2C_OUT  ; vyslat
I2CAW2:  ret   ; navrat z podprogramu
;-------------------------------------------------------------
; skutecne vysilani/prijem na I2C
; vstup:  ACC -> vysilana (OUT)/prijata(IN) hodnota
; vystup: I2C_ACK -> prijaty(OUT)/vysilany(IN) ACK

I2C_IN:   ; prijem bytu z I2C s vyslanim ACK
  mov A,#11111111b ; bude se prijimat
  jmp I2C_OUT1
I2C_OUT:  ; vyslani bytu na I2C s prijmem ACK
  setb I2C_ACK  ; ACK se bude prijimat
I2C_OUT1: mov B,#8  ; bude 8 bitu
I2C_OUT2: rlc A  ; ACC.7 -> Carry
  mov SDA,C  ; Carry -> SDA
  DELAY   ; cekej
  setb SCL  ; SCL=1 (zacatek zapisu dat)
  DELAY   ; cekej
  mov C,SDA    
  clr SCL  ; SCL=0 (konac zapisu dat)
  DELAY   ; cekej
  djnz B,I2C_OUT2 ; vyslat vsech 8 bitu
  rlc A  ; posledni prijaty bit do ACC
  mov C,I2C_ACK ; stav ACK -> Carry
  mov SDA,C  ; Carry -> SDA
  DELAY   ; cekej
  setb SCL  ; SCL=1 (pro zacatek prijeti ACK)
  DELAY   ; cekej
  mov C,SDA  ; stav ACK -> Carry
  mov I2C_ACK,C ; Carry -> I2C_ACK
  clr SCL  ; SCL=0 (pro ukonceni prijeti ACK)
  DELAY   ; cekej
  setb SDA  ; radsi SDA=1
  ret   ; navrat z podprogramu
;----------------------------------------------------------------
  end

;Stazeno z www.HW.cz
;                              Autorem tohoto SW je Petr Novak -  Novak@hw.cz



 
DOWNLOAD rutiny v .ZIP souboru
Hodnocení článku: