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
;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