PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Frage zu LCD



Stefan_84
14.07.2008, 14:06
Guten Tag!
Wie schon in einem früheren Thread erwähnt möchte ich meine Schaltung mit einem LC-Display austatten um Akkuspannung, Zeit usw. abzulesen.
Es handelt sich dabei um ein 2Zeiliges Display mit je 16 Zeichen. Die Datenleitungen hängen auf PortC, die Steuerleitungen auf PortE (E0=Ena, E1=R/W, E2=RS)

Hab jetzt mal ein Testprogramm gemacht damit ich den Umgang mit dem Display lernen kann. Das folgende Programm funktioniert und gibt auf dem Display "AB" aus.


;************************************************* ****************************
;*
;* DATEINAME : disp1.asm
;* TITEL : Display ansteuern
;* DATUM : 14.7.08
;* AUTOR : STK
;* VERSION : 1.0
;*
;*
;************************************************* ****************************

.include "m8515def.inc"

;--KONSTANTENDEKLARATION---------------------------------------------
; status register bits
.equ CarryFlag = 0
.equ ZeroFlag = 1
.equ NegativeFlag = 2
.equ TwosFlag = 3
.equ SignFlag = 4
.equ HalfCarryFlag = 5
.equ TransferFlag = 6
.equ GlobalFlag = 7
.equ Frequenz = 4000000
.equ Teiler = 4000

;--VARIABLENDEKLARATION----------------------------------------
.def work = R16 ;Temp. Variable
.def zaehler = R17
.def sreg_save = R18
.CSEG
.org 0x0000

rjmp MAIN ;Reset
rjmp UnusedInt_ISR ;Ext. Int0
rjmp UnusedInt_ISR ;Ext. Int1
rjmp UnusedInt_ISR ;Timer1 Capture Event
rjmp timer ;Timer1 Compare Match A
rjmp UnusedInt_ISR ;Timer1 Compare Match B
rjmp UnusedInt_ISR ;Timer1 Overflow
rjmp UnusedInt_ISR ;Timer0 Overflow
rjmp UnusedInt_ISR ;Serial Transfer Complete
rjmp UnusedInt_ISR ;USART Rx Complete
rjmp UnusedInt_ISR ;USART Data Reg. Empty
rjmp UnusedInt_ISR ;USART Tx Complete
rjmp UnusedInt_ISR ;Analog Comperator
rjmp UnusedInt_ISR ;Ext. Int Request 2
rjmp UnusedInt_ISR ;Timer0 Compare Match
rjmp UnusedInt_ISR ;EEPRom Ready
rjmp UnusedInt_ISR ;Store Program memory ready
UnusedInt_ISR: reti


;--Hauptprogramm------------------------------------------------
MAIN:
;Stackpointer initialisieren
ldi work,low (RAMEND) ; RAMEND ist eine im include file vorgegebene Konstante,
out SPL,work
ldi work, high(RAMEND)
out SPH,work
rjmp init

Main_loop:
;Hauptprogramm
;Display Position 1
ldi work, 0b001
out porte, work

ldi work, 0b10000000
out portc, work

clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait100: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait100

ldi work, 0b000
out porte, work

;Schreibe A auf Display

ldi work, 0b101
out porte, work

ldi work, 0b01000001
out portc, work

clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait10: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait10

ldi work, 0b100 ;Daten in Textpuffer geschrieben
out porte, work

;Display Position 2

ldi work, 0b001
out porte, work

ldi work, 0b10000001
out portc, work

clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait101: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait101

ldi work, 0b000
out porte, work

;Schreibe B auf Display

ldi work, 0b101
out porte, work

ldi work, 0b01000010
out portc, work

clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait11: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait11

ldi work, 0b100 ;Daten in Textpuffer geschrieben
out porte, work


rcall ende

rjmp Main_loop;



;--Unterprogramme-----------------------------------------------------
init:
clr zaehler
ser work
out ddrc, work ;Ausgang: Display D0-D7
out ddre, work ;Ausgang: Display Ena, RW, RS
clr work
out tccr1a, work
ldi work, 0b00001001
out tccr1b, work

ldi work, 0b01100000 ;Timer Einstellungen
out tIMSK, work


ldi work, HIGH(Frequenz / Teiler)
out ocr1ah, work

ldi work, LOW(Frequenz / Teiler)
out ocr1al, work
sei


;warten

clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait0: ;>1,64ms warten
ldi work, 0b00111100
cpse work, zaehler
rjmp wait0

rcall init_disp
rjmp main_loop

init_disp:
ldi work, 0b000
out porte, work

ldi work, 0b00000001 ;Display löschen
out portc, work
ldi work, 0b001
out porte, work
clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait1: ;>1,64ms warten
ldi work, 0b00001000
cpse work, zaehler
rjmp wait1

ldi work, 0b000
out porte, work


ldi work, 0b00000010 ;Cursor auf Anfang
out portc, work
ldi work, 0b001
out porte, work
clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait3: ;>1,64ms warten
ldi work, 0b00001000
cpse work, zaehler
rjmp wait3

ldi work, 0b000
out porte, work

ldi work, 0b00000100 ;Entry mdoe
out portc, work
ldi work, 0b001
out porte, work
clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait4: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait4

ldi work, 0b000
out porte, work

ldi work, 0b00001100 ;Display ein
out portc, work
ldi work, 0b001
out porte, work
clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait5: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait5

ldi work, 0b000
out porte, work

ldi work, 0b00010100 ;Cursor Shift
out portc, work
ldi work, 0b001
out porte, work
clr zaehler
clr work
out TCNT1L, work
out TCNT1H, work
wait8: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait8

ldi work, 0b000
out porte, work

ldi work, 0b00111000 ;Function set
out portc, work
ldi work, 0b001
out porte, work
clr work
clr zaehler
out TCNT1L, work
out TCNT1H, work
wait2: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait2

ldi work, 0b000
out porte, work

ldi work, 0b01000000 ;CGRAM
out portc, work
ldi work, 0b001
out porte, work
clr work
clr zaehler
out TCNT1L, work
out TCNT1H, work
wait6: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait6

ldi work, 0b000
out porte, work

ldi work, 0b10000000 ;DDRAM
out portc, work
ldi work, 0b001
out porte, work
clr work
clr zaehler
out TCNT1L, work
out TCNT1H, work
wait7: ;>40us warten
ldi work, 0b00000001
cpse work, zaehler
rjmp wait7
ldi work, 0b000
out porte, work
ret

ende:
rjmp ende
ret


;*********Interrupt************
timer:
in sreg_save, sreg
inc zaehler
out sreg, sreg_save
reti


Mir kommt jetzt aber vor das das etwas viel Code ist um 2 Zeichen auszugeben, daher wollte ich mal nachfragen ob ich das schon richtig mache und ob das vielleicht irgendwie kompakter oder eleganter gelöst werden kann.

mfg
Stefan

fhs
14.07.2008, 18:10
Hallo Stefan,

kompakter und eleganter -- das kann man fast immer erreichen. Wenn Deine Software fehlerfrei läuft, hast Du ja schon einen sehr großen Schritt getan!

Hier ein ASM-LCD-Beispiel (http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD), aus dem Du vielleicht noch ein paar Ideen entnehmen kannst.

Dein Code wäre besser lesbar, wenn Du ihn mehr strukturiertest. Du schreibst zwar "Unterprogramme" in einen Kommentar, aber danach folgt Code, innerhalb dessen Du viel hin- und herspringst. "init" könnte man z.B. als echtes Unterprogramm gestalten, mit "rcall" erreichen, mit "ret" verlassen. Ebenso die "wait"-Routinen; die ließen sich dann mit einem Parameter aufrufen, der die Wartezeit angibt, so dass Du nicht so viele Sprünge/Labels (wait0, wait1, wait3 usw.) benötigst. Wie gesagt, das ist einfach eine Frage des (persönlichen) Stils und keine Sache von "richtig" oder "falsch".

Es ist >2 Jahre her, dass ich éine LCD-Ansteuerung selbst in Assembler geschrieben habe -- ich kenne die Probleme gut! Glückwunsch zum erfolgreichen Programm!

Gruß

Fred

Stefan_84
15.07.2008, 13:00
Hallo!
Hab mich schon daran gemacht die Unterprogramm etwas auszubauen. Die Pausen sind jetzt ebenfalls als ein Unterprogramm ausgeführt. Danke für den Tipp.
Einen konstanten Text ausgeben ist eh kein Problem, schwieriger wird jetzt die Akkuspannung am Display auszugeben. (z.B.: 10000000 = 5,00V) Das hab ich mir noch nicht so recht zusammengereimt wie ich das jetzt umsetzen soll.
Ich werd jetzt mal das Beispiel durcharbeiten zu dem du mir den Link gepostet hast, vielleicht werd ich ja schlauer.

Danke
mfg
Stefan

fhs
15.07.2008, 13:43
Hallo Stefan,


...(z.B.: 10000000 = 5,00V)...
vermutlich eher so etwas wie 1023 = 5V und 0=0V. Da bringt Dich dieses Tutorial zur Festkommaarithmetik (http://www.mikrocontroller.net/articles/Festkommaarithmetik) hoffentlich weiter.

Viel Erfolg! Wie gesagt, eine LCD-Ansteuerung so in Assembler zu schreiben, dass sie überhaupt funktioniert, beweist, dass der Rest für Dich auch sehr gut zu schaffen ist!

Viele Grüße

Fred

Stefan_84
15.07.2008, 13:59
Ja genau! Danke.
Jetzt muss ich erst mal schauen wie ich das ins Assambler umsetzen kann.

Danke
mfg
Stefan

gulliver
09.09.2008, 13:24
Hallo Forum,

ich denke mal, mein Anliegen paßt hier rein.

Hat schon mal jemand die Mini-LCD-Module 2x8 von Reichelt (EA DIPS082, 40x20mm) im 4-Bit-Modus stabil zum Laufen gebracht?

Im 8-Bit-Modus habe ich damit keine Probleme, aber im 4-Bit-Modus drehe ich bald vom Teller. Direkt nach dem Flashen zeigt es korrekt an, auch nach einem Reset.
Schalte ich aber die Spannung neu ein, dann zeigt es entweder nur die erste Zeile oder Müll an, diesen aber meist in der 2.Zeile. Erst nach zwei bis dreimaligem resetten zeigt es wieder korrekt an.
Dies deutet auf Fehler in der Initialisierung hin. Die Initialisierung ist aber nach dem saumiserablen Datenblatt eine ganz normale, wie für 2x16 oder andere mit dem 44780-Standardcontroller. Nicht mal eine lauffähige Initialisierungsroutine haben die als Beispiel drin, nur solche Kinderkacke, die jeder sowieso schon weiß. Mit einem 16x2-Display im 4-Bit-Modus läuft das gleiche Programm ohne Probleme.

Weiterhin ist mir aufgefallen, daß, wenn es nach dem Resetten dann beide Zeilen anzeigt, der Kontrast etwas geringer wird. Von Kontrasteinstellungen wird im Datenblatt aber nichts erwähnt, sind auch keine Befehlssequenzen dafür vorhanden. Hat jemand schon Erfahrungen mit diesem Display und vor allem, gibt es etwas, was im Datenblatt nicht drinsteht, aber wichtig ist? Ich bin da fast am Verzweifeln. Habe auch schon mit dem Timing rumgespielt, auch 3sek vor der Initialisierung gewartet, hat aber nix gebracht.

mfg Roger