logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AVR][ATMega8] Procedury I2C w asemblerze

Pawel_361 21 Sty 2010 15:19 3133 9
REKLAMA
  • #1 7569085
    Pawel_361
    Poziom 17  
    Witam wszystkich forumowiczów.
    Zmagam się z nawiązaniem komunikacji poprzez I2C procesora ATmega8 oraz układu RTC PCF8583.
    Na wstępie napiszę, że linie SDA i SCL są podciągnięte do VCC przez rezystory 1K.
    Układ pracuje z kwarcem wewnętrznym 1MHz.
    Podprogram "dwiems" generuje opóźnienie rzędu 2ms.
    Podprogram "blad" wywołuje pętle, która zapala diode i program zostaje w tej pętli.
    Pin A0 układu RTC jest podłączony do GND, więc adres układu to 160 dla zapisu a 161 dla odczytu.
    Napisałem procedury do obsługi szyny I2C.
    Oto one:


    
    ;==========================================================
    I2cstart:
    ;==========================================================
    	sbi		i2cddr,sda		;sda jako wyj
    	sbi		i2cddr,scl		;scl jako wyj
    	nop
    	sbi 	I2CPORT,sda		;sda stan wysoki
    	nop
    	sbi 	I2CPORT,scl		;scl stan wysoki
    	rcall	dwiems
    	cbi 	I2CPORT,sda		;sda stan niski /procedura start
    	rcall 	dwiems
    	cbi 	I2CPORT,scl		;scl stan niski zeby potem mogl byc narastajacy
    	ret
    ;==========================================================
    I2cstop:
    ;==========================================================
    	sbi		i2cddr,sda		;sda jako wyj
    	sbi		i2cddr,scl		;scl jako wyj
    	nop
    	cbi 	I2CPORT,sda		;stan niski sda
    	nop
    	sbi 	I2CPORT,scl		;stan wysoki scl
    	rcall	dwiems
    	sbi 	I2CPORT,sda		;stan wysoki sda
    	rcall 	dwiems
    	ret
    ;==========================================================
    i2cwrite:	;PROCEDURA ZAPISU BAJTU NA LINIĘ I2C
    ;==========================================================
    sbi I2CDDR, SDA ; SDA jako wyjście
    ldi licznik, 8 ; ustaw ilość powtórzeń pętli
    petla1:
    sbrs acc, 7 ; jeśli bit 7 w acc jest ustawiony, to pomiń następną instrukcję
    cbi I2CPORT, SDA ; ustaw na SDA stan niski
    sbrc acc, 7 ; jeśli bit 7 w acc jest wyzerowany, to pomiń następną instrukcję
    sbi I2CPORT, SDA ; ustaw na SDA stan wysoki
    sbi I2CPORT, SCL ; ustaw na SCL stan wysoki, ZBOCZE NARASTAJĄCE
    rcall DWIEMS ; opóˇnienie
    cbi I2CPORT, SCL ; ustaw na SCL stan niski
    lsl acc ; przesunięcie w lewo acc
    dec licznik ; zmniejsz licznik pętli o 1
    brne petla1 ; jeśli niezerowy, to skocz do petla1
    ; ACK
    cbi I2CDDR, SDA ; SDA jako wejście
    Cbi I2CPORT, SDA ; ustaw na SDA stan NISKI
    RCALL	DWIEMS
    sbi I2CPORT, SCL ; ustaw na SCL stan wysoki
    sbiC I2CPIN, SDA ; jeśli SDA jest w stanie niskim, to pomiń następną instrukcję
    RCALL	BLAD
    Cbi I2CPORT, SCL ; ustaw na SCL stan NISKI
    
    ret
    
    ;==========================================================
    i2cread:	; procedura odczytu bajtu z szyny I2C
    ;==========================================================
    cbi I2CDDR, SDA ; SDA jako wejście
    Cbi I2CPORT, SDA ; ustawienie stanu NISKIEGO na SDA
    RCALL	DWIEMS
    ldi licznik, 8
    petla2:
    RCALL	DWIEMS
    sbi I2CPORT, SCL ; stan wysoki na SCL
    rcall DWIEMS ; opóˇnienie
    sbic I2CPIN, SDA ; jeśli SDA jest w stanie niskim to pomiń następną instrukcję
    ori acc,0 ; ustaw bit 0 acc
    lsl acc ; przesunięcie acc w lewo
    cbi I2CPORT, SCL ; stan niski na SCL
    
    
    dec licznik ; zmniejsz licznik pętli o 1
    brne petla2 ; jeśli niezerowy to skocz do petla2
    
    rcall DWIEMS ; opózninie
    ; ACK
    sbi 	I2CDDR, SDA ; SDA jako wyjście
    RCALL	DWIEMS
    cbi 	I2CPORT, SDA ; ustaw na SDA stan niski (ACK)
    sbi 	I2CPORT, SCL ; ustaw na SCL stan wysoki
    rcall 	DWIEMS ; opóˇnienie
    cbi 	I2CPORT, SCL ; ustaw na SCL stan niski
    ret
    


    Domyślam się, że procedury start,stop i write są poprawne. Podczas zapisu do danej komórki układ nie zapala diody, więc bit ACK jest poprawnie rozpoznawany. Jak wyjmę układ z podstawki to procesor zapala diodę.

    Problem tkwi w tym, że przy odczycie niezależnie od komórki, którą chce odczytać zawsze zwraca 0x00.
    Procedurę odczytu wykonuję w następujący sposób:
    1.Procedura start.
    2.Procedura zapisu na szynę I2C adresu slave'a do zapisu czyli 160.
    3.Procedura zapisu na szynę I2C adresu komóki czyli np $2 (rejestr sekund).
    4.Procedura startu.
    5.Procedura zapisu na szynę I2C adresu slave'a do odczytu czyli 161.
    6.Procedura odczytu danych z szyny I2C i zapis do ACC(rejestr roboczy R20).
    7.Procedura stop.

    Następnie wynik z ACC konwertuję z BCD i ślę na LCD.
    Algorytm dekodowania jest poprawny, bo jak ręcznie wpiszę do ACC wartość np. 0b00010010 to na LCD trafia wynik 12.

    Proszę o pomoc. Osobie, która pomoże mi odnaleźć błąd oddam wszystkie punkty :)
  • REKLAMA
  • REKLAMA
  • #3 7569399
    Pawel_361
    Poziom 17  
    Dzieki wielkie, nareszcie program ruszył :)
    Mam jednak problem z odczytem.
    Odczyt sekundnika pokazuje 00, później 02, 04 itd.
    Sam odczyt z pcfa jest realizowany co jakies 20ms.
    Przetestowałem algorytm dekodowania z bcd i przy wpisywaniu ręcznym zadanej wartości działa poprawnie. Wynika z tego, że pcf wysyła niepoprawne dane a raczej procedura odczytu szwankuje. Czy mógłbyś kolego atom1477 zerknąć jeszcze raz na ten kod ??
    Oczywiście obiecane punkty wysyłam.
  • REKLAMA
  • #4 7569462
    Konto nie istnieje
    Poziom 1  
  • #5 7569542
    Pawel_361
    Poziom 17  
    A przypadkiem w procedurze odczytu w polu "ldi licznik, 8 " nie powinno być 7 ??

    Dodano po 3 [minuty]:

    Po zmianie na 7 juz jest lepiej bo nie pokazuje krzaków co jakis czas ale nadal zmienia co 2sekundy.
  • #6 7569922
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #7 7570234
    Pawel_361
    Poziom 17  
    Hmm, coś jest nie tak.
    Zegar cały czas operuje tylko na parzystych liczbach.
    Nawet jak zapiszę do niego godzine 11 to i tak przy odczycie pokazuje 22.
    Aby ominąć mój algorytm dekodowania z BCD postanowiłem najpierw zapisać do RTC godzinę 11 i następnie odczytać i w formie BCD wysłać na portD a następnie miernikiem sprawdzić co zwraca układ rtc.
    Oto kod:
    
    
    rcall	i2cstart
    ldi acc, 160 ;zapisz na i2c adres sleave'a
    rcall	i2cwrite
    ldi acc,$4  ;zapisz do pcfa adres komórki godzin
    rcall	i2cwrite
    ldi acc, 0b00010001 ;zapisz godzine 11
    rcall	i2cwrite
    rcall	i2cstop
    
    rcall	i2cstart
    ldi acc, 160 ;zapisz do pcfa adres sleave'a
    rcall	i2cwrite
    ldi acc,$4		; zapisz adres komorki godzin
    rcall	i2cwrite
    rcall i2cstart
    ldi acc, 161 ;zapisz na i2c adres sleave'a
    rcall	i2cwrite
    rcall	i2cread
    rcall	i2cstop
    
    out portD,acc ;wyślij na portD wyniki odczytu
    
    lop:
    nop
    rjmp lop ; sztuczna pętla aby zatrzymać program
    


    Po sprawdzeniu wyprowadzeń miernikiem wynik następujący:
    od bitu 7 do 1: 00100010 czyli 22
    Pomóżcie bo już nie mam siły do tego I2C :(
  • #8 7570677
    Konto nie istnieje
    Poziom 1  
  • #9 7572704
    Pawel_361
    Poziom 17  
    Dobrze realizuję I2C. Błąd leżał w procedurze odczytu.
    I jak się okazało nieświadomie naprowadzałem Cię na błąd - w liczniku pętli powinno być 7 :) i oprócz tego naprawiłem jeszcze jeden błąd.
    Zamieszczam w 100% sprawdzone procedury do obsługi magistrali I2C ASM mojego autorstwa.
    Załączniki:
  • #10 7573047
    Konto nie istnieje
    Poziom 1  
REKLAMA