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 LCDJeś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 LCDwfchZapis 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 LoopUstawienie 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 retProcedura 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