Powyższy schemat przedstawia sposób podłączenia alfanumerycznego wyświetlacza LCD (ze stero-
wnikiem HD44780 lub kompatybilnym), który może wyświetlić 2 linie tekstu po 16 znaków (2x16). Kon-
densator C1 filtruje napięcie zasilania Vcc=4.75-5.25V i powinien być umieszczony, jak najbliżej mikro-
kontrolera. Rezystor R1 utrzymuje wysoki stan logiczny na pinie RESET, przez co zapobiega przypad-
kowemu i samoistnemu resetowaniu się mikrokontrolera (np. podczas pracy w środowisku, gdzie wys-
tępują duże zakłócenia). Działanie zworki J1 jest ściśle związane z programem opisanym niżej. Złącze
CON1 służy do programowania mikrokontrolera w systemie (ISP - In-System Programming) i zawiera
sygnały rozmieszczone w standardowy sposób, zalecany przez firmę Atmel. Programowanie w systemie
oznacza możliwość zaprogramowania mikrokontrolera w układzie elektronicznym, w którym pracuje bez
potrzeby wyjmowania/wylutowywania go z niego. Potencjometrem P1 reguluje się kontrast wyświetlacza
LCD, co ma duży wpływ na jego czytelność. Jeśli wyświetlacz ma podświetlenie w postaci diody LED,
to jego wyprowadzenia nr 15 i 16 służą do jej zasilania. W przeciwnym razie wyprowadzenia te nie są
podłączone (NC).
Na wielu schematach, pokazujących sposób podłączenia wyświetlacza LCD do mikrokontrolera w trybie
4-bitowym, linie danych D0-D3 wyświetlacza są połączone bezpośrednio z masą zasilania (GND). Nie
jest to prawidłowy sposób biorąc pod uwagę fakt, że linie te są dwukierunkowe i mogą pracować jako
wejścia/wyjścia (I/O). Przykładowo, jeśli program sterujący odczytuje dane z wyświetlacza i na którejś
linii D0-D3 pojawia się wysoki stan logiczny, to następuje zwarcie plusa zasilania do masy. Oczywiście
zwarcie to jest krótkotrwałe i nie musi uszkodzić wyświetlacza, czy zaburzać jego pracy, ale mimo to
lepiej unikać takich sytuacji. Dlatego na moim schemacie nieużywane linie D0-D3 wyświetlacza nie są
w ogóle podłączone.
Aby niżej opisany program zadziałał, bardzo ważne jest właściwe skonfigurowanie mikrokontrolera, czyli
zaprogramowanie tzw. fuse/lock bitów. Jeśli mikrokontroler był już używany, to należy się upewnić że ma
odpowiednio ustawione fuse i lock bity: FL (Fuse Low): $62, FH (Fuse High): $DF ($D9 dla ATmega-
328), FE (Fuse Extended): $F9 ($FF dla ATmega48/328), LB (Lock Bits): $FF. Fabrycznie nowe mikro-
kontrolery ATmega48/88/168/328 mają właśnie takie domyślne ustawienia. Powodują one, że mikrokon-
troler korzysta z wewnętrznego oscylatora RC, o częstotliwości nominalnej 8 MHz (bity CKSEL3-0=
0010); włączony jest dzielnik częstotliwości przez 8, co powoduje taktowanie mikrokontrolera zegarem
1 MHz (CKDIV8=0); wydłużony jest czas jego startu do ok. 65ms po włączeniu napięcia zasilania (SUT-
1-0=10), a także włączona jest możliwość jego zaprogramowania przez interfejs szeregowy (SPIEN=0).
Należy bardzo uważać, aby nie dokonać zmian w fuse/lock bitach, które uniemożliwią dalsze programo-
wanie mikrokontrolera.
Poniżej znajduje się opis kolejnych fragmentów kodu programu, przeznaczonego dla mikrokontrolerów
serii ATmega48/88/168/328, który służy do inicjalizacji i obsługi wyświetlacza LCD.
.include "m48def.inc" ;definicje dla ATmega48
;.include "m88def.inc" ;definicje dla ATmega88
;.include "m168def.inc" ;definicje dla ATmega168
;.include "m328def.inc" ;definicje dla ATmega328
Dołączanie plików z definicjami nazw i adresów rejestrów dla danego mikrokontrolera (w tym przypadku
dla ATmega48). Jeśli kompilujemy program dla ATmega88, 168 lub 328, to należy pierwszą linię zamie-
nić w komentarz (na jej początku dodać znak ";") i uaktywnić jedną z trzech pozostałych linii (usunąć
znak ";").
.cseg ;pamięć programu (FLASH)
.org $0000 ;wektory przerwań (dla ATmega48/88: 26 wektorów 2-bajtowych, o adresach $0000-$0019,
;dla ATmega168/328: 26 wektorów 4-bajtowych, o adresach $0000-$0032).
;Jeśli żadne przerwania nie będą używane, to w tym miejscu można bezpośrednio umieścić kod programu
;Wektor nr 1 (Reset)
;rjmp RESET ;dla ATmega48/88 musi to być instrukcja RJMP o rozmiarze 2 bajtów,
;jmp RESET ;dla ATmega168/328 musi to być instrukcja JMP o rozmiarze 4 bajtów,
;ponieważ wszystkie wektory w tych mikrokontrolerach mają taki rozmiar.
;RESET:
;Inicjalizacja wskaźnika stosu (zbędna dla ATmega48/88/168/328)
;ldi R16,LOW(RAMEND)
;out SPL,R16
;ldi R16,HIGH(RAMEND)
;out SPH,R16
Dyrektywa ".cseg" oznacza blok pamięci kodu/programu (FLASH) mikrokontrolera, a ".org $0000" okre-
śla jej początek, czyli adres zerowy. Po włączeniu/resecie systemu, to właśnie od tego adresu mikro-
kontroler rozpoczyna wykonywanie instrukcji. Ten program nie używa przerwań dlatego pod adresem
zerowym, znajduje się jego pierwsza instrukcja. Natomiast jeśli przerwania są wykorzystywane, to pod
tym adresem znajduje się tablica 26 wektorów przerwań. Każdy wektor to instrukcja skoku do procedury,
która obsługuje dane przerwanie (2-bajtowa RJMP dla ATmega48/88 lub 4-bajtowa JMP dla ATmega-
168/328). Po wystąpieniu przerwania mikrokontroler przerywa wykonywanie głównego programu, zapa-
miętuje na stosie adres następnej instrukcji, która miałabyć wykonana i wykonuje instrukcję skoku, która
znajduje się pod adresem danego wektora przerwania. Każda procedura obsługująca przerwanie musi
być zakończona instrukcją RETI. Po jej wykonaniu mikrokontroler przywraca ze stosu adres instrukcji,
która nie została wykonana z powodu wystąpienia przerwania, a następnie kontynuuje począwszy od
niej wykonywanie głównego programu.
Kod służący do inicjalizacji wskaźnika stosu, czyli rejestru SP (Stack Pointer) zawierającego adres koń-
ca pamięci SRAM mikrokontrolera, nie jest potrzebny dla ATmega48/88/168/328. W tych modelach war-
tość wskaźnika stosu jest ustawiana automatycznie, zaraz po włączeniu/resecie mikrokontrolera.
;Konfiguracja mikrokontrolera
ldi R16,$01 ;częstotliwość pracy mikrokontrolera (CLK): 1-20 [MHz]
mov R15,R16
ldi R16,$EF ;zatrzymanie zbędnych modułów (ADC, TWI, SPI, USART, TC0, TC1, TC2)
sts $64,R16 ;zapis rejestru PRR
ldi R16,$80 ;wyłączenie zasilania komparatora analogowego
sts $50,R16 ;zapis rejestru ACSR
Zapisywanie do rejestru R15 wartości, która odpowiada częstotliwości taktowania mikrokontrolera. Mo-
dele ATmega48/88/168/328 mogą pracować z częstotliwością 1-20 MHz, której odpowiada wartość $01-
$14. W tym przypadku mikrokontroler pracuje z zegarem 1 MHz, dlatego do rejestru R15 jest wpisywana
wartość $01. Jeśli mikrokontroler byłby taktowany inną częstotliwością, to należy wpisać jej właściwą
wartość. Jest to niezbędne do generowania prawidłowych opóźnień, podczas komunikacji mikrokontro-
lera z wyświetlaczem LCD.
Zostaje też zatrzymane taktowanie nieużywanych modułów mikrokontrolera: przetwornika analogowo-
cyfrowego (ADC), interfejsów do komunikacji szeregowej (TWI, SPI, USART) oraz liczników (TC0, TC1,
TC2), aby zmniejszyć pobór prądu. Dzieje się to po zapisaniu wartości $EF w rejestrze PRR (Power
Reduction Register). Dodatkowo jest również wyłączany komparator analogowy, po zapisaniu wartości
$80 w rejestrze ACSR (Analog Comparator control and Status Register).
;Obsługa wyświetlacza LCD 2x16 znaków (HD44780), z wyprowadzeniami podłączonymi w następujący sposób:
;R/W=GND, E=PD7, RS=PD6, D7=PD3, D6=PD2, D5=PD1, D4=PD0, D0-D3=NC (nie podłączone).
;Po włączeniu zasilania wyświetlacz LCD: zostaje wyczyszczony (kursor na pozycji 1 w 1 linii), działa
;w trybie 8-bitowym, może wyświetlać 1 linię znaków o rozmiarze 5x8 pikseli, wyświetlacz, kursor
;i jego miganie są wyłączone, kursor porusza się do przodu, przesuwanie (shift) jest wyłączone.
rcall LCDi ;inicjalizacja LCD (włączenie trybu 4-bitowego)
ldi R18,$28 ;ustawienie opcji: 2 linie, znaki 5x8 pikseli, interfejs 4-bit
rcall LCDwi ;zapis instrukcji do LCD
ldi R18,$0C ;włączenie LCD bez kursora
rcall LCDwi ;zapis instrukcji do LCD
;Instrukcje wyświetlacza LCD [czas ich wykonywania]:
; $01 - czyszczenie LCD i powrót kursora na pozycję 1 w 1 linii [1.52 ms]
; $02 - ustawienie kursora na pozycji 1 w 1 linii [1.52 ms]
; $04 - poruszanie kursora do tył, przesuwanie (shift) wyłączone [37 us]
; $05 - poruszanie kursora do tył, przesuwanie (shift) włączone [37 us]
; $06 - poruszanie kursora do przodu, przesuwanie (shift) wyłączone [37 us]
; $07 - poruszanie kursora do przodu, przesuwanie (shift) włączone [37 us]
; $08 - wyłączenie LCD [37 us]
; $0C - włączenie LCD bez kursora [37 us]
; $0E - włączenie LCD z kursorem [37 us]
; $0F - włączenie LCD z migającym kursorem [37 us]
; $10 - przesunięcie kursora w lewo [37 us]
; $14 - przesunięcie kursora w prawo [37 us]
; $18 - przesunięcie ekranu w lewo [37 us]
; $1C - przesunięcie ekranu w prawo [37 us]
; $80 - ustawienie adresu $00 dla DDRAM (kursor na pozycji 1 w 1 linii) [37 us]
; $C0 - ustawienie adresu $40 dla DDRAM (kursor na pozycji 1 w 2 linii) [37 us]
Inicjalizacja, ustawienie parametrów pracy i włączenie wyświetlacza LCD. Ponadto spis podstawowych
instrukcji, które są obsługiwane przez wyświetlacz. Poniższa tabela przedstawia rozmieszczenie znaków
na ekranie oraz ich adresy w pamięci DDRAM wyświetlacza LCD.
NUMER LINII | NUMER ZNAKU (POZYCJA KURSORA) |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
1 | $00 | $01 | $02 | $03 | $04 | $05 | $06 | $07 | $08 | $09 | $0A | $0B | $0C | $0D | $0E | $0F |
2 | $40 | $41 | $42 | $43 | $44 | $45 | $46 | $47 | $48 | $49 | $4A | $4B | $4C | $4D | $4E | $4F |
;Obsługa zworki J1
sbi PORTC,$05 ;ustawienie pinu PC5 jako wejścia z wysokim stanem (pull-up)
in R16,PINC ;odczyt stanu pinów PC0-PC6
andi R16,$20
brne Boot1 ;skok, jeśli na pinie PC5 jest stan wysoki (zworka J1=OFF)
;Zworka J1=ON (zwarta)
rcall LCDclr ;czyszczenie LCD
rcall FuseBit ;odczyt i wyświetlenie na LCD wartości fuse/lock bitów
Boot0: in R16,PINC ;odczyt stanu pinów PC0-PC6
andi R16,$20
breq Boot0 ;skok, jeśli na pinie PC5 jest stan niski (zworka J1=ON)
;Zworka J1=OFF (rozwarta)
Boot1: rcall LCDclr ;czyszczenie LCD
ldi ZL,LOW(Text1<<1)
ldi ZH,HIGH(Text1<<1)
rcall LCDwf ;wyświetlenie na LCD ciągu ASCIIZ z pamięci FLASH
ldi R18,$C0 ;ustawienie kursora na pozycji 1 w 2 linii
rcall LCDwi ;zapis instrukcji do LCD
rcall LCDwf ;wyświetlenie na LCD ciągu ASCIIZ z pamięci FLASH
Pin nr 28 (PC5) mikrokontrolera jest konfigurowany jako wejście, podłączone (podciągnięte) do plusa
napięcia zasilania przez wewnętrzny rezystor (pull-up). Jeśli po włączeniu/resecie systemu zworka J1
jest rozwarta (OFF), to na pinie PC5 panuje stan wysoki i program przechodzi do wyświetlania zwykłych
napisów testu wyświetlacza (rysunek 2). Natomiast jeśli zworka J1 będzie wtedy zwarta (ON), to na pinie
PC5 będzie stan niski i program wyświetli szesnastkowe wartości fuse/lock bitów, aktualnie ustawionych
w mikrokontrolerze (rysunek 1). Będą one pokazane w formacie "FL:LB:FE:FH". Pierwsza wartość (FL)
to młodszy bajt fuse bitów, druga to lock bity, trzecia to dodatkowe fuse bity, a czwarta to starszy bajt
fuse bitów. Wartości te będą widoczne aż do momentu rozwarcia (OFF) zworki J1. Wtedy zostaną już
wyświetlone zwykłe napisy testu wyświetlacza.
Rysunek 1 | | Rysunek 2 |
;Zapisywanie 8 znaków użytkownika do pamięci CGRAM wyświetlacza LCD
ldi ZL,LOW(Chars<<1)
ldi ZH,HIGH(Chars<<1) ;adres danych opisujących budowę 8 znaków użytkownika [64-bajty]
ldi R18,$40 ;ustawienie adresu $00 dla CGRAM (pierwszy znak)
rcall LCDwi ;zapis instrukcji do LCD
ldi R22,$40
LCDwfch: lpm R18,Z+
rcall LCDwc ;zapis znaku do LCD
dec R22
brne LCDwfch
;Wyświetlanie znaku użytkownika na LCD
ldi R18,$CF ;ustawienie kursora na pozycji 16 w 2 linii
rcall LCDwi ;zapis instrukcji do LCD
ldi R18,$05 ;znak użytkownika nr 5
rcall LCDwc ;wyświetlenie znaku na LCD
Zapis 8 znaków użytkownika (nr 0-7), o wymiarach 5x8 pikseli do pamięci CGRAM wyświetlacza LCD,
a następnie wyświetlenie znaku nr 5 na ostatniej pozycji w 2 linii. Po wykonaniu tego kodu zawartość
ekranu wyświetlacza LCD powinna wyglądać tak, jak na rysunku 3.
Każdy znak jest opisany za pomocą 8-bajtów, w których tylko młodszych 5-bitów opisuje mapę bitową
znaku, a najstarsze 3-bity nie są używane (wartość 0). Tak więc do opisania 8 znaków użytkownika są
potrzebne 64-bajty, które znajdują się pod etykietą "Chars" w pamięci FLASH mikrokontrolera.
Sposób zapisu mapy bitowej przykładowego znaku użytkownika nr 5, przedstawia poniższa tabela.
Zwykle ostatnią (dolną) linię znaku pozostawia się pustą, bo na niej może być wyświetlany migający
kursor, jeśli jest włączony.
ZNAK | BAJTY MAPY BITOWEJ |
DWÓJKOWO | DZIESIĘTNIE |
| 00010001 00001110 00001000 00001110 00000010 00001110 00010001 00000000 | 17 14 8 14 2 14 17 0 |
| | Rysunek 3 |
;Inicjalizacja rejestrów
clr XL
clr XH
movw R22,XL
movw R24,XL
inc XL
Ustawienie początkowych wartości rejestrów, które będą używane w głównej pętli programu.
;Główna pętla programu
Loop: rcall Add3216 ;dodawanie słowa do wartości 32-bitowej
ldi ZL,LOW(sbuf)
ldi ZH,HIGH(sbuf) ;adres bufora wyjściowego w pamięci SRAM
mov R16,R22 ;najstarszy bajt 32-bitowej wartości
rcall ConBH ;konwersja bajtu do systemu HEX-ASCIIZ
mov R16,R23
rcall ConBH ;konwersja bajtu do systemu HEX-ASCIIZ
mov R16,R24
rcall ConBH ;konwersja bajtu do systemu HEX-ASCIIZ
mov R16,R25 ;najmłodszy bajt 32-bitowej wartości
rcall ConBH ;konwersja bajtu do systemu HEX-ASCIIZ
sbiw ZL,$08
ldi R18,$C6 ;ustawienie kursora na pozycji 7 w 2 linii
rcall LCDwi ;zapis instrukcji do LCD
rcall LCDws ;wyświetlenie na LCD ciągu ASCIIZ z pamięci SRAM
rjmp Loop
Główna pętla programu, która jest wykonywana bez przerwy. Z każdym obiegiem pętli, 32-bitowa war-
tość zapisana w rejestrach [R22:R23:R24:R25] jest zwiększana o 16-bitową wartość $0001 z rejestrów
[XH:XL]. Następnie każdy bajt tej zwiększonej wartości jest zamieniany na szesnastkowy ciąg ASCIIZ
i zapisywany do bufora w pamięci SRAM mikrokontrolera. Uzyskany w ten sposób 8-znakowy ciąg
ASCIIZ jest wyświetlany, począwszy od pozycji nr 7 w 2 linii. Instrukcja skoku RJMP zamyka pętlę.
Dzięki temu podczas pracy programu na wyświetlaczu LCD można zaobserwować, szybko zwiększającą
się 32-bitową wartość szesnastkową. Przykładowa zawartość ekranu wyświetlacza LCD, podczas wyko-
nywania głównej pętli programu jest przedstawiona na rysunku 4.
Rysunek 4
;Dodawanie słowa do wartości 32-bitowej: [R22:R23:R24:R25] + [XH:XL] = [R22:R23:R24:R25]
Add3216: clr R2
add R25,XL ;najmłodszy bajt wartości/wyniku, młodszy bajt słowa
adc R24,XH ;starszy bajt słowa
adc R23,R2
adc R22,R2 ;najstarszy bajt wartości/wyniku
ret ;C=1 jeśli wynik >4294967295
Procedura dodaje 16-bitowe słowo z rejestrów [XH:XL] do 32-bitowej wartości, zapisanej w rejestrach
[R22:R23:R24:R25].
;Zapis szesnastkowej wartości bajtu do pamięci SRAM w postaci ciągu ASCIIZ: "NN"
ConBH: ldi R17,$02
ConBH0: swap R16 ;bajt do konwersji
mov R18,R16
andi R18,$0F
subi R18,$D0
cpi R18,$3A
brlt ConBH1
subi R18,$F9 ;subi R18,$D9 - małe litery (a-f)
ConBH1: st Z+,R18
dec R17
brne ConBH0
st Z,R17 ;wyjście danych
ret
Procedura konwertuje bajt z rejestru R16 do postaci szesnastkowego 2-znakowego ciągu ASCIIZ,
zapisanego do bufora w pamięci SRAM mikrokontrolera.
;Zapis szesnastkowych wartości fuse/lock bitów do pamięci SRAM w postaci
;ciągu ASCIIZ: "FL:LB:FE:FH" i wyświetlenie go na wyświetlaczu LCD.
FuseBit: ldi YL,LOW(sbuf)
ldi YH,HIGH(sbuf) ;adres wyjścia danych
clr ZL
clr ZH
ldi R18,$3A
FuseBit0: lds R16,$57 ;odczyt rejestru SPMCSR
ori R16,$09 ;ustawienie bitów BLBSET i SELFPRGEN
sts $57,R16 ;zapis rejestru SPMCSR
lpm R2,Z+ ;odczyt fuse/lock bitów
;W zależności od wartości adresu [ZH:ZL] są odczytywane:
; $0000 - Fuse bits Low byte (FL)
; $0001 - Lock Bits (LB)
; $0002 - Fuse bits Extended byte (FE)
; $0003 - Fuse bits High byte (FH)
ldi R16,$02
FuseBit1: swap R2
mov R17,R2
andi R17,$0F
subi R17,$D0
cpi R17,$3A
brlt FuseBit2
subi R17,$F9
FuseBit2: st Y+,R17
dec R16
brne FuseBit1
st Y+,R18
cpi ZL,$04
brne FuseBit0
st -Y,R16
;Wyświetlanie wartości fuse/lock bitów na LCD
ldi ZL,LOW(Text0<<1)
ldi ZH,HIGH(Text0<<1)
rcall LCDwf ;wyświetlenie na LCD ciągu ASCIIZ z pamięci FLASH
ldi R18,$C0 ;ustawienie kursora na pozycji 1 w 2 linii
rcall LCDwi ;zapis instrukcji do LCD
ldi ZL,LOW(sbuf)
ldi ZH,HIGH(sbuf)
rcall LCDws ;wyświetlenie na LCD ciągu ASCIIZ z pamięci SRAM
ret
Procedura odczytuje aktualnie ustawione wartości fuse/lock bitów mikrokontrolera, zapisuje je do
pamięci SRAM w postaci 11-znakowego ciągu ASCIIZ, zawierającego cztery szesnastkowe wartości
oddzielone dwukropkami, a następnie wyświetla ten ciąg na LCD.
;Inicjalizacja wyświetlacza LCD
LCDi: ldi R16,$CF
out DDRD,R16 ;ustawienie pinów PD0-PD3/PD6-PD7 jako wyjść, PD4-PD5 jako wejść
clr R16 ;E=0, RS=0
out PORTD,R16 ;wyzerowanie wyjść PD0-PD3/PD6-PD7
;Czekanie na ustabilizowanie się napięcia zasilania
ldi R16,$C8 ;opóźnienie 20 ms
rcall Wait ;pętla opóźniająca
rcall Wait ;pętla opóźniająca
;Wysłanie trzech instrukcji $30 do LCD
ldi R18,$03
LCDi0: ldi R16,$83
out PORTD,R16 ;E=1, RS=0
;(wait 4 CL)
cbi PORTD,$07 ;E=0, RS=0
ldi R16,$32 ;opóźnienie 5 ms
rcall Wait ;pętla opóźniająca
dec R18
brne LCDi0
;Wysłanie instrukcji $20 do LCD (włączenie trybu 4-bitowego)
ldi R16,$82
out PORTD,R16 ;E=1, RS=0
;(wait 4 CL)
cbi PORTD,$07 ;E=0, RS=0
ldi R16,$0A ;opóźnienie 1 ms
rcall Wait ;pętla opóźniająca
ret
Procedura konfiguruje port D mikrokontrolera, inicjalizuje wyświetlacz LCD i włącza jego 4-bitowy tryb
komunikacji. W miejscach, w których znajduje się komentarz ";(wait 4 CL)" powinny być umieszczone
instrukcje, powodujące opóźnienie o 4 cykle zegara taktującego mikrokontroler (np. 4 instrukcje NOP).
W praktyce okazały się one zbędne, przynajmniej w przypadku mojego wyświetlacza.
;Zapis instrukcji do wyświetlacza LCD (tryb 4-bitowy)
LCDwi: ldi R20,$80 ;E=1, RS=0
rjmp LCDwc0
;Zapis znaku do wyświetlacza LCD (tryb 4-bitowy)
LCDwc: ldi R20,$C0 ;E=1, RS=1
LCDwc0: ldi R21,$02
LCDwc1: swap R18 ;bajt do wysłania
mov R19,R18
andi R19,$0F
andi R20,$F0 ;E=1, RS=początkowa wartość
add R20,R19
out PORTD,R20 ;wysłanie 4-bitów do LCD (najpierw starsze, później młodsze)
;(wait 4 CL)
cbi PORTD,$07 ;E=0, RS=początkowa wartość
ldi R16,$01 ;opóźnienie 100 us
rcall Wait ;pętla opóźniająca
dec R21
brne LCDwc1
ret
Procedura w zależności od wywołania, zapisuje instrukcję lub znak do wyświetlacza LCD. W miejscu,
w którym znajduje się komentarz ";(wait 4 CL)" powinny być umieszczone instrukcje, powodujące opóź-
nienie o 4 cykle zegara taktującego mikrokontroler (np. 4 instrukcje NOP). W praktyce okazały się one
zbędne, przynajmniej w przypadku mojego wyświetlacza.
;Czyszczenie wyświetlacza LCD i powrót kursora na pozycję 1 w 1 linii
LCDclr: ldi R18,$01 ;czyszczenie LCD i powrót kursora
rcall LCDwi ;zapis instrukcji do LCD
ldi R16,$10 ;opóźnienie 1.6 ms
rcall Wait ;pętla opóźniająca
ret
Procedura zapisuje instrukcję $01 do wyświetlacza LCD, która powoduje wyczyszczenie zawartości jego
ekranu i powrót kursora na pierwszą pozycję w 1 linii. Następnie procedura czeka przez ok. 1.5 ms czyli
tyle czasu, ile sterownik wyświetlacza potrzebuje na wykonanie tej instrukcji.
;Zapis ciągu ASCIIZ z pamięci SRAM do wyświetlacza LCD (tryb 4-bitowy)
LCDws0: rcall LCDwc ;zapis znaku do LCD
LCDws: ld R18,Z+ ;odczyt znaku z pamięci SRAM
tst R18
brne LCDws0
ret
Procedura wyświetla na LCD ciąg ASCIIZ, zapisany w pamięci SRAM mikrokontrolera.
;Zapis ciągu ASCIIZ z pamięci FLASH do wyświetlacza LCD (tryb 4-bitowy)
LCDwf0: rcall LCDwc ;zapis znaku do LCD
LCDwf: lpm R18,Z+ ;odczyt znaku z pamięci FLASH
tst R18
brne LCDwf0
ret
Procedura wyświetla na LCD ciąg ASCIIZ, zapisany w pamięci FLASH mikrokontrolera.
;Pętla opóźniająca o zadany czas: 100u - 25.5m [s]
Wait: mov R2,R15 ;R15 (CLK) = częstotliwość pracy mikrokontrolera: $01-$14 (1-20 MHz)
ldi R17,$19
mul R16,R17 ;R16 (DLY) = wartość opóźnienia: $01-$FF (100us-25.5ms)
Wait0: movw YL,R0
Wait1: sbiw YL,$01
brne Wait1
dec R2
brne Wait0
ret
Procedura generuje opóźnienie czasowe (100us - 25.5ms), zależne od wartości rejestru R16. Wygene-
rowane opóźnienie będzie miało prawidłowy czas tylko wtedy, gdy rejestr R15 będzie zawierał wartość
częstotliwości, z jaką aktualnie pracuje mikrokontroler.
;Napisy dla wyświetlacza LCD
Text0: .db "Fuse/lock bits:",0
Text1: .db "*** LCD test ***",0,"Count:",0
Napisy pokazywane na wyświetlaczu LCD, umieszczone w pamięci FLASH mikrokontrolera.
;Znaki użytkownika dla wyświetlacza LCD
Chars: .db 17,14,10,10,10,14,17,0 ;0
.db 17,4,12,4,4,14,17,0 ;1
.db 17,14,2,14,8,14,17,0 ;2
.db 17,14,2,6,2,14,17,0 ;3
.db 17,10,10,14,2,2,17,0 ;4
.db 17,14,8,14,2,14,17,0 ;5
.db 17,14,8,14,10,14,17,0 ;6
.db 17,14,10,2,2,2,17,0 ;7
Tablica umieszczona w pamięci FLASH mikrokontrolera, zawierająca 64-bajty opisujące mapy bitowe
8 znaków użytkownika, które są zapisywane do pamięci CGRAM wyświetlacza LCD.
.dseg ;pamięć danych (SRAM)
.org $0100
sbuf: .byte 12 ;rezerwuje N-bajtów w pamięci SRAM
Dyrektywa ".dseg" oznacza blok pamięci danych (SRAM) mikrokontrolera, a ".org $0100" określa adres
jej początku. Następnie znajduje się etykieta z nazwą bufora dla danych wyjściowych/wejściowych oraz
opcjonalna dyrektywa ".byte", która mówi kompilatorowi ile bajtów pamięci SRAM w tym buforze, będzie
używanych (zapisywanych) przez program.
Poniższy rysunek przedstawia budowę dużych cyfr (3x2 znaki), które mogą być pokazane na standar-
dowym wyświetlaczu LCD 2x16. Cyfry te składają się maksymalnie z 8 znaków użytkownika oraz pus-
tego znaku spacji ($20). Dwie pierwsze czcionki wykorzystują też całkowicie zapełniony znak ($FF),
który może nie być dostępny w każdym wyświetlaczu. Pod czcionkami cyfr znajdują się różne znaki
użytkownika, np. stosowane do wyświetlania bargrafów, czy sygnalizowania stanu naładowania baterii
urządzenia. Program do generowania dużych cyfr (3x2 znaki) jest opisany na tej stronie.