![]() |
Wyświetlacz LCD - duże cyfry | ![]() |
Kompilacja |

.include "m48def.inc" ;definicje dla ATmega48
;.include "m88def.inc" ;definicje dla ATmega88
;.include "m168def.inc" ;definicje dla ATmega168
;.include "m328def.inc" ;definicje dla ATmega328
.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
;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
sbi PORTC,$05 ;ustawienie pinu PC5 jako wejścia z wysokim stanem (pull-up)
;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]
;Obsługa zworki J1 - wyświetlanie wartości fuse/lock bitów
sbic PINC,$05 ;odczyt stanu pinu PC5
rjmp 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: sbis PINC,$05 ;odczyt stanu pinu PC5
rjmp Boot0 ;skok, jeśli na pinie PC5 jest stan niski (zworka J1=ON)
;Zworka J1=OFF (rozwarta)
Boot1: rcall LCDclr ;czyszczenie LCD
Jeśli po włączeniu/resecie systemu zworka J1 jest zwarta (ON), to na pinie PC5 panuje stan niski i pro-
;Zapisywanie 8 znaków użytkownika do pamięci CGRAM wyświetlacza LCD
ldi ZL,LOW(Chrs3<<1) ;wybór kroju dużych cyfr (3x2 znaki): Chrs0/Chrs1/Chrs2/Chrs3
ldi ZH,HIGH(Chrs3<<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
Zapis 8 znaków użytkownika (nr 0-7), o wymiarach 5x8 pikseli do pamięci CGRAM wyświetlacza LCD,
;Inicjalizacja rejestrów
ser XL
ser XH
movw R4,ZL ;adres danych opisujących budowę dużych cyfr (3x2 znaki) [60-bajtów]
;Główna pętla programu
Loop: adiw XL,$01 ;zwiększenie 16-bitowej wartości o 1
movw R0,XL
rcall Con16D ;konwersja 16-bitowej wartości do postaci dziesiętnej
movw XL,R0
ldi R23,$80 ;adres znaku 1 w 1 linii LCD
ldi R22,$04
Loop0: ld R16,Y+ ;odczyt kolejnej cyfry ($00-$09) z pamięci SRAM
ldi R17,$06
mul R16,R17 ;mnożenie odczytanej cyfry przez 6
movw ZL,R4
add ZL,R0
adc ZH,R1 ;dodanie wyniku mnożenia do wartości adresu, wskazującego na początek
;struktury w pamięci FLASH, która opisuje budowę poszczególnych cyfr
;o rozmiarze 3x2 znaki.
mov R18,R23 ;ustawienie kursora na początku kolejnej cyfry w 1 linii LCD
rcall LCDwi ;zapis instrukcji do LCD
lpm R18,Z+ ;odczyt znaku z pamięci FLASH
rcall LCDwc ;zapis znaku do LCD
lpm R18,Z+ ;odczyt znaku z pamięci FLASH
rcall LCDwc ;zapis znaku do LCD
lpm R18,Z+ ;odczyt znaku z pamięci FLASH
rcall LCDwc ;zapis znaku do LCD
mov R18,R23
ori R18,$40 ;ustawienie kursora na początku kolejnej cyfry w 2 linii LCD
rcall LCDwi ;zapis instrukcji do LCD
lpm R18,Z+ ;odczyt znaku z pamięci FLASH
rcall LCDwc ;zapis znaku do LCD
lpm R18,Z+ ;odczyt znaku z pamięci FLASH
rcall LCDwc ;zapis znaku do LCD
lpm R18,Z+ ;odczyt znaku z pamięci FLASH
rcall LCDwc ;zapis znaku do LCD
subi R23,$FC ;zwiększenie adresu o 4 - przerwa między cyframi
;subi R23,$FD ;zwiększenie adresu o 3 - brak przerwy między cyframi
dec R22
brne Loop0
ldi R16,$FF ;opóźnienie 25.5 ms
rcall Wait ;pętla opóźniająca
rcall Wait ;pętla opóźniająca
rcall Wait ;pętla opóźniająca
rcall Wait ;pętla opóźniająca
rjmp Loop
Ustawienie początkowych wartości rejestrów i główna pętla programu, która jest wykonywana bez![]() Rysunek 3 | ![]() Rysunek 4 |
;Konwersja 16-bitów do systemu dziesiętnego: [XH:XL] => [B4:B3:B2:B1], gdzie:
;[B1] - bajt z najmniej znaczącą cyfrą wyniku (B1-B4 = $00-$09).
Con16D: ldi YL,LOW(sbuf)
ldi YH,HIGH(sbuf) ;adres wyjścia danych
adiw YL,$04
ldi R17,$04 ;maksymalna liczba cyfr
Con16D0: ldi R18,$10 ;liczba bitów do konwersji
sub R16,R16
Con16D1: rol R16
cpi R16,$0A
brcs Con16D2
subi R16,$0A
sec
rjmp Con16D3
Con16D2: clc
Con16D3: rol XL ;młodszy bajt do konwersji
rol XH ;starszy bajt do konwersji
dec R18
brpl Con16D1
st -Y,R16
dec R17
brne Con16D0
ret
Procedura konwertuje 16-bitowe słowo z rejestrów [XH:XL] do postaci 4-bajtowego ciągu dziesiętnego
;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(Text<<1)
ldi ZH,HIGH(Text<<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
;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
;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
;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
;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
;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
;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 R24,R0
Wait1: sbiw R24,$01
brne Wait1
dec R2
brne Wait0
ret
;Napisy dla wyświetlacza LCD
Text: .db "Fuse/lock bits:",0
;Znaki użytkownika dla wyświetlacza LCD, służące do wyświetlania dużych cyfr o rozmiarze 3x2 znaki
;Duże cyfry proste z przerwą (4 znaki użytkownika + całkowicie zapełniony znak $FF)
Chrs0: .db 31,31,31,0,0,0,0,0 ;0
.db 0,0,0,0,0,31,31,31 ;1
.db 31,31,31,0,0,0,31,31 ;2
.db 31,0,0,0,0,31,31,31 ;3
.db 0,0,0,0,0,0,0,0 ;4
.db 0,0,0,0,0,0,0,0 ;5
.db 0,0,0,0,0,0,0,0 ;6
.db 0,0,0,0,0,0,0,0 ;7
;Budowa poszczególnych cyfr
.db 255,0,255,255,1,255 ;0
.db 0,255,32,1,255,1 ;1
.db 2,2,255,255,3,3 ;2
.db 0,2,255,1,3,255 ;3
.db 255,1,255,32,32,255 ;4
.db 255,2,2,3,3,255 ;5
.db 255,2,2,255,3,255 ;6
.db 255,0,255,32,32,255 ;7
.db 255,2,255,255,3,255 ;8
.db 255,2,255,3,3,255 ;9
;Duże cyfry zaokrąglone z przerwą (8 znaków użytkownika + całkowicie zapełniony znak $FF)
Chrs1: .db 31,31,31,0,0,0,0,0 ;0
.db 0,0,0,0,0,31,31,31 ;1
.db 31,31,31,0,0,0,31,31 ;2
.db 31,0,0,0,0,31,31,31 ;3
.db 7,15,31,31,31,31,31,31 ;4
.db 28,30,31,31,31,31,31,31 ;5
.db 31,31,31,31,31,31,15,7 ;6
.db 31,31,31,31,31,31,30,28 ;7
;Budowa poszczególnych cyfr
.db 4,0,5,6,1,7 ;0
.db 0,5,32,1,255,1 ;1
.db 2,2,5,255,3,3 ;2
.db 0,2,5,1,3,7 ;3
.db 6,1,255,32,32,255 ;4
.db 255,2,2,3,3,7 ;5
.db 4,2,2,6,3,7 ;6
.db 4,0,5,32,32,255 ;7
.db 4,2,5,6,3,7 ;8
.db 4,2,5,3,3,7 ;9
;Duże cyfry proste bez przerwy (8 znaków użytkownika)
Chrs2: .db 30,30,30,30,30,30,30,30 ;0
.db 15,15,15,15,15,15,15,15 ;1
.db 31,31,0,0,0,0,0,0 ;2
.db 0,0,0,0,0,0,31,31 ;3
.db 0,0,0,0,0,0,15,15 ;4
.db 31,31,0,0,0,0,31,31 ;5
.db 30,30,0,0,0,0,30,30 ;6
.db 15,15,0,0,0,0,15,15 ;7
;Budowa poszczególnych cyfr
.db 1,2,0,1,3,0 ;0
.db 32,1,32,32,1,32 ;1
.db 7,5,0,1,3,3 ;2
.db 7,5,0,4,3,0 ;3
.db 1,3,0,32,32,0 ;4
.db 1,5,6,4,3,0 ;5
.db 1,5,6,1,3,0 ;6
.db 1,2,0,32,32,0 ;7
.db 1,5,0,1,3,0 ;8
.db 1,5,0,4,3,0 ;9
;Duże cyfry zaokrąglone bez przerwy (8 znaków użytkownika)
Chrs3: .db 28,30,30,30,30,30,30,28 ;0
.db 7,15,15,15,15,15,15,7 ;1
.db 31,31,0,0,0,0,0,0 ;2
.db 0,0,0,0,0,0,31,31 ;3
.db 0,0,0,0,0,0,3,7 ;4
.db 31,31,0,0,0,0,31,31 ;5
.db 28,24,0,0,0,0,24,28 ;6
.db 7,3,0,0,0,0,3,7 ;7
;Budowa poszczególnych cyfr
.db 1,2,0,1,3,0 ;0
.db 32,1,32,32,1,32 ;1
.db 7,5,0,1,3,3 ;2
.db 7,5,0,4,3,0 ;3
.db 1,3,0,32,32,0 ;4
.db 1,5,6,4,3,0 ;5
.db 1,5,6,1,3,0 ;6
.db 1,2,0,32,32,0 ;7
.db 1,5,0,1,3,0 ;8
.db 1,5,0,4,3,0 ;9
.dseg ;pamięć danych (SRAM)
.org $0100
sbuf: .byte 12 ;rezerwuje N-bajtów w pamięci SRAM