mikrokontrolery.net

 

   

Przykład 9 - magistrala I2C
W tym odcinku kursu asembelra zajmiemy się magistralą I2C, Program, który napiszemy będzie odczytywał z przetwornika PCF8591 wynik pomiaru i wyświetlał go w postaci binarnej na wyświetlaczu LED. Przed przystąpieniem do przerabiania materiału zawartego w tym przykładzie zalecane jest zapoznanie się z podstawowymi informacjami dotyczącymi transmisji szyną I2C zawartymi w tym dokumencie, lub na stronie : http://www.autokacik.pl/i2c/. Aby możliwe było przeprowadzenie tego ćwiczenia, należy dołączyć do płytki testowej potencjometr podłączony w sposób pokazany na rysunku :

Kręcąc osią potencjimetru zmieniamy napięcie podawane na wejście przetwornika A/C. Zakres przetwarzania przetwornika wynosi 0..2.55V (chyba, że ustawimy inne napięcie referencyjne), tak więc nie należy przekraczać tego zakresu. Wyświetlany wynik pomiaru jest podany w postaci binarnej. Nie dopisałem żadnych procedur przetwarzających wynik na postać bardziej czytelną dla człowieka, ponieważ będzie to tematem na inny artykuł. Celem tego programu jest wyłącznie zaprezentowanie sposobu korzystania z szyny I2C.

; Kurs asemblera mikrokontrolerów AVR
;
; Przykład 9 - magistrala I2C
;
.include "2313def.inc"
; nadanie odpowiednim rejestrom I/O nazw symbolicznych
.equ I2CDir = DDRD
.equ I2COut = PORTD
.equ I2CIn = PIND
; zdefiniowanie pinów magistrali I2C
.equ SDA = 6
.equ SCL = 5
; określenie adresów układu PCF8591
.equ PCF8591_ADDR = 144
; bity R/W
.equ R = 1
.equ W = 0
; potwierdzenie
.equ ACK = 0
.equ NOACK = 1
; nadanie odpowiednim rejestrom nazw symbolicznych
.def acc = r16
.def licznik = r17
.def pomoc = r18

.cseg ; segment kodu
.org 0x00 ; adres 0x00
ldi acc, 0xFF
out DDRB, acc ; skonfigurowanie protu PORTB jako wyjścia
out PORTB, acc ; wszystkie piny PORTB w stanie wysokim
; włączenie pierwszej cyfry wyświetlacza
sbi DDRD, 3 ; skonfigurowanie PORTD.3 jako wyjścia
cbi PORTD, 3 ; ustawienie stanu niskiego na PORTD.3
; ustawienie wskaˇnika stosu na koniec obszaru RAM
ldi acc, RAMEND ; załaduj do acc adres końca obszaru pamięci RAM
out SPL, acc ; zapisz ten adres do SPL


; początek programu głównego
start:
rcall i2cstart ; rozpoczęcie transmisji szyną I2C
ldi acc, PCF8591_ADDR | R ; załaduj do acc adres układu PCF8591 do odczytu
rcall i2cwrite ; wyślij ten adres na szynę I2C
ldi acc, NOACK ; zładuj do acc wartość bitu ACK (brak potwierdzenia - odczytany zostanie tylko 1 bajt)
rcall i2cread ; odczytaj bajt z szyny I2C
rcall i2cstop ; koniec transmisji
; przygotowanie danych do wyswietlenia
com acc ; zeneguj wszystkie bity acc
; wyświetlenie danych na wyświetlaczu
out PORTB, acc ; wyślij do PORTB zawartość acc

rjmp start ; skok na początek programu głównego

; procedura opóˇniająca
delay:
cp r0, r0
breq ll1
ll1: breq ll2
ll2: breq ll3
ll3: breq ll4
ll4: ret

; procedura generująca sekwencję startu
i2cstart:
sbi I2CDir, SCL ;linie SDA i SCL pracują jako wyjście
sbi I2CDir, SDA

sbi I2COut, SDA ; ustawienie linii SDA i SCL w satn wysoki
sbi I2COut, SCL

rcall delay ;opóˇnienie

cbi I2COut, SDA ; ustaw SDA w stan niski
rcall delay ; opóˇnienie

cbi I2COut, SCL ;ustaw SCL w stan niski
rcall delay ;opóˇnienie

ret

; procedura generująca sekwencję stopu
i2cstop:
sbi I2CDir, SDA ; SDA jako wyjście

sbi I2COut, SCL ; ustaw na SCL stan wysoki
rcall delay ; opóˇnienie

sbi I2COut, SDA ; ustaw na SDA stan wysoki
rcall delay ; opóˇnienie
ret

; procedura wysłania bajtu na szynę I2C
i2cwrite:
sbi I2CDir, SDA ; SDA jako wyjście
ldi licznik, 8 ; ustaw ilość powtórzeń pętli
petla1:
; wysłanie na szynę I2C najstarszego bitu z acc
sbrs acc, 7 ; jeśli bit 7 w acc jest ustawiony, to pomiń następną instrukcję
cbi I2COut, SDA ; ustaw na SDA stan niski
sbrc acc, 7 ; jeśli bit 7 w acc jest wyzerowany, to pomiń następną instrukcję
sbi I2COut, SDA ; ustaw na SDA stan wysoki
; wygenerowanie opadającego zbocza na SCL -> zapis do SLAVE'a
sbi I2COut, SCL ; ustaw na SCL stan wysoki
rcall delay ; opóˇnienie
cbi I2COut, SCL ; ustaw na SCL stan niski
; przygotowanie następnego bitu do transmisji
lsl acc ; przesunięcie w lewo acc
; modyfikacja i sprawdzenie wartości licznika pętli
dec licznik ; zmniejsz licznik pętli o 1
brne petla1 ; jeśli niezerowy, to skocz do petla1

rcall delay ; opóˇnienie
; przygotowanie do odczytu sygnału ACK ze SLAVE'a
cbi I2CDir, SDA ; SDA jako wejście
cbi I2COut, SDA ; ustaw na SDA stan niski
sbi I2COut, SCL ; ustaw na SCL stan wysoki
; odczyt sygnału ACK ze SLAVE'a
sbis I2CIn, SDA ; jeśli SDA jest w stanie wysokim, to pomiń następną instrukcję
ldi acc, ACK ; ACK = 0
sbic I2CIn, SDA ; jeśli SDA jest w stanie niskim, to pomiń następną instrukcję
ldi acc, NOACK ; ACK = 1
rcall delay ; opóˇnienie

cbi I2COut, SCL ; ustaw na SCL stan niski
ret

; procedura odczytu bajtu z szyny I2C
i2cread:
mov r19, acc
cbi I2CDir, SDA ; SDA jako wejście
cbi I2COut, SDA ; ustawienie stanu niskiego na SDA
ldi licznik, 8
petla2:
sbi I2COut, SCL ; stan wysoki na SCL
rcall delay ; opóˇnienie
lsl acc ; przesunięcie acc w lewo
sbic I2CIn, SDA ; jeśli SDA jest w stanie niskim to pomiń następną instrukcję
ori acc,1 ; ustaw bit 0 acc
cbi I2COut, SCL ; stan niski na SCL

dec licznik ; zmniejsz licznik pętli o 1
brne petla2 ; jeśli niezerowy to skocz do petla2

rcall delay ; opózninie
; transmijsa bitu ACK
sbi I2CDir, SDA ; SDA jako wyjście

sbrs r19, 0 ; jeśli bit 0 w acc jest ustawiony to pomiń następną instrukcję
cbi I2COut, SDA ; ustaw na SDA stan niski (ACK)
sbrc r19, 0 ; jeśli bit 0 w acc jest wyzerowany to pomiń następną instrukcję
sbi I2COut, SDA ; ustaw na SDA stan wysoki (NOACK)

sbi I2COut, SCL ; ustaw na SCL stan wysoki

rcall delay ; opóˇnienie

cbi I2COut, SCL ; ustaw na SCL stan niski
ret

Ostatnio na forum:

 

 

 

 

 
 
 
 
 

(c) 2004-2008 Radosław Kwiecień
Polityka prywatności