;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; LCD-Routinen ;; ;; ============ ;; ;; (c)andreas-s@web.de ;; ;; ;; ;; bearbeitet von Johannes Fechner, ;; ;; https://www.mikrocontroller.net/user/show/emitterfolger ;; ;; * sämtliche veränderte Register außer SREG werden ;; ;; gerettet (einschließlich Parameter) ;; ;; * unbenutzte Pins am DB-Port werden nicht beeinflusst ;; ;; * Anschluss von DB4..7 optional auch an Pins 4..7 ;; ;; * lcd_data und lcd_command zu lcd_write zusammengefasst ;; ;; * Busy-Flag-Abfrage (optional) ;; ;; Version 2022-12-06 ;; ;; ;; ;; 4-Bit-Interface ;; ;; DB4..7, RS und E müssen ans selbe µC-Port ;; ;; ;; ;; Register für Argumente: temp0, temp1 ;; ;; (müssen im einbindenden Hauptprogramm ;; ;; definiert werden.) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; -------------- für Testzwecke ---------------- .ifndef temp0 .def temp0 = r20 .endif .ifndef temp1 .def temp1 = r21 .endif .ifndef XTAL .equ XTAL = 4000000 .endif ; ---------------------------------------------- .def temp2 = r22 .def temp3 = r23 ; Port für Datenbus DB4..DB7 festlegen .equ LCD_DB_PORT = PORTD .equ LCD_DB_DDR = DDRD .equ LCD_DB_PIN = PIND .equ LCD_DB_03 = 1 ; definieren, falls Anschluss von DB4..7 an Pins 0..3 ; RS und E an gleichem Port wie die Daten DB4..DB7 .equ LCD_RS = PD2 .equ LCD_E = PD3 ; Port und Pin für R/W festlegen (nur bei Benutzung des Busy-Flags erforderl.) .equ LCD_RW_PORT = PORTB .equ LCD_RW_DDR = DDRB .equ LCD_RW = PB0 ; .equ LCD_BUSY_FLAG = 1 ; definieren, falls statt Warteschleifen das Busy-Flag ; abgefragt werden soll ; === Routine lcd_write === ; Sendet ein Byte an das LCD. ; Datenbyte/Befehl muss in temp1 liegen. ; temp0 == 0: Befehl; temp0 == 1: Daten. lcd_write: push temp1 push temp2 push temp3 mov temp2, temp1 ; Original zur Verarbeitung kopieren ; Vorbereitung zum Ausgeben des oberen Nibbles andi temp2, 0xF0 ; unteres Nibble löschen .ifdef LCD_DB_03 swap temp2 ; Nibbles vertauschen .endif sbrc temp0, 0 ; falls temp0.0 == 1, sbr temp2, 1< Eingänge in temp1, LCD_DB_DDR .ifdef LCD_DB_03 andi temp1, ~0x0F .else andi temp1, ~0xF0 .endif out LCD_DB_DDR, temp1 cbi LCD_DB_PORT, LCD_RS ; RS löschen sbi LCD_RW_PORT, LCD_RW ; R/W setzen lcd_busy_loop: rcall delay5us ; ein paar Takte warten sbi LCD_DB_PORT, LCD_E ; E setzen rcall delay5us ; dem LCD-Controller etwas Zeit geben in temp1, LCD_DB_PIN ; oberes Nibble lesen (BF == DB7) cbi LCD_DB_PORT, LCD_E ; E löschen rcall delay5us ; Pause bis zur nächsten Enable-Flanke rcall lcd_enable ; zweites Nibble ignorieren; ; falls im 8-Bit-Modus während ; Initialisierung wird einfach eine ; BF:AC-Antwort ignoriert ; wiederholen, solange Busy-Flag high ist .ifdef LCD_DB_03 sbrc temp1, 3 .else sbrc temp1, 7 .endif rjmp lcd_busy_loop ; LCD-Controller ist wieder bereit cbi LCD_RW_PORT, LCD_RW ; R/W wieder löschen ; LCD-DB -> wieder Ausgänge in temp1, LCD_DB_DDR .ifdef LCD_DB_03 ori temp1, 0x0F .else ori temp1, 0xF0 .endif out LCD_DB_DDR, temp1 pop temp1 ret ; === Routine lcd_enable === ; Erzeugt einen High-Low-Puls am Enable-Pin lcd_enable: sbi LCD_DB_PORT, LCD_E ; Enable high rcall delay5us cbi LCD_DB_PORT, LCD_E ; Enable wieder low ret ; === Routine delay5us === ; ca. 5 µs Pause (nach E-Flanken bei BF-Abfrage) delay5us: push temp1 ldi temp1, (XTAL * 5 / 3) / 1000000 delay5us_loop: dec temp1 brne delay5us_loop pop temp1 ret ; === Routine delay50us === ; ca. 50 µs Pause (nach jeder Übertragung ohne BF-Abfrage) delay50us: push temp1 ldi temp1, (XTAL * 50 / 3) / 1000000 delay50us_loop: dec temp1 brne delay50us_loop pop temp1 ret ; === Routine delay5ms === ; Längere Pause von ca. 5 ms (nach manchen Befehlen ohne BF-Abfrage) delay5ms: push temp1 push temp2 ldi temp1, (XTAL * 5 / 607) / 1000 delay5ms_loop0: ldi temp2, 0xC9 delay5ms_loop1: dec temp2 brne delay5ms_loop1 dec temp1 brne delay5ms_loop0 pop temp2 pop temp1 ret ; === Routine lcd_init === ; LCD-Initialisierung: muss vor allen anderen LCD-Routinen aufgerufen werden lcd_init: push temp1 push temp3 ; LCD-DB, -E, -RS -> Ausgänge in temp1, LCD_DB_DDR .ifdef LCD_DB_03 ori temp1, (1< Ausgang in temp1, LCD_RW_DDR ori temp1, 1<