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