; ; Lcd - Routinen ; Controler: M50530 ; 4-bit Interface ; ; Arno Schweißinger ; .include "m8def.inc" .def temp1 = r16 .def temp2 = r17 .def temp3 = r18 ;--------- LCD begin ----------------------------- .equ LCD =PORTC ; PC0-PC3: sind LCD-Datenltg .equ OC1 =PINC4 ; PC4: Cursor adress, display start adress .equ OC2 =PINC5 ; PC5: RAM Data .equ LCD_E =PORTB .equ Enable =PINB5 ; PB5: LCD enable ldi temp1,0b11111111 ; Alle Bits von setzen (alle Pins auf Ausgang)... out DDRC, temp1 ; Inhalt von temp1 ins IO-Register DDRC ausgeben in temp1, DDRB sbr temp1, 1 << Enable ; LCD-E: als Ausgang setzen out DDRB, temp1 ;--------- LCD ende ----------------------------- ldi temp1, LOW(RAMEND) ; Init Stack out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1 rcall lcd_init ldi temp1, $01 ; Zeile ldi temp2, $01 ; Spalte rcall lcd_cursorXY ldi ZL,LOW(Text_out*2) ldi ZH,HIGH(Text_out*2) lese_db: lpm tst R0 breq lese_ende mov temp1, R0 rcall lcd_char adiw ZL,1 rjmp lese_db lese_ende: ende: ;Endlosschleife rjmp ende Text_out: .db "123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H123456789I123456789J123456789K123456789L123456789M123456789N123456789O123456789P123456789Q123456789R",0 ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; LCD-Routinen ;; ;; ============ ;; ;; M50530 ;; ;; ;; ;; 4bit-Interface ;; ;; DB4-DB7: PC0-PC3 ;; ;; OC1: PC4 ;; ;; OC2: PC5 ;; ;; EX: PD4 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;sendet ein Zeichen an das LCD lcd_char: mov temp2, temp1 ;"Sicherungskopie" für ;die Übertragung des 2.Nibbles swap temp1 ;Vertauschen andi temp1, 0b00001111 ;oberes Nibble auf Null setzen sbr temp1, 1 << OC2 ;entspricht 0bxx1xxxxx (OC2 high) out LCD, temp1 ;ausgeben rcall lcd_enable ;Enable-Routine aufrufen ;2. Nibble, kein swap da es schon ;an der richtigen stelle ist andi temp2, 0b00001111 ;obere Hälfte auf Null setzen sbr temp2, 1 << OC2 ;entspricht 0b1xxxxx (OC2 high) out LCD, temp2 ;ausgeben rcall lcd_enable ;Enable-Routine aufrufen rcall delay50us ;Delay-Routine aufrufen ret ;zurück zum Hauptprogramm ;sendet einen Befehl an das LCD lcd_command: ;wie lcd_data, nur ohne OC2 zu setzen mov temp2, temp1 swap temp1 andi temp1, 0b00001111 out LCD, temp1 rcall lcd_enable andi temp2, 0b00001111 out LCD, temp2 rcall lcd_enable rcall delay50us ret ;erzeugt den Enable-Puls lcd_enable: sbi LCD_E, Enable ;Enable high nop ;3 Taktzyklen warten cbi LCD_E, Enable ;Enable wieder low ret ;Und wieder zurück ;Pause nach jeder Übertragung ;Bei 4MHz: ;1 Takt = 250ns delay50us: push temp1 ;50us Pause ldi temp1,$42 ;$42 delay50us_:dec temp1 ;1 Tackt brne delay50us_ ;2 Tackte pop temp1 ret ;wieder zurück ( $FF=190us ) ;Längere Pause für manche Befehle delay5ms: ;5ms Pause push temp1 push temp2 ldi temp1, $21 ;$21 WGLOOP0: ldi temp2, $c9 ;$C9 WGLOOP1: dec temp2 brne WGLOOP1 dec temp1 brne WGLOOP0 pop temp2 pop temp1 ret ;wieder zurück ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden lcd_init: ldi temp3,10 powerupwait: rcall delay5ms dec temp3 brne powerupwait ldi temp1, 0b11011000 ;set function mode (SF) rcall lcd_command ;4bit-Modus einstellen 11 -4/8bit-FONT-2xDUTY-2xRAM ldi temp1, 0b01010000 ;set entry mode (SE) rcall lcd_command ;Cursor selbst setzen ldi temp1, 0b00110011 ;set display mode (SD) rcall lcd_command ;Display ein, Cursor nicht anzeigen rcall lcd_clear ret ; setzt den Cursor ; Temp1 = Spalte ; Temp2 = Zeile ; in temp1 steht die neue Position des Cusors ; Zeilen: array[1..8] of Integer = ($00,$40,$80,$C0,$18,$58,$98,$D8); Aus Pascalprogramm kopiert lcd_cursorXY: push ZL push ZH ldi ZL,LOW(CursorPos*2-1) ;Adresse ermitteln ldi ZH,HIGH(CursorPos*2-1) ;eine Reihe abziehe (beginnt mit Null) add zl,temp1 ;Um Temp1 Zeile erhöhen lpm ;Cursorposition holen mov temp1, R0 ;Ergebnis nach Temp1 kopieren pop ZH pop ZL add temp1, temp2 ;CursorPosition Reihe addieren dec temp1 ;ein Feld zurück, Felder beginnen mit Null lcd_cursor: mov temp2, temp1 ;"Sicherungskopie" für ;die Übertragung des 2.Nibbles swap temp1 ;Vertauschen andi temp1, 0b00001111 ;oberes Nibble auf Null setzen sbr temp1, 1 << OC1 ;entspricht 0bx1xxxxxx (OC1 high) sbr temp1, 1 << OC2 ;entspricht 0bxx1xxxxx (OC2 high) out LCD, temp1 ;ausgeben rcall lcd_enable ;Enable-Routine aufrufen ;2. Nibble, kein swap da es schon ;an der richtigen stelle ist andi temp2, 0b00001111 ;obere Hälfte auf Null setzen sbr temp2, 1 << OC1 ;entspricht 0bx1xxxxxx (OC1 high) sbr temp2, 1 << OC2 ;entspricht 0bxx1xxxxx (OC2 high) out LCD, temp2 ;ausgeben rcall lcd_enable ;Enable-Routine aufrufen rcall delay50us ;Delay-Routine aufrufen ret ;zurück zum Hauptprogramm CursorPos: .db $00,$40,$80,$C0,$18,$58,$98,$D8 ; Sendet den Befehl zum löschen des Displays lcd_clear: ldi temp1, 0b00000001 ;Display löschen rcall lcd_command ;clear RAM, Cursor home rcall delay5ms ret ;----------------------------------- Ende Dispay ----------------------------------------