mikrokontrolery.net

 

   

Przykład 10 - magistrala 1-wire

Przykład 10 - magistrala 1-wire (wersja wstępna)

Poniższy program odczytuje temperaturę z czujnika DS1822 (18B20) i wyświetla ją na dwóch cyfrach wyświetlacza siedmiosegmentowego płytki AVT-3500. Czujnik należy podłączyć do złącza śrubowego SCL (końcówka DQ) oraz do zasilania (+5V, GND). Zworki J1 i J2 należy przełączyć w pozycję B-C.

; Kurs asemblera mikrokontrolerów AVR
;
; Przykład 10 - magistrala 1wire

.include "2313def.inc"

#define DQ_PORT DDRD
#define DQ 5
#define SET_DQ cbi DQ_PORT, DQ
#define CLR_DQ sbi DQ_PORT, DQ

#define IN_DQ PIND

#define acc r19
#define count r20
#define temp r21
#define rdel r22
#define lsb r23
#define msb r24

#define D1 r25
#define D2 r26
#define ktora_cyfra r27

.org 0x00
rjmp start
; umieszczenie w niewykorzystanym obszarze wektorów przerwań talblicy z kodami znaków
; w celu zaoszczędzenia miejsca w pamięci programu :-)
znaki: .db 192,249,164,176,153,146,130,248,128,144
; !w razie korzystania z przerwań o wektorach zajętych przez tablicę
; należy przenieść ją w inny obszar pamięci!
.org 0x06
rjmp timer0
.org 0x0B

; procedura opóźniająca o (5+5*rdel) * 0,25 us
delay:
nop
subi rdel, 1
brne delay
ret

; procedura generujaca sygnał reset na linii 1wire
ow_reset:
cli
CLR_DQ ; stan niski na linii 1wire
ldi rdel, 255 ;
rcall delay ;
ldi rdel, 119 ; opóźnienie ok 480 us
rcall delay ;
SET_DQ ; stan wysoki na linii 1wire
ldi rdel, 255 ;
rcall delay ;
ldi rdel, 119 ; opóźnienie ok 480 us
rcall delay ;
sei
ret

; procedura nadania bitu przez linię 1wire
ow_write_bit:
cli ; zablokowanie przerwań
CLR_DQ ; stan niski na linii 1wire
ldi rdel, 7
rcall delay
cpi acc, 0
breq dalej
SET_DQ
dalej:
ldi rdel, 80
rcall delay
SET_DQ
sei
ret

; procedura odczytu bitu z linii 1wire
ow_read_bit:
cli
CLR_DQ
ldi rdel, 1
rcall delay
SET_DQ
ldi rdel, 11
rcall delay
ldi acc, 1
sbis IN_DQ, DQ
ldi acc, 0
sei
ret


; procedura wsłania bajtu na linię 1wire
ow_write:
mov temp, acc ; zapamiętanie danej wejściowej w rejestrze temp
ldi count, 1 ; załadowanie do licznika wartości początkowej
loop1:
mov acc, temp ; przywrócenie danej wejściowej
and acc, count ; iloczyn logiczny danej wejściowej i licznika
rcall ow_write_bit ; wywołanie procedury zapisu bitu
lsl count ; przesuniecie licznika o 1 bit w lewo
cpi count, 0 ; sprawdzenie, czy licznik = 0
brne loop1 ; jeśli nie to wróc na początek pętli
ret

; procedura odczytu bajtu z linii 1wire
ow_read:
ldi temp, 0 ; wyzerowanie rejestru temp
ldi count, 1 ; załadowanie do licznika wartości początkowej
loop2:
rcall ow_read_bit ; wywołanie procedury odczytu bitu z linii 1wire
cpi acc, 0 ; porównanie zwróconej wartośći z liczbą 0
breq rd1 ; jeśli równe to skocz do rd1
or temp, count ; jeśli rózne to wykonaj sumę logiczną temp i licznika
rd1:
ldi rdel, 6 ; opóźnienie
rcall delay
lsl count ; przesunięcie licznika o 1 bit w lewo
cpi count, 0 ; sprawdzenie, czy licznik = 0
brne loop2 ; jeśli nie to skocz na początek pętli
mov acc, temp ; przepisanie temp do acc
ret

; program główny
start:
; inicjalizacja stosu
ldi acc, RAMEND
out SPL, acc
; konfiguracja PORTB
ldi acc, 255
out DDRB, acc

; ustawnienie PORTB.3 w tryb wyjściowy
sbi DDRD, 3
; ustawnienie PORTB.4 w tryb wyjściowy
sbi DDRD, 4
; ustawnienie PORTB.3 w stan wysoki
sbi PORTD, 3
; ustawnienie PORTB.4 w stan wysoki
sbi PORTD, 4
; inicjalizacja timera TIMER0
ldi acc, 4 ; ustaw preskaler timera 0 na 64
out TCCR0, acc ;

ldi acc, 128 ; wpisz wartosć początkową licznika
out TCNT0, acc ;

ldi acc, 2 ; odblokuj przerwanie od timera 0
out TIMSK, acc
; odblokowanie przerwań
sei

main:
rcall ow_reset ; reset
ldi acc, 0xCC
rcall ow_write ; wyślij rozkaz SKIP ROM
ldi acc, 0x44
rcall ow_write ; wyślij rozkaz rozpoczęcia pomiaru temperatury
ldi acc, 250
rcall waitms
rcall waitms
rcall waitms ; odczekaj 750 ms na zakończenie pomiaru

rcall ow_reset ; reset
ldi acc, 0xCC
rcall ow_write ; wyślij rozkaz SKIP ROM
ldi acc, 0xBE
rcall ow_write ; wyślij rozkaz odczytu danych z układu DS1822

rcall ow_read ; odczytaj mniej znaczący bajt wyniku pomiaru
mov lsb, acc
rcall ow_read ; odczytaj bardizej znaczacy bajt wyniku pomiaru
mov msb, acc

lsr lsb ;
lsr lsb ;
lsr lsb ; przesunięcie lsb o 4 bity w prawo
lsr lsb ;

andi msb, 0x07 ; wyzerowanie 5 najstarszych bitów msb

lsl msb ;
lsl msb ;
lsl msb ; przesunięcie msb o 4 bity w lewo
lsl msb ;

or lsb, msb ; suma logiczna lsb i msb, w lsb znajduje się temperatura

; przygotowanie temperatury do wyświetlenia na wyświetlaczu
; dzielenie temperatury przez 10
mov dd8u, lsb ; przeniesienie temperatury do rejestru dzielenia
ldi dv8u, 10 ; załadowanie dzielnika
rcall div8u ; wywołanie procedury dzielenia

ldi ZH, high(znaki << 1) ; załadowanie do rejestru Z adresu
ldi ZL, low(znaki << 1) ; tablicy z kodami znaków

add ZL, dres8u ; do adresu początku tablicy dodaj
clr acc ; wynik dzielenia przez 10
adc ZH, acc

lpm ; załaduj do r0 bajt z tablicy znaków
mov D1, r0 ; przenieś r0 do D1

ldi ZH, high(znaki << 1) ; załadowanie do rejestru Z adresu
ldi ZL, low(znaki << 1) ; tablicy z kodami znaków

add ZL, drem8u ; do adresu początku tablicy dodaj
clr acc ; reszte z dzielenia przez 10
adc ZH, acc

lpm ; załaduj do r0 bajt z tablicy znaków
mov D2, r0 ; przenieś r0 do D2

rjmp main ; skok na początek pętli głównej





; Przybliżone czasy opóźnień są podane dla
; rezonatora 4MHz
.def licz1 = r20
.def licz2 = r21
.def licz3 = r22
waitms:
mov licz3, acc ; ustaw czas opóźnienia
; powtórz n razy pętlę L,
; co da opóźnienie ok. n * 1 ms
L:
; powtórz 10 razy pętlę L0,
; co da opóźnienie ok 1ms
ldi licz2, 10
L0:
; powtórz 100 razy pętlę L1,
; co da opóźnienie ok. 100 us
ldi licz1, 100
L1:
nop ; 1 cykl
dec licz1 ; 1 cykl
brne l1 ; 2 cykle
; koniec pętli L1
dec licz2
brne l0
; koniec pętli L0
dec licz3
brne L
; koniec pętli L
ret

; Procedura dzielenia 8bitowego
; pochodzi z noty AVR200 firmy ATMEL
.def drem8u =r15 ;remainder
.def dres8u =r16 ;result
.def dd8u =r16 ;dividend
.def dv8u =r17 ;divisor
.def dcnt8u =r18 ;loop counter

div8u: sub drem8u,drem8u ;clear remainder and carry
ldi dcnt8u,9 ;init loop counter
d8u_1: rol dd8u ;shift left dividend
dec dcnt8u ;decrement counter
brne d8u_2 ;if done
ret ;return
d8u_2: rol drem8u ;shift dividend into remainder
sub drem8u,dv8u ;remainder = remainder - divisor
brcc d8u_3 ;if result negative
add drem8u,dv8u ;restore remainder
clc ;clear carry to be shifted into result
rjmp d8u_1 ;else
d8u_3: sec ;set carry to be shifted into result
rjmp d8u_1
; koniec procedury dzielenia

; procedura obsługi przerwania od TIMER0
timer0:
ldi acc, 250 ; ustaw wartość początkową licznika
out TCNT0, acc ;

sbi PORTD, 3 ; wyłącz anody wyświetlaczy
sbi PORTD, 4 ;

inc ktora_cyfra ; zwiększ ktora_cyfra o 1

cpi ktora_cyfra, 1 ; jeśli ktora_cyfra != 1 to
brne t1 ; skocz do t1, w przeciwnym razie
cbi PORTD, 4 ; włącz pierwszą cyfrę wyświetlacza
out PORTB, D1 ; wyświetl na wyświetlaczu zawartość r10
rjmp end1 ; skocz do end1
t1:
cpi ktora_cyfra, 2 ; jeśli ktora_cyfra != 2 to
brne t2 ; skocz do t2, w przeciwnym razie
cbi PORTD, 3 ; włącz drugą cyfrę wyświetlacza
out PORTB, D2 ; wyświetl na wyświetlaczu zawartość r11
rjmp end1 ; skocz do end1
t2:
ldi ktora_cyfra, 0 ; zeruj ktora_cyfra
end1:
reti
 

1-wire avr

 

 

 

 

 

 

 

 

 

 

 
 
 
 

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