PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] LCD-Probleme



White_Fox
14.09.2014, 18:20
Hallo

Ich sitze jetzt schon einige Tage an meinem Code und es stellt sich allmählich eine gewisse Betriebsblindheit ein.
Findet jemand den Fehler in meinem Code?


Folgendes Problem: Ich habe hier ein 2x16-LCD, das jedoch keine Zeichen anzeigen will.
Ich kann es zwar initialisieren (obere Balkenreihe verschwindet), jedoch zeigt es keine Zeichen an.

Kann mal wer über den Code rüberschauen?


.equ LCD_DAT_PORT =PORTC ;Port für Datenleitungen definieren
.equ LCD_STRG_PORT =PORTA ;Port definieren, an dem RS, RW und E angeschlossen sind
.equ LCD_DDR =DDRC ;Datenrichtungsregister LCD-Datenport
.equ LCD_PIN =PINC ;Pin-Register LCD-Datenport
.equ LCD_E =7 ;Enable-Pin definieren
.equ LCD_RS =5 ;Register-Select-Pin definieren
.equ LCD_RW =6 ;Read-Write-Pin definieren
.equ Schlussmarke =0 ;Schlussmarke für längeren Text, ASCII-Wert
.def LCD_Puffer =R16 ;Register für Daten/Befehlübergabe
.def LCD_TMP1 =R17 ;Arbeitsregister für LCD-Routinen, wird bei Verwendung auf dem Stack gesichert
.def LCD_TMP2 =R18 ;Arbeitsregister für LCD-Routinen, wird bei Verwendung auf dem Stack gesichert
.equ LCD_FunctionSet =0b00101110 ;FunctionSet: 0b001 DL N F * * DL=8/4-Bit, N=1/2 Zeilen, 5x8/5x10
.equ LCD_Display =0b00001000 ;Display Ein/Aus: 0b00001 D C B D=Display Ein/Aus, C=Kursor Ein/Aus, B=Blinken Ein/Aus
.equ LCD_EntryMode =0b00000110 ;Entry Mode Set: 0b000001 I S I=Kursor Laufrichtung, S=Shift Ein/Aus


;============
;Ports konfigurieren
;Stack initialisieren, usw
;============


rcall LCD_initialisieren
rcall Warte_50ms
rcall Warte_50ms

ldi LCD_Puffer, 'W'
rcall LCD_Befehluebergabe
rcall Warte_50ms

Ende:
rjmp Ende


;================================================= =================
;................................................. .................
;LCD initialisieren - 8-Bit-Modus
;................................................. .................
;================================================= =================

LCD_initialisieren:

push LCD_TMP1

ldi LCD_TMP1, 0b00110000
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_1ms
rcall Warte_1ms
rcall Warte_1ms
rcall Warte_1ms
rcall Warte_10us

ldi LCD_TMP1, 0b00110000
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_100us

ldi LCD_TMP1, 0b00110000
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable

ldi LCD_TMP1, LCD_FunctionSet ;Function Set
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_10us
rcall Warte_10us
rcall Warte_25us

ldi LCD_TMP1, LCD_Display ;Display und Kursor einstellen
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_10us
rcall Warte_10us
rcall Warte_25us

ldi LCD_TMP1, LCD_EntryMode ;Entry Mode Set
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_1ms
rcall Warte_1ms

pop LCD_TMP1

ret


;================================================= =================
;................................................. .................
;LCD Befehl uebergeben
;................................................. .................
;================================================= =================

LCD_Befehluebergabe:
out LCD_DAT_PORT, LCD_Puffer
cbi LCD_STRG_PORT,LCD_RS
nop
nop
nop
rcall LCD_Enable
rcall LCD_BusyFlag
ret


;================================================= =================
;................................................. .................
;LCD Daten uebergeben
;................................................. .................
;================================================= =================

LCD_Datenuebergabe:
out LCD_DAT_PORT, LCD_Puffer
sbi LCD_STRG_PORT,LCD_RS
nop
nop
nop
rcall LCD_Enable
rcall LCD_BusyFlag
cbi LCD_STRG_PORT,LCD_RS
ret


;================================================= =================
;................................................. .................
;LCD Enable-Routine
;................................................. .................
;================================================= =================

LCD_Enable:
sbi LCD_STRG_PORT, LCD_E
nop
nop
nop
cbi LCD_STRG_PORT, LCD_E
ret


;================================================= =================
;................................................. .................
;LCD Busyflag abwarten
;................................................. .................
;================================================= =================

LCD_BusyFlag:
push LCD_TMP1
ldi LCD_TMP1, 0b00000000 ;Portpin 7 als Eingang konfigurieren um das BF auszulesen
cbi LCD_STRG_PORT,LCD_RS
sbi LCD_STRG_PORT,LCD_RW
out LCD_DDR, LCD_TMP1

LCD_WarteBF: ;Warteschleife, wird verlassen sobald Pin 7 gesetzt wird
sbic LCD_PIN, 7
jmp LCD_WarteBF

ldi LCD_TMP1, 0b11111111
out LCD_DDR, LCD_TMP1
pop LCD_TMP1
ret

schorsch_76
14.09.2014, 18:34
Was für ein Kontroller ist es denn?

KS0073? HD47780?

Welcher Mode? 4Bit? (ok, wohl 8 bit)

Hast du die Kontrastspannung richtig eingestellt?

Edit: Passt N? muss es 1 sein? 2 zeilen .. richtig?
.equ LCD_FunctionSet =0b00101110 ;FunctionSet: 0b001 DL N F * * DL=8/4-Bit, N=1/2 Zeilen, 5x8/5x10

Stimmt die Startadresse an die du schreibst?

White_Fox
14.09.2014, 18:49
Danke für deine Antwort :)


Was für ein Kontroller ist es denn?
Das ist die Preisfrage. :D
Ich hatte mal vor einigen Jahren das gleiche Display, und da schien es ein KS0066U zu sein, allerdings hat das gleiche Programm bei einem neugekauften LCD nicht mehr funktioniert. Der funktionierenden Init nach muß es allerdings ein HD44780 sein.


Welcher Mode? 4Bit? (ok, wohl 8 bit)
Genau, 8 Bit.


Hast du die Kontrastspannung richtig eingestellt?
Definitiv ja, habs mit nem Poti auch mehrmals durchprobiert.


Edit: Passt N? muss es 1 sein? 2 zeilen .. richtig?
Was meinst du mit den ersten beiden Fragen?
Ja, es ist ein 2x16-LCD. Falsche Verdrahtung/Lötbrücken/fehlerhafte Leitung kann ich ebenso ausschliessen.


Stimmt die Startadresse an die du schreibst?
Die wird doch nach "Cursor auf Anfang" automatisch auf die erste Position gesetzt, oder? Den Befehl hab ich auch schon mehrmals ausprobiert.

schorsch_76
14.09.2014, 18:54
Ich meine "FunctionSet".
.equ LCD_FunctionSet =0b00101110 ;FunctionSet: 0b001 DL N F * * DL=8/4-Bit, N=1/2 Zeilen, 5x8/5x10

- - - Aktualisiert - - -

Ich habe letzte Woche auch ein Display in Betrieb genommen. Es hat mit der 47780 Init Sequenz nicht funktioniert. Es war ein KS0073. Ich habe dann ein einfaches Programm geschrieben was ohne irgendeine Logic einfach die Bytes rausgejuckelt hat. Dann hatte ich eine Sequenz die funktioniert hat. Allerdings war meines 4 Bit Mode...

White_Fox
14.09.2014, 19:00
Du hast Recht, das stimmt nicht ganz. Ich hab da auf gut Glück was ausprobiert und es nicht wieder rückgängig gemacht bevor ich den Code gepostet habe.

Aber mit dem richtigen Wert funktioniert das auch nicht.

.equ LCD_FunctionSet =0b00111000 ;FunctionSet: 0b001 DL N F * * DL=8/4-Bit, N=1/2 Zeilen, 5x8/5x10

schorsch_76
14.09.2014, 19:03
Kannst du nach der Init Sequenz einfach beliebig viele Zeichen rausschreiben? Dann sollte der Cursor "irgendwann" wieder im sichtbaren Bereich sein. So hatte ich festgestellt, das mein function set nicht richtig war...

Falls es ein reiner HD47780 ist, hast du mal die Lib von Fleury ausprobiert?

White_Fox
14.09.2014, 19:11
Ich habe mal ein 'W' in Dauerschleife ins LCD geschickt, das LCD stellt sich immer noch stur:


rcall LCD_initialisieren
rcall Warte_50ms
rcall Warte_50ms

Ende:
cbi PINA, 1
ldi LCD_Puffer, 'W'
rcall LCD_Datenuebergabe
rcall Warte_50ms
rcall Warte_50ms
rcall Warte_50ms

sbi PINA, 1

rjmp Ende



Die Bibliothek von Fleury ist doch C-Code...oder? Ich hab für AVRs gerade keinen C-Compiler zur Hand.

schorsch_76
14.09.2014, 19:18
Nach meinem HD47780 Datasheet ist das die richtige Sequenz für den 8 Bit mode ...

29048

Ich hab dein LCD_initialisieren mal angesehen. Ist sicher RS und RW auf 0 bevor du Enable togglest? Schreib hier mal sicherheitshalber 0 raus auf LCD_STRG_PORT...
Passen auch die DDRs für die beiden Ports?

Ansonsten ist mir nichts aufgefallen ...

- - - Aktualisiert - - -

Ahh .. du wartest nur 4.01ms und nicht 4.1 ms ... zwar wenig unterschied ... aber ... naja ... könnte sein. Mach mal 5 oder 10 draus.

White_Fox
14.09.2014, 19:22
Moment...soll RS nicht auf HIGH gezogen werden beim Daten übergeben?

Ansonsten sind sowohl RS als auch RW auf LOW-Pegel vor der Init auf LOW gezogen.
Das hier ist das komplette Hauptprogramm:


;Ports als Ausgang konfigurieren
ldi R16, 0b11111111
out DDRC, R16
out DDRA, R16
ldi R16, 0b00000000
out LCD_DAT_PORT, R16
out LCD_STRG_PORT, R16

;Stack
ldi R16, LOW(RAMEND)
out SPL, R16
ldi R16, HIGH(RAMEND)
out SPH, R16

rcall Warte_50ms
sbi PINA, 0

rcall LCD_initialisieren
rcall Warte_50ms
rcall Warte_50ms

Ende:
cbi PINA, 1
ldi LCD_Puffer, 'W'
rcall LCD_Datenuebergabe
rcall Warte_50ms
rcall Warte_50ms
rcall Warte_50ms

sbi PINA, 1

rjmp Ende

PortA ( da hängen E, RS und RW dran) und PORTC werden komplett mit 0x00 beschrieben, direkt nach der Festlegung der Datenrichtung.
An A0 und A1 hängen bloß je eine LED.

schorsch_76
14.09.2014, 19:25
RS muss beim initialisieren 0 sein. Siehe meinen Anhang. Auch RW.

- - - Aktualisiert - - -

Beim Daten schreiben muss RS 1 und RW 0 sein. Aber erst nach der initialisierung.

White_Fox
14.09.2014, 19:28
Ich meinte nach der Init. Bei der normalen Datenübergabe.

Edit:
Genau.

schorsch_76
14.09.2014, 19:34
Hmmm ...

Bei mir war nach der Init die Zeilen zu sehen. Vor der Init war hier absolut nichts zu sehen.

Ich denke, entweder ist es kein 47780 oder das Timing passt nicht.

Gibt's kein Datasheetdownload von der Seite, wo du das Ding erworben hast?

White_Fox
14.09.2014, 19:41
Es handelt sich um dieses LCD:
http://www.pollin.de/shop/dt/OTc1OTc4OTk-/Bauelemente_Bauteile/Aktive_Bauelemente/Displays/LCD_Modul_TC1602E_01.html

Die Unterlagen von Pollin taugen zwar nicht viel, ich habe aber auch noch das hier gefunden:
http://www.oppod.com/upload/download/20111224013027_57179.pdf

schorsch_76
14.09.2014, 19:54
Auf Seite 15 deines zweiten Links ist die Init Sequenz.... dann mal checken ...falls mir was auffällt schreib ichs nochmal ...

- - - Aktualisiert - - -

Ich hab was ...

Das Display mag

Funktion Set
Display On
Display Clear
EntryMode Set

Also nicht wie beim 47780 Erst das Interface....

Der Block mal raus


ldi LCD_TMP1, 0b00110000
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_1ms
rcall Warte_1ms
rcall Warte_1ms
rcall Warte_1ms
rcall Warte_10us

ldi LCD_TMP1, 0b00110000
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable
rcall Warte_100us

ldi LCD_TMP1, 0b00110000
out LCD_DAT_PORT, LCD_TMP1
rcall LCD_Enable

White_Fox
14.09.2014, 21:08
Stimmt...das Interface wird weggelassen, das hab ich völlig übersehen.

Das Display wird immer noch initialisiert, aber Zeichen zeigt es immer noch nicht an.

schorsch_76
14.09.2014, 21:41
Nach dem EntryMode Set noch ein "Return Home"
RS 0
RW 0
PORT Data = 2
Siehe Seite 11. Dann Text rausballern.

White_Fox
14.09.2014, 21:50
Ich danke dir sehr für deine Hilfe...aber ich werde das wohl erst morgen ausprobieren. :)

White_Fox
15.09.2014, 10:13
Schade...auch nach Cursor-Home tut sich immer noch nix.

schorsch_76
15.09.2014, 14:37
Ich würde das ganze aus dem Programm rausnehmen und mich erstmal nur auf die Sequenz konzentrieren. Sprich: Ein Programm das nur versucht das Display zu initialisieren und ein Zeichen zu schreiben. Auf das absolut Notwendigste konzentrieren. Nichts parametrieren. Nur direkt hintereinander die Sequenz abarbeiten. Das Motto: "Raus aus dem Wald auf die grüne Wiese".

DDRC=...
DDRD.=...

PORTD=...
_delay...
PORTD=...
_delay ..

usw. ... dass du eine funktionierende Sequenz bekommst.

Hast du das Display jedes mal auch von Vcc getrennt bevor du es versucht hast? Sonst steht es nämlich im flaschen Zustand und reagiert auf die richtige folge nicht ...

- - - Aktualisiert - - -

Das Dsiplay ist eine Statemachine. Es können manche Sachen nur direkt nach einem Power On gemacht werden.

White_Fox
15.09.2014, 15:36
Ich hab beides schon mehrmals ausprobiert. Ja, das LCD samt AVR auch ab- und wieder angeschaltet.

Wie gesagt, bevor ich den Thread hier aufgemacht habe, habe ich schon ein paar Tage dran gesessen.


Ich habe mir auch mal die Init-Sequenzen mehrerer verschiedener LCD-Controller angeschaut und nachprogrammiert. Unter anderem KS0066U, SPLC780D1 und gerad eben auch den ST7066U.
Das LCD selber habe ich auch schon ausgetauscht, die EA-Pins des AVR auf korrekte Funtkion geprüft.

Allmählich bin ich versucht, das LCD aus dem Fenster zu werfen...
Trotzdem danke für deine Hilfe und Mühe bisher.

schorsch_76
15.09.2014, 15:53
Hast du mal zwischen den Schritten richtig lange Zeiten rein gemacht? So ne Sekunde? Häng mal an die Ports noch ne Batterie von 11 LEDs dran. Insbesonders an die 3 Ctrl Pins (E/RS/RW) . Ich habs auch an den Datenpins gehabt. Mit den langen Zeiten konnte ich dann sehen ob das so auf der Hardware so passiert wie ich mir das vorstelle. Evtl ist dein Strobe auch zu kurz mit nur 3 Taktzyklen für diesen Kontroller.

Ich hab dann noch einen Pin genommen (mit Treiber Transistor) um das Display an und aus zu schalten. So stelle ich sicher dass das Display immer im Start Zustand ist, wenn ich meine Sequenz starte.

Edit: So hab ich meins ageschlossen.
29049

- - - Aktualisiert - - -

Ach ja: Ich warte dann nach "Power On" für das Display noch 1s bis sicher die Spannung aufgebaut ist. Nicht nur ein paar ms wie im Datasheet beschrieben.

White_Fox
15.09.2014, 22:03
.include"m644PAdef.inc"

;Ports als Ausgang konfigurieren
ldi R16, 0b11111111
out DDRC, R16
out DDRA, R16
out DDRB, R16
ldi R16, 0b00000000
out PORTC, R16
out PORTA, R16
out PORTB, R16

;Stack
ldi R16, LOW(RAMEND)
out SPL, R16
ldi R16, HIGH(RAMEND)
out SPH, R16

;Initialisierungszeit
rcall Warte_1s

;Function Set
ldi R16, 0b00100100
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

ldi R16, 0b00100100
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Display on/off Controll
ldi R16, 0b00001111
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Display clear
ldi R16, 0b00000001
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Entry Mode Set
ldi R16, 0b00000111
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Cursor Home
ldi R16, 0b00000010
out PORTC, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Sende Daten an LCD
rcall Warte_1s
ldi R16, 0b01010101
out PORTC, R16
out PORTB, R16
sbi PORTA, 5
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
cbi PORTA, 5

E:
rjmp E

Sind in dem Code doch noch Fehler? Ich habe 8 LEDs an Port B gehängt und sehe, was das LCD empfangen soll. Soweit passt das auch. Wartezeit generell eine Sekunde-kommt auch ungefähr hin. Das LCD...rührt sich nicht. Die Balken verschwinden, ja, aber kein Zeichen.

witkatz
15.09.2014, 22:52
Hallo White_Fox

zwei Sachen sind mir in deinem letzten Code aufgefallen:
1. Es wird Entry Mode 0b00000111 verwendet, also Display Shift Left, damit wird das Display nach dem Schreiben nach links verschoben -> und die Zeichen verschwinden wenn du links geschrieben hast. Hast du andere Entry Mode ausprobiert, versuch's mal mit diesem abgespeckten Code mit Entry Mode 0b00000110.
2. sehe ich das richtig, dass du jetzt beim Initialisieren den Function Set 0b00100100 sendest? 3x 0b00110000 wäre glaub ich richtig. Mit der Sekunde Wartezeit hast du vielleicht übertrieben? Ist zwar gut, um die Abfolge zu kontrollieren, aber in der Reality reichen 5ms. Hier ein Bild zu der 8-Bit Initialisierung eines anderen 1602 LCD.
29052

Gruß
witkatz

oberallgeier
15.09.2014, 22:58
... Sind in dem Code doch noch Fehler? ... Die Balken verschwinden, ja, aber kein Zeichen.Ohh Mann. Ich hab jetzt mal versucht meine (gut funktionierende) Routine für ein 2x16-LCD, Code in C, mit Deinem Code zu vergleichen. Ich habe ja den lauffähigen Code als Assembler im File compilat.lls. Aber zehn vor Mitternacht die Bedienung des LCDs aus 12764 Zeilen rauszufisseln krieg ich nicht hin.

Aber dann fiel mir ein, vielleicht kannst Du das selbst (vernünftiger als ich) machen: eine Kurzroutine in C schreiben - nur grad Initialisierung und zwei drei Zeichen senden. Und dann die entstandene LLS-Datei durchschauen ? Wär das ein Weg für Dich ? Du kannst auch gerne meine LCD-Bibliothek bekommen . . .

schorsch_76
16.09.2014, 12:14
Bei


;Sende Daten an LCD
rcall Warte_1s
ldi R16, 0b01010101
out PORTC, R16
out PORTB, R16
sbi PORTA, 5
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
cbi PORTA, 5



Sehe ich kein gesetztes RS... oder ist PortA, bit 5 das RS?

- - - Aktualisiert - - -

So würde ich die Sequenz in C machen. Falls du noch sagst, du hast keinen C Compiler, dann sag an welches Target (CPU) und CPU Takt, dann lade ich auch noch das hex file hoch...



#include <avr/io.h>
#include <util/delay.h>

int main(int argc, char** argv)
{
DDRB = 0b1111111;
DDRC = 0b1111111;
DDRD = 0b1111111;

PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

// Belegung: Port B: Databits
// Port C: 5=E / 6=RW / 7=rs

// wait until display power is on
_delayms(1000);

// function set
PORTB = 0b00111000;

// toggle E
PORTC |= (1<<5);
_delayms(1000);
PORTC &= ~(1<<5);

_delayms(1000);

// display on
PORTB=0b00001111; // everything on, that we see the most

// toggle E
PORTC |= (1<<5);
_delayms(1000);
PORTC &= ~(1<<5);

_delayms(1000);

// display clear
PORTB=0b00000001;
_delayms(1000);

// toggle E
PORTC |= (1<<5);
_delayms(1000);
PORTC &= ~(1<<5);

_delayms(1000);

// entry mode set
PORTB=0b00000110;

// toggle E
PORTC |= (1<<5);
_delayms(1000);
PORTC &= ~(1<<5);

_delayms(1000);

// cursor home
PORTB=0b00000010;
_delayms(1000);

// toggle E
PORTC |= (1<<5);
_delayms(1000);
PORTC &= ~(1<<5);

_delayms(1000);

// try to write character
PORTC |= (1<<7);
_delayms(1000);

PORTB = 'W';
_delayms(1000);

// toggle E
PORTC |= (1<<5);
_delayms(1000);
PORTC &= ~(1<<5);

while(1);



Gruß
Georg

White_Fox
16.09.2014, 17:38
@schorsch:
Boah, das wäre prima. :)
Besagter AVR ist ein ATMega644PA, rennt mit 8MHz über einen Quartz.

Pinbelegung:


LCD AVR
DB0 PC0
DB1 PC1
DB2 PC2
DB3 PC3
DB4 PC4
DB5 PC5
DB6 PC6
DB7 PC7

RS PA5
RW PA6
E PC7


Vielen Dank schon mal.


@witkatz:
Hoppla...danke für den Hinweis mit dem Entrymode. Habs mal geändert und nach einem Powerdown-Reset durchlaufen lassen...leider ohne Ergebnis.

@oberallgeier:
Welche Bibliothek benutzt du denn? Die von Fleury?

Wenn das Hex-File von schorsch nicht funktioiert werde ich mir einen C-Compiler besorgen und dann mal verschiedene Bibliotheken ausprobieren.

witkatz
16.09.2014, 18:02
Und hast du auch die Initialisierung entspr. des Flußdiagramms abgeändert?
3 mal (!) 0b00110000 senden und danach erst Function Set mit Lines und Font -> Display Off -> Display Clear -> Entry Mode.
Meine chinesischen 1602 LCDs funktionieren damit, sind aber, was diese Abfolge angeht ziemlich pingelig.

White_Fox
16.09.2014, 19:11
Ja, ganz am Anfang. Habs wieder rausgenommen weil es in einem anderen Datenblatt gefehlt hat.
Ich werds aber gern nochmal versuchen.

Edit:
Nix passiert.

.include"m644PAdef.inc"

;Ports als Ausgang konfigurieren
ldi R16, 0b11111111
out DDRC, R16
out DDRA, R16
out DDRB, R16
ldi R16, 0b00000000
out PORTC, R16
out PORTA, R16
out PORTB, R16

;Stack
ldi R16, LOW(RAMEND)
out SPL, R16
ldi R16, HIGH(RAMEND)
out SPH, R16

;Initialisierungszeit
rcall Warte_1s

ldi R16, 0b00110000
out PortC, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s



;Function Set
ldi R16, 0b00100100
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Display on/off Controll
ldi R16, 0b00001111
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Display clear
ldi R16, 0b00000001
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Entry Mode Set
ldi R16, 0b00000110
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s


;Cursor Home
ldi R16, 0b00000010
out PORTC, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Sende an LCD
rcall Warte_1s
ldi R16, 0b01010101
out PORTC, R16
out PORTB, R16
sbi PORTA, 5
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
cbi PORTA, 5

E:
rjmp E

witkatz
16.09.2014, 19:48
Und wie kommst du jetzt auf den Wert b00100100 für Function Set? Willst du jetzt auf einmal 4-Bit Modus einzeilig?
Wie wär's mit 0b00111000 für 8 bit, 2 Zeilen 5x8 dots?

White_Fox
16.09.2014, 21:38
Hm...eigenartig warum das da so steht. Das war wohl der späten Stunde gestern geschuldet, als ich das geschrieben habe.
Danke für den hinweis...ich werds gleich mal korrigieren. Obwohl ich da schon mit Sicherheit den eigentlich richtigen Wert drin hatte in den letzten vier Tagen.

Edit: Immer noch nichts. :(

.include"m644PAdef.inc"

;Ports als Ausgang konfigurieren
ldi R16, 0b11111111
out DDRC, R16
out DDRA, R16
out DDRB, R16
ldi R16, 0b00000000
out PORTC, R16
out PORTA, R16
out PORTB, R16

;Stack
ldi R16, LOW(RAMEND)
out SPL, R16
ldi R16, HIGH(RAMEND)
out SPH, R16

;Initialisierungszeit
rcall Warte_1s

ldi R16, 0b00110000
out PortC, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s



;Function Set
ldi R16, 0b00111000
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Display on/off Controll
ldi R16, 0b00001111
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Display clear
ldi R16, 0b00000001
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Entry Mode Set
ldi R16, 0b00000110
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s


;Cursor Home
ldi R16, 0b00000010
out PORTC, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s

;Sende an LCD
rcall Warte_1s
ldi R16, 0b01010101
out PORTC, R16
out PORTB, R16
sbi PORTA, 5
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
cbi PORTA, 5

E:
rjmp E

schorsch_76
17.09.2014, 07:30
Pinbelegung:


LCD AVR
DB0 PC0
DB1 PC1
DB2 PC2
DB3 PC3
DB4 PC4
DB5 PC5
DB6 PC6
DB7 PC7

RS PA5
RW PA6
E PC7



Fällt dir hier bei PortC Pin 7 was auf?

E == Databit7 == doppelt belegt.

- - - Aktualisiert - - -

Hier ist das hexfile mit

// Belegung: Port C: Databits
// Port A: 5=RS / 6=RW / 7 = E

Datenintegrität:
sha1sum lcd.hex
42f8c995d4e36a1db1aedf668a075646addf47cc lcd.hex
Size: 958 lcd.hex

Download:
http://www.file-upload.net/download-9538240/lcd.hex.html

Source: mit avr-gcc 4.8.2 übersetzt.

Es sind insgesamt 21 oder 22 sec wartezeit drin....



#include <avr/io.h>
#include <util/delay.h>

void toggle_e()
{
_delay_ms(1000);
PORTA |= (1<<7);
_delay_ms(1000);
PORTA &= ~(1<<7);
_delay_ms(1000);
}
int main(int argc, char** argv)
{
// everything output
DDRA = 0b1111111;
DDRB = 0b1111111;
DDRC = 0b1111111;
DDRD = 0b1111111;

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;

// Belegung: Port C: Databits
// Port A: 5=RS / 6=RW / 7 = E

// wait until display power is on
_delay_ms(1000);

// function set
PORTC = 0b00111000;

toggle_e();

// display on
PORTC=0b00001111; // everything on, that we see the most

toggle_e();

// display clear
PORTC=0b00000001;

toggle_e();

// entry mode set
PORTC=0b00000110;

toggle_e();

// cursor home
PORTC=0b00000010;

toggle_e();

// try to write character
PORTA |= (1<<5); // RS
_delay_ms(1000);

PORTC = 'W';
_delay_ms(1000);

toggle_e();

while(1);
}

oberallgeier
17.09.2014, 08:37
... @oberallgeier: Welche Bibliothek benutzt du denn? Die von Fleury? ...Anfangs, ja. Kam mir nicht so wirklich gut vor, ich hatte danach den Code von Markus Frejek (http://www.mikrocontroller.net/articles/AVR-Transistortester)übernommen und den aufmerksam/kritisch durchgearbeitet und angepasst. Gewählt im wesentlichen weil ich a) Markus´ Testknecht nachgebaut hatte und b) er die Texte ins EEPROM verlegt hatte. Seither nehme ich diesen Code, nibbelorientiert und ich weiß jetzt einigermassen was ich tue ... (nen, was der Code macht).

oberallgeier
17.09.2014, 09:46
... Sind in dem Code doch noch Fehler? Ich habe 8 LEDs an Port B gehängt ...
Hallo Fox,

es scheinen ja mehrere Fehler drin zu sein, aber wo . . . ich zieh das mal anders auf. Dazu bitte dieses Posting ERST fertig lesen, überlegen, evtl. den hex-File runterladen und in den 644er flashen. Beachte!!! Die Belegung ist für einen PortB im vierbittigen Modus, die entsprechenden Pinns sind im C-Quelltext genannt. WENN der hexcode bei Dir funktioniert, könnten wir, könntest Du, auf dieser Basis weitermachen.

Du hattest anfangs von ner 8bittigen Verbindung vom Port C geschrieben, nun hängen die LEDs am Port B. Deswegen habe ich eine kurze Routine in C für ein LCD geschrieben:
mega644, interner Oszillator, 8 MHz
LCD 2x16 am Port B angeschlossen im vierbittigen Modus,
4-bittige Datenübergabe ans LCD

Dazu gibts diese Hex:
:100000000C9438000C944D000C944D000C944D0051
:100010000C944D000C944D000C944D000C944D002C
:100020000C944D000C944D000C944D000C944D001C
:100030000C944D000C944D000C944D000C944D000C
:100040000C944D000C944D000C944D000C944D00FC
:100050000C944D000C944D000C944D000C944D00EC
:100060000C944D000C944D000C944D000C944D00DC
:1000700011241FBECFEFD0E1DEBFCDBF11E0A0E065
:10008000B1E0ECE8F2E002C005900D92A232B107B7
:10009000D9F70E94FC000C9444010C94000095B127
:1000A000282F22952F70907F292B25B93DE0932F83
:1000B0009A95F1F72D9A2AE1922F9A95F1F72D98BA
:1000C00095B18F70907F982B95B93A95F1F72D9A4D
:1000D0002A95F1F72D9880EA8A95F1F785B1807F0E
:1000E00085B908952C980E944F0008952C9A0E947B
:1000F0004F0008952D9A8AE18A95F1F72D98089579
:1001000081E00E94720080E197E20197F1F7089583
:1001100084B18F6384B980E69AEE0197F1F785B1D7
:10012000807E836085B92D9A9AE1892F8A95F1F7AF
:100130002D98E0E1F7E23197F1F72D9A892F8A9512
:10014000F1F72D9820ED37E0F9013197F1F72D9A6D
:10015000892F8A95F1F72D98F9013197F1F785B13B
:10016000807E826085B9F9013197F1F72D9A9A95D1
:10017000F1F72D98C9010197F1F788E20E9472000A
:100180008CE00E94720086E00E9472000E94800053
:100190000895CF93DF93EC0103C00E94760021966F
:1001A00088818823D1F7DF91CF9108950F931F9312
:1001B000CF93DF938B01880F880F880F80640E9494
:1001C0007200C0E0D0E0F801EC0FFD1F80810E94BA
:1001D00076002196C830D105B1F7DF91CF911F91FC
:1001E0000F91089520E436E004C0F9013197F1F74A
:1001F00001970097D1F7089511B89FEF92B98FE753
:1002000084B980E885B980EC87B98FE388B91AB8DA
:100210009BB90E9488000E94800088EE93E020E451
:1002200036E0F9013197F1F70197D9F780E091E0D5
:100230000E94C90088EE93E020E436E0F90131978E
:10024000F1F70197D9F780EC0E94720081E191E00B
:100250000E94C90080E090E00895CF93DF93EC0105
:10026000CE010E943C01882321F00E947600219655
:10027000F7CFDF91CF910895F999FECF92BD81BD5F
:0C028000F89A992780B50895F894FFCFF4
:10028C00477275DF6F626572616C6C676569657268
:10029C00002020536F206765687473203B2D292044
:0202AC00200030
:00000001FF...die läuft bei mir (aber bei MIR für nen mega1284); ist hier, für den eben gezeigten hex-File, für DEINEN mega644 compiliert.

Dazu der C-Quelltext - damit Du weißt, was vor sich geht:

/* >>
Stand ..\C3\tstu\tstu_644.c
================================================== ============================= =
*** Aufgabenstellung : LCD auf Port B !!! des mega644/8 MHz int. Osc.
================================================== ============================ */
#define F_CPU 8e6
// - - - - - - - - - - - - - - - -
#include <lcd_162_xta.c> // LCD-Lib ähnlich Tr-Tester, akt. PORTB, PB0..7

// ================================================== =========================== =


// ================================================== =========================== =
// ================================================== =========================== =
//### Programm pausieren lassen !! Der Pausenwert ist nur experimentell !
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
{
uint16_t __c = 1600;
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__c)
: "0" (__c)
);
}
}
// ================================================== =========================== =


// ================================================== =========================== =
// === HAUPTProgramm ================================================== ======== =
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int main(void) //
{ //
// - - - - - - - - - - - - - - -
DDRA = 0b00000000; // Alles auf Eingang mit (0)
PORTA = 0b11111111; // mit PullUp (1)
//
DDRB = 0b01111111; // Ausgänge mit (1)
PORTB = 0b10000000; //
//
DDRC = 0b11000000; //
PORTC = 0b00111111; //
//
DDRD = 0b00000000; //
PORTD = 0b11111111; //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - -
// ####>>>> Initialisierung/Anschlüsse von PORT B für LCD DEM 16x2
// "WS" bedeutet für mich - die Anschlüsse an meinem Wannenstecker
// data bit 4 PB0 0 A WS Pin1 |
// data bit 5 PB1 1 A Pin2 | -- Der 10-polige Wannenstecker
// data bit 6 PB2 2 A Pin3 | ist an die Belegung
// data bit 7 SCK, PB3 3 A Pin4 | des Transitortester angepasst
// RS line PB4 RS Pin5 | es kommen noch
// ENABLE line xxxx, PB5 EN1 Pin6 | Pin 9 GND und
// R/W (offen) xxxx, PB6 R/W Pin7 | Pin 10 Vcc dazu
// NC (TasteC) xxx, PB7 NC Pin8 |___________________________
// GND Pin9
// Vcc Pn10 | Anmerkg: ENABLE line !
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
lcd_init(); //
lcd_clear(); // Vor LCD-Ausgabe Display leeren
// - - - - - - - - - - - - - - -
wms( 1000 ); // Wait

// - - - - - - - - - - - - - - -
lcd_string("Grußoberallgeier");

// - - - - - - - - - - - - - - -
//void wms(uint16_t ms) // Waitroutine
wms( 1000 ); // Wait

// - - - - - - - - - - - - - - -
Line2(); // An den Anfang der 2. Zeile springen
lcd_string(" So gehts ;-) "); // Zeile löschen

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return 0; //
} //
// ===== Ende des Testabschnittes, er kann aus mehreren Abschnitten bestehen ====
// ================================================== =============================In der Quelle ist auch GENAU beschrieben, wie das LCD angeschlossen wird. MEIN LCD läuft damit ordentlich - und ich bin relativ sicher, dass es an einem 644er auch laufen wird.

Wenn Du jetzt in der *.lls den Assemblercode verfolgen willst, so kannst Du das hier tun. Dazu die *.lls öffnen und möglichst die C-Quelle daneben betrachten.


tstu.elf: file format elf32-avr

Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000022 00800100 0000028c 00000300 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 0000028c 00000000 00000000 00000074 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .debug_aranges 00000020 00000000 00000000 00000322 2**0
CONTENTS, READONLY, DEBUGGING
3 .debug_pubnames 000000ae 00000000 00000000 00000342 2**0
CONTENTS, READONLY, DEBUGGING
4 .debug_info 00000798 00000000 00000000 000003f0 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_abbrev 0000017b 00000000 00000000 00000b88 2**0
CONTENTS, READONLY, DEBUGGING
6 .debug_line 0000049b 00000000 00000000 00000d03 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_frame 000000c0 00000000 00000000 000011a0 2**2
CONTENTS, READONLY, DEBUGGING
8 .debug_str 0000014f 00000000 00000000 00001260 2**0
CONTENTS, READONLY, DEBUGGING
9 .debug_loc 00000257 00000000 00000000 000013af 2**0
CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
0: 0c 94 38 00 jmp 0x70 ; 0x70 <__ctors_end>
4: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
8: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
10: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
14: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
18: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
1c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
20: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
24: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
28: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
2c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
30: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
34: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
38: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
3c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
40: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
44: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
48: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
4c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
50: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
54: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
58: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
5c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
60: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
64: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
68: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>
6c: 0c 94 4d 00 jmp 0x9a ; 0x9a <__bad_interrupt>

00000070 <__ctors_end>:
70: 11 24 eor r1, r1
72: 1f be out 0x3f, r1 ; 63
74: cf ef ldi r28, 0xFF ; 255
76: d0 e1 ldi r29, 0x10 ; 16
78: de bf out 0x3e, r29 ; 62
7a: cd bf out 0x3d, r28 ; 61

0000007c <__do_copy_data>:
7c: 11 e0 ldi r17, 0x01 ; 1
7e: a0 e0 ldi r26, 0x00 ; 0
80: b1 e0 ldi r27, 0x01 ; 1
82: ec e8 ldi r30, 0x8C ; 140
84: f2 e0 ldi r31, 0x02 ; 2
86: 02 c0 rjmp .+4 ; 0x8c <.do_copy_data_start>

00000088 <.do_copy_data_loop>:
88: 05 90 lpm r0, Z+
8a: 0d 92 st X+, r0

0000008c <.do_copy_data_start>:
8c: a2 32 cpi r26, 0x22 ; 34
8e: b1 07 cpc r27, r17
90: d9 f7 brne .-10 ; 0x88 <.do_copy_data_loop>
92: 0e 94 fc 00 call 0x1f8 ; 0x1f8 <main>
96: 0c 94 44 01 jmp 0x288 ; 0x288 <_exit>

0000009a <__bad_interrupt>:
9a: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>

0000009e <lcd_send>:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//Eigentliche LCD-Zugriffs-Funktion; 4-Bit-Modus
void lcd_send(unsigned char data) {
// oberes Nibble setzen
LCD_PORT = (LCD_PORT & 0xF0) | ((data >> 4) & 0x0F);
9e: 95 b1 in r25, 0x05 ; 5
a0: 28 2f mov r18, r24
a2: 22 95 swap r18
a4: 2f 70 andi r18, 0x0F ; 15
a6: 90 7f andi r25, 0xF0 ; 240
a8: 29 2b or r18, r25
aa: 25 b9 out 0x05, r18 ; 5
can be achieved.
*/
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
ac: 3d e0 ldi r19, 0x0D ; 13
ae: 93 2f mov r25, r19
b0: 9a 95 dec r25
b2: f1 f7 brne .-4 ; 0xb0 <lcd_send+0x12>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
b4: 2d 9a sbi 0x05, 5 ; 5
b6: 2a e1 ldi r18, 0x1A ; 26
b8: 92 2f mov r25, r18
ba: 9a 95 dec r25
bc: f1 f7 brne .-4 ; 0xba <lcd_send+0x1c>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
be: 2d 98 cbi 0x05, 5 ; 5
// oberes Nibble setzen
LCD_PORT = (LCD_PORT & 0xF0) | ((data >> 4) & 0x0F);
_delay_us(5);
lcd_enable();
// unteres Nibble setzen
LCD_PORT = (LCD_PORT & 0xF0) | (data & 0x0F);
c0: 95 b1 in r25, 0x05 ; 5
c2: 8f 70 andi r24, 0x0F ; 15
c4: 90 7f andi r25, 0xF0 ; 240
c6: 98 2b or r25, r24
c8: 95 b9 out 0x05, r25 ; 5
ca: 3a 95 dec r19
cc: f1 f7 brne .-4 ; 0xca <lcd_send+0x2c>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
ce: 2d 9a sbi 0x05, 5 ; 5
d0: 2a 95 dec r18
d2: f1 f7 brne .-4 ; 0xd0 <lcd_send+0x32>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
d4: 2d 98 cbi 0x05, 5 ; 5
d6: 80 ea ldi r24, 0xA0 ; 160
d8: 8a 95 dec r24
da: f1 f7 brne .-4 ; 0xd8 <lcd_send+0x3a>
// unteres Nibble setzen
LCD_PORT = (LCD_PORT & 0xF0) | (data & 0x0F);
_delay_us(5);
lcd_enable();
_delay_us(60);
LCD_PORT &= 0xF0;
dc: 85 b1 in r24, 0x05 ; 5
de: 80 7f andi r24, 0xF0 ; 240
e0: 85 b9 out 0x05, r24 ; 5
}
e2: 08 95 ret

000000e4 <lcd_command>:
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// sendet einen Befehl an das LCD

void lcd_command(unsigned char temp1)
{
LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
e4: 2c 98 cbi 0x05, 4 ; 5
lcd_send(temp1);
e6: 0e 94 4f 00 call 0x9e ; 0x9e <lcd_send>
}
ea: 08 95 ret

000000ec <lcd_data>:
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// sendet ein Datenbyte an das LCD

void lcd_data(unsigned char temp1)
{
LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
ec: 2c 9a sbi 0x05, 4 ; 5
lcd_send(temp1);
ee: 0e 94 4f 00 call 0x9e ; 0x9e <lcd_send>
}
f2: 08 95 ret

000000f4 <lcd_enable>:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
f4: 2d 9a sbi 0x05, 5 ; 5
f6: 8a e1 ldi r24, 0x1A ; 26
f8: 8a 95 dec r24
fa: f1 f7 brne .-4 ; 0xf8 <lcd_enable+0x4>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
fc: 2d 98 cbi 0x05, 5 ; 5
}
fe: 08 95 ret

00000100 <lcd_clear>:
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Sendet den Befehl zur Löschung des Displays

void lcd_clear(void)
{
lcd_command(CLEAR_DISPLAY);
100: 81 e0 ldi r24, 0x01 ; 1
102: 0e 94 72 00 call 0xe4 ; 0xe4 <lcd_command>
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
106: 80 e1 ldi r24, 0x10 ; 16
108: 97 e2 ldi r25, 0x27 ; 39
10a: 01 97 sbiw r24, 0x01 ; 1
10c: f1 f7 brne .-4 ; 0x10a <lcd_clear+0xa>
_delay_ms(5);
}
10e: 08 95 ret

00000110 <lcd_init>:
// Initialisierung:
// Muss ganz am Anfang des Programms aufgerufen werden.

void lcd_init(void)
{
LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN1); // Port auf Ausgang schalten
110: 84 b1 in r24, 0x04 ; 4
112: 8f 63 ori r24, 0x3F ; 63
114: 84 b9 out 0x04, r24 ; 4
116: 80 e6 ldi r24, 0x60 ; 96
118: 9a ee ldi r25, 0xEA ; 234
11a: 01 97 sbiw r24, 0x01 ; 1
11c: f1 f7 brne .-4 ; 0x11a <lcd_init+0xa>
// muss 3mal hintereinander gesendet werden zur Initialisierung
_delay_ms(30);
LCD_PORT = (LCD_PORT & 0xF0 & ~(1<<LCD_RS)) | 0x03;
11e: 85 b1 in r24, 0x05 ; 5
120: 80 7e andi r24, 0xE0 ; 224
122: 83 60 ori r24, 0x03 ; 3
124: 85 b9 out 0x05, r24 ; 5

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
126: 2d 9a sbi 0x05, 5 ; 5
can be achieved.
*/
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
128: 9a e1 ldi r25, 0x1A ; 26
12a: 89 2f mov r24, r25
12c: 8a 95 dec r24
12e: f1 f7 brne .-4 ; 0x12c <lcd_init+0x1c>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
130: 2d 98 cbi 0x05, 5 ; 5
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
132: e0 e1 ldi r30, 0x10 ; 16
134: f7 e2 ldi r31, 0x27 ; 39
136: 31 97 sbiw r30, 0x01 ; 1
138: f1 f7 brne .-4 ; 0x136 <lcd_init+0x26>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
13a: 2d 9a sbi 0x05, 5 ; 5
can be achieved.
*/
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
13c: 89 2f mov r24, r25
13e: 8a 95 dec r24
140: f1 f7 brne .-4 ; 0x13e <lcd_init+0x2e>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
142: 2d 98 cbi 0x05, 5 ; 5
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
144: 20 ed ldi r18, 0xD0 ; 208
146: 37 e0 ldi r19, 0x07 ; 7
148: f9 01 movw r30, r18
14a: 31 97 sbiw r30, 0x01 ; 1
14c: f1 f7 brne .-4 ; 0x14a <lcd_init+0x3a>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
14e: 2d 9a sbi 0x05, 5 ; 5
can be achieved.
*/
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
150: 89 2f mov r24, r25
152: 8a 95 dec r24
154: f1 f7 brne .-4 ; 0x152 <lcd_init+0x42>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
156: 2d 98 cbi 0x05, 5 ; 5
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
158: f9 01 movw r30, r18
15a: 31 97 sbiw r30, 0x01 ; 1
15c: f1 f7 brne .-4 ; 0x15a <lcd_init+0x4a>
lcd_enable();

_delay_ms(1);
lcd_enable();
_delay_ms(1);
LCD_PORT = (LCD_PORT & 0xF0 & ~(1<<LCD_RS)) | 0x02;
15e: 85 b1 in r24, 0x05 ; 5
160: 80 7e andi r24, 0xE0 ; 224
162: 82 60 ori r24, 0x02 ; 2
164: 85 b9 out 0x05, r24 ; 5
166: f9 01 movw r30, r18
168: 31 97 sbiw r30, 0x01 ; 1
16a: f1 f7 brne .-4 ; 0x168 <lcd_init+0x58>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
16c: 2d 9a sbi 0x05, 5 ; 5
can be achieved.
*/
void
_delay_loop_1(uint8_t __count)
{
__asm__ volatile (
16e: 9a 95 dec r25
170: f1 f7 brne .-4 ; 0x16e <lcd_init+0x5e>
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
172: 2d 98 cbi 0x05, 5 ; 5
milliseconds can be achieved.
*/
void
_delay_loop_2(uint16_t __count)
{
__asm__ volatile (
174: c9 01 movw r24, r18
176: 01 97 sbiw r24, 0x01 ; 1
178: f1 f7 brne .-4 ; 0x176 <lcd_init+0x66>
_delay_ms(1);
lcd_enable();
_delay_ms(1);

// 4Bit / 2 Zeilen / 5x7
lcd_command(CMD_SetIFOptions | 0x08);
17a: 88 e2 ldi r24, 0x28 ; 40
17c: 0e 94 72 00 call 0xe4 ; 0xe4 <lcd_command>

// Display ein / Cursor aus / kein Blinken
lcd_command(CMD_SetDisplayAndCursor | 0x04);
180: 8c e0 ldi r24, 0x0C ; 12
182: 0e 94 72 00 call 0xe4 ; 0xe4 <lcd_command>

// inkrement / kein Scrollen
lcd_command(CMD_SetEntryMode | 0x02);
186: 86 e0 ldi r24, 0x06 ; 6
188: 0e 94 72 00 call 0xe4 ; 0xe4 <lcd_command>
lcd_clear();
18c: 0e 94 80 00 call 0x100 ; 0x100 <lcd_clear>
}
190: 08 95 ret

00000192 <lcd_string>:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Schreibt einen String auf das LCD

void lcd_string(char *data)
{
192: cf 93 push r28
194: df 93 push r29
196: ec 01 movw r28, r24
198: 03 c0 rjmp .+6 ; 0x1a0 <lcd_string+0xe>
while(*data) {
lcd_data(*data);
19a: 0e 94 76 00 call 0xec ; 0xec <lcd_data>
data++;
19e: 21 96 adiw r28, 0x01 ; 1
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Schreibt einen String auf das LCD

void lcd_string(char *data)
{
while(*data) {
1a0: 88 81 ld r24, Y
1a2: 88 23 and r24, r24
1a4: d1 f7 brne .-12 ; 0x19a <lcd_string+0x8>
lcd_data(*data);
data++;
}
}
1a6: df 91 pop r29
1a8: cf 91 pop r28
1aa: 08 95 ret

000001ac <lcd_generatechar>:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Schreibt ein Zeichen in den Character Generator RAM
// Daten liegen direkt im RAM
void lcd_generatechar(uint8_t code, const uint8_t *data)
{ //
1ac: 0f 93 push r16
1ae: 1f 93 push r17
1b0: cf 93 push r28
1b2: df 93 push r29
1b4: 8b 01 movw r16, r22
lcd_command(LCD_SET_CGADR|(code<<3)); // Startposition des Zeichens einstellen
1b6: 88 0f add r24, r24
1b8: 88 0f add r24, r24
1ba: 88 0f add r24, r24
1bc: 80 64 ori r24, 0x40 ; 64
1be: 0e 94 72 00 call 0xe4 ; 0xe4 <lcd_command>
1c2: c0 e0 ldi r28, 0x00 ; 0
1c4: d0 e0 ldi r29, 0x00 ; 0
for (uint8_t i=0; i<8; i++) // Bitmuster übertragen
{ //
lcd_data(data[i]); //
1c6: f8 01 movw r30, r16
1c8: ec 0f add r30, r28
1ca: fd 1f adc r31, r29
1cc: 80 81 ld r24, Z
1ce: 0e 94 76 00 call 0xec ; 0xec <lcd_data>
1d2: 21 96 adiw r28, 0x01 ; 1
// Schreibt ein Zeichen in den Character Generator RAM
// Daten liegen direkt im RAM
void lcd_generatechar(uint8_t code, const uint8_t *data)
{ //
lcd_command(LCD_SET_CGADR|(code<<3)); // Startposition des Zeichens einstellen
for (uint8_t i=0; i<8; i++) // Bitmuster übertragen
1d4: c8 30 cpi r28, 0x08 ; 8
1d6: d1 05 cpc r29, r1
1d8: b1 f7 brne .-20 ; 0x1c6 <lcd_generatechar+0x1a>
{ //
lcd_data(data[i]); //
} //
} // Ende void lcd_generatechar(uint8_t code,
1da: df 91 pop r29
1dc: cf 91 pop r28
1de: 1f 91 pop r17
1e0: 0f 91 pop r16
1e2: 08 95 ret

000001e4 <wms>:
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
{
uint16_t __c = 1600;
__asm__ volatile (
1e4: 20 e4 ldi r18, 0x40 ; 64
1e6: 36 e0 ldi r19, 0x06 ; 6
1e8: 04 c0 rjmp .+8 ; 0x1f2 <wms+0xe>
1ea: f9 01 movw r30, r18
1ec: 31 97 sbiw r30, 0x01 ; 1
1ee: f1 f7 brne .-4 ; 0x1ec <wms+0x8>
// ================================================== =========================== =
// ================================================== =========================== =
//### Programm pausieren lassen !! Der Pausenwert ist nur experimentell !
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
1f0: 01 97 sbiw r24, 0x01 ; 1
1f2: 00 97 sbiw r24, 0x00 ; 0
1f4: d1 f7 brne .-12 ; 0x1ea <wms+0x6>
"brne 1b"
: "=w" (__c)
: "0" (__c)
);
}
}
1f6: 08 95 ret

000001f8 <main>:
// === HAUPTProgramm ================================================== ======== =
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int main(void) //
{ //
// - - - - - - - - - - - - - - -
DDRA = 0b00000000; // Alles auf Eingang mit (0)
1f8: 11 b8 out 0x01, r1 ; 1
PORTA = 0b11111111; // mit PullUp (1)
1fa: 9f ef ldi r25, 0xFF ; 255
1fc: 92 b9 out 0x02, r25 ; 2
//
DDRB = 0b01111111; // Ausgänge mit (1)
1fe: 8f e7 ldi r24, 0x7F ; 127
200: 84 b9 out 0x04, r24 ; 4
PORTB = 0b10000000; //
202: 80 e8 ldi r24, 0x80 ; 128
204: 85 b9 out 0x05, r24 ; 5
//
DDRC = 0b11000000; //
206: 80 ec ldi r24, 0xC0 ; 192
208: 87 b9 out 0x07, r24 ; 7
PORTC = 0b00111111; //
20a: 8f e3 ldi r24, 0x3F ; 63
20c: 88 b9 out 0x08, r24 ; 8
//
DDRD = 0b00000000; //
20e: 1a b8 out 0x0a, r1 ; 10
PORTD = 0b11111111; //
210: 9b b9 out 0x0b, r25 ; 11
// R/W (offen) MISO, PB6 R/W Pin7 | Pin 10 Vcc dazu
// NC (TasteC) SCK, PB7 NC Pin8 |___________________________
// GND Pin9
// Vcc Pn10 | Anmerkg: ENABLE line !
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
lcd_init(); //
212: 0e 94 88 00 call 0x110 ; 0x110 <lcd_init>
lcd_clear(); // Vor LCD-Ausgabe Display leeren
216: 0e 94 80 00 call 0x100 ; 0x100 <lcd_clear>
21a: 88 ee ldi r24, 0xE8 ; 232
21c: 93 e0 ldi r25, 0x03 ; 3
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
{
uint16_t __c = 1600;
__asm__ volatile (
21e: 20 e4 ldi r18, 0x40 ; 64
220: 36 e0 ldi r19, 0x06 ; 6
222: f9 01 movw r30, r18
224: 31 97 sbiw r30, 0x01 ; 1
226: f1 f7 brne .-4 ; 0x224 <main+0x2c>
// ================================================== =========================== =
// ================================================== =========================== =
//### Programm pausieren lassen !! Der Pausenwert ist nur experimentell !
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
228: 01 97 sbiw r24, 0x01 ; 1
22a: d9 f7 brne .-10 ; 0x222 <main+0x2a>
lcd_clear(); // Vor LCD-Ausgabe Display leeren
// - - - - - - - - - - - - - - -
wms( 1000 ); // Wait

// - - - - - - - - - - - - - - -
lcd_string("Grußoberallgeier");
22c: 80 e0 ldi r24, 0x00 ; 0
22e: 91 e0 ldi r25, 0x01 ; 1
230: 0e 94 c9 00 call 0x192 ; 0x192 <lcd_string>
234: 88 ee ldi r24, 0xE8 ; 232
236: 93 e0 ldi r25, 0x03 ; 3
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
{
uint16_t __c = 1600;
__asm__ volatile (
238: 20 e4 ldi r18, 0x40 ; 64
23a: 36 e0 ldi r19, 0x06 ; 6
23c: f9 01 movw r30, r18
23e: 31 97 sbiw r30, 0x01 ; 1
240: f1 f7 brne .-4 ; 0x23e <main+0x46>
// ================================================== =========================== =
// ================================================== =========================== =
//### Programm pausieren lassen !! Der Pausenwert ist nur experimentell !
void wms(uint16_t ms) //
{
for(; ms>0; ms--)
242: 01 97 sbiw r24, 0x01 ; 1
244: d9 f7 brne .-10 ; 0x23c <main+0x44>
// - - - - - - - - - - - - - - -
//void wms(uint16_t ms) // Waitroutine
wms( 1000 ); // Wait

// - - - - - - - - - - - - - - -
Line2(); // An den Anfang der 2. Zeile springen
246: 80 ec ldi r24, 0xC0 ; 192
248: 0e 94 72 00 call 0xe4 ; 0xe4 <lcd_command>
lcd_string(" So gehts ;-) "); // Zeile löschen
24c: 81 e1 ldi r24, 0x11 ; 17
24e: 91 e0 ldi r25, 0x01 ; 1
250: 0e 94 c9 00 call 0x192 ; 0x192 <lcd_string>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return 0; //
} //
254: 80 e0 ldi r24, 0x00 ; 0
256: 90 e0 ldi r25, 0x00 ; 0
258: 08 95 ret

0000025a <lcd_eep_string>:
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//String aus EEPROM laden und an LCD senden
void lcd_eep_string(const unsigned char *data)
{ //
25a: cf 93 push r28
25c: df 93 push r29
25e: ec 01 movw r28, r24
unsigned char c;
while(1) //
{ //
c = eeprom_read_byte(data); //
260: ce 01 movw r24, r28
262: 0e 94 3c 01 call 0x278 ; 0x278 <__eerd_byte_m644>
if(c==0) return; //
266: 88 23 and r24, r24
268: 21 f0 breq .+8 ; 0x272 <lcd_eep_string+0x18>
lcd_data(c); //
26a: 0e 94 76 00 call 0xec ; 0xec <lcd_data>
data++; //
26e: 21 96 adiw r28, 0x01 ; 1
270: f7 cf rjmp .-18 ; 0x260 <lcd_eep_string+0x6>
}
} // Ende void lcd_eep_string(const
272: df 91 pop r29
274: cf 91 pop r28
276: 08 95 ret

00000278 <__eerd_byte_m644>:
278: f9 99 sbic 0x1f, 1 ; 31
27a: fe cf rjmp .-4 ; 0x278 <__eerd_byte_m644>
27c: 92 bd out 0x22, r25 ; 34
27e: 81 bd out 0x21, r24 ; 33
280: f8 9a sbi 0x1f, 0 ; 31
282: 99 27 eor r25, r25
284: 80 b5 in r24, 0x20 ; 32
286: 08 95 ret

00000288 <_exit>:
288: f8 94 cli

0000028a <__stop_program>:
28a: ff cf rjmp .-2 ; 0x28a <__stop_program>

witkatz
17.09.2014, 10:18
@White_Fox: Ich fand noch eine Beschreibung deines TC1602E-1 im Netz: TC1602E-01.pdf (http://www.mikrocontroller.net/attachment/182786/TC1602E-01.pdf) vielleicht nützt es was. Auch hier findet man den gleichen Init-Flowchart wieder, den ich schon mal gepostet hab. Ich bin der Meinung (ohne jegliche AVR-Erfahrung), dass dein Code an der markierten Stelle immer noch nicht exakt umgesetzt ist:
29057
Hier steht es bei dir:
...
;Display on/off Controll
ldi R16, 0b00001111
out PORTC, R16
out PORTB, R16
sbi PORTA, 7
rcall Warte_1s
cbi PORTA, 7
rcall Warte_1s
...[/Code]

Du hast doch schon den Aufwand getrieben, die Ausgänge auf Debug-LEDs zu legen. Da müsste es doch möglich sein, eine relativ gut dokumentierte Initiaisierungs-Sequenz richtig durchzutakten, oder?

White_Fox
17.09.2014, 15:57
Oha...vielen Dank für eure bisherigen Bemühungen, ich werde mir das zu späterer Stunde nochmal zu Gemüte führen, bin grad etwas kurz angeunden.

Nur ganz kurz:

Fällt dir hier bei PortC Pin 7 was auf?

E == Databit7 == doppelt belegt.
Meine Herren...wo hab ich nur meinen Kopf? E liegt nicht auf PortC, sondern daneben, auf PortA.

White_Fox
17.09.2014, 20:22
So...ich habe das erste Hexfile von schorsch eben getestet.
Nix am LCD zu sehen...allerdings bleibt der schwarze Balken in der ersten Zeile stehen.

Ich werde mal das Hex von oberallgeier testen.


Edit:

YEAH!!! Das Hex von oberallgeier läuft.
Meine Güte, was freu ich mich gerade...dann werde ich mal ganz genau untersuchen was dein Code im Einzelnen macht.

Ich danke euch allen sehr für eure Mithilfe...ihr habt was gut bei mir. :)

Edit2:
@witkatz:
Die .pdf kommt ir bekannt vor...ich glaub die hab ich schonmal kurz überflogen. Aber da steht ja der Controller drin, das DB guck ich mir jetzt auch nochmal genauer an. Danke.

oberallgeier
17.09.2014, 22:29
... YEAH!!! Das Hex ... läuft. Meine Güte, was freu ich mich gerade ... genau untersuchen was dein Code im Einzelnen macht ...Na prima. Das ist eine eher ältere Bibliothek aus meiner LCD-Routinen-Sammlung. Die läuft hier ohne Abfrage des Busybits - aber sie läuft, jedenfalls bei mir, "immer", hat dafür noch ne recht gute Kommentierung und ist daher hier gut geeignet. UND - die delays sind schon lausig lang . . . . Die Version mit Busyabfrage ist leider nicht präsentierbar, da müsste ich seit ner Weile mal aufräumen :-/

Als Anhaltspunkt für eine Übersetzung nach Assembler brauchst Du also noch die beiden LCD-Quellen.
Die lcd_162_xt.h. Bitte beachte die Einschränkung hier, dass die Datenleitungen hier nur die ersten vier Pinne eines Port sein können (andernfalls müsste man ein bisschen was ummodeln...
// Erweiterte Fassung mit Routine für selbst definierte Zeichen
// Stand = Erweiterung von lcd-routines.h und lcd-routines.c
// vom 11. Apr. 2012
// 28 Nov 2012, 16:23 Leichte Korrekturen

// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
// + http://www.mikrocontroller.net/articles/HD44780#Benutzerdefinierte_Sonderzeichen
// + http://www.mikrocontroller.net/articles/Pseudo-Graphische_LCD-Ansteuerung
// vgl. auch http://www.mikrocontroller.net/topic/265717#2766442
//
// Ansteuerung ab KoCo_x15 geändert auf RS=PB4, EN=PB5

void lcd_data(unsigned char temp1);
void lcd_command(unsigned char temp1);
void lcd_send(unsigned char data);
void lcd_string(char *data);
void lcd_enable(void);
void lcd_init(void);
void lcd_clear(void);
void lcd_eep_string(const unsigned char *data);
void lcd_generatechar( uint8_t code, const uint8_t *data );

//LCD-Befehle
// - - - - - - - - - - - - - - -
#define CMD_SetEntryMode 0x04
#define CMD_SetDisplayAndCursor 0x08
#define CMD_SetIFOptions 0x20
#define CMD_SetCGRAMAddress 0x40 // für Custom-Zeichen
#define CMD_SetDDRAMAddress 0x80 // zum Cursor setzen

// LCD Befehle
// - - - - - - - - - - - - - - -
#define CLEAR_DISPLAY 0x01


// Set CG RAM Address --------- 0b01xxxxxx (Character Generator RAM)
#define LCD_SET_CGADR 0x40

#define LCD_GC_CHAR0 0
#define LCD_GC_CHAR1 1
#define LCD_GC_CHAR2 2
#define LCD_GC_CHAR3 3
#define LCD_GC_CHAR4 4
#define LCD_GC_CHAR5 5
#define LCD_GC_CHAR6 6
#define LCD_GC_CHAR7 7


//Makros für LCD
// - - - - - - - - - - - - - - -
#define Line1() SetCursor(1,0) //An den Anfang der 1. Zeile springen
#define Line2() SetCursor(2,0) //An den Anfang der 2. Zeile springen

#define SetCursor(y, x) lcd_command((uint8_t)(CMD_SetDDRAMAddress + (0x40*(y-1)) + x))
//An eine bestimmte Position springen


#define LCDLoadCustomChar() lcd_command(CMD_SetCGRAMAddress) //Custom-Zeichen laden

//Eigene Zeichen
// - - - - - - - - - - - - - - -
#define LCD_CHAR_OMEGA 244 //Omega-Zeichen
#define LCD_CHAR_U 228 //µ-Zeichen
#define LCD_CHAR_DIODE 0 //Dioden-Icon ###>>> wird als Custom-Character erstellt

// Pinbelegung für das LCD, an verwendete Pins anpassen
#define LCD_PORT PORTB
#define LCD_DDR DDRB
#define LCD_RS PB4
#define LCD_EN1 PB5
und die lcd_162_xta.c
// Erweiterte Fassung mit Routine für selbst definierte Zeichen
// Stand = Erweiterung von lcd-routines.h und lcd-routines.c
// vom 11. Apr. 2012
// 28 Nov 2012 16:24 Leichte Korrekturen

// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
//
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar

#include <avr/io.h>
//#include "lcd-routines.h"
#include "lcd_162_xt.h"
#include <util/delay.h>
#include <avr/eeprom.h>


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// sendet ein Datenbyte an das LCD

void lcd_data(unsigned char temp1)
{
LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
lcd_send(temp1);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// sendet einen Befehl an das LCD

void lcd_command(unsigned char temp1)
{
LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
lcd_send(temp1);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//Eigentliche LCD-Zugriffs-Funktion; 4-Bit-Modus
void lcd_send(unsigned char data) {
// oberes Nibble setzen
LCD_PORT = (LCD_PORT & 0xF0) | ((data >> 4) & 0x0F);
_delay_us(5);
lcd_enable();
// unteres Nibble setzen
LCD_PORT = (LCD_PORT & 0xF0) | (data & 0x0F);
_delay_us(5);
lcd_enable();
_delay_us(60);
LCD_PORT &= 0xF0;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// erzeugt den Enable-Puls
void lcd_enable(void)
{
LCD_PORT |= (1<<LCD_EN1);
_delay_us(10); // kurze Pause
// Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1<<LCD_EN1);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Initialisierung:
// Muss ganz am Anfang des Programms aufgerufen werden.

void lcd_init(void)
{
LCD_DDR = LCD_DDR | 0x0F | (1<<LCD_RS) | (1<<LCD_EN1); // Port auf Ausgang schalten
// muss 3mal hintereinander gesendet werden zur Initialisierung
_delay_ms(30);
LCD_PORT = (LCD_PORT & 0xF0 & ~(1<<LCD_RS)) | 0x03;
lcd_enable();

_delay_ms(5);
lcd_enable();

_delay_ms(1);
lcd_enable();
_delay_ms(1);
LCD_PORT = (LCD_PORT & 0xF0 & ~(1<<LCD_RS)) | 0x02;
_delay_ms(1);
lcd_enable();
_delay_ms(1);

// 4Bit / 2 Zeilen / 5x7
lcd_command(CMD_SetIFOptions | 0x08);

// Display ein / Cursor aus / kein Blinken
lcd_command(CMD_SetDisplayAndCursor | 0x04);

// inkrement / kein Scrollen
lcd_command(CMD_SetEntryMode | 0x02);
lcd_clear();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Sendet den Befehl zur Löschung des Displays

void lcd_clear(void)
{
lcd_command(CLEAR_DISPLAY);
_delay_ms(5);
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Schreibt einen String auf das LCD

void lcd_string(char *data)
{
while(*data) {
lcd_data(*data);
data++;
}
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//String aus EEPROM laden und an LCD senden
void lcd_eep_string(const unsigned char *data)
{ //
unsigned char c;
while(1) //
{ //
c = eeprom_read_byte(data); //
if(c==0) return; //
lcd_data(c); //
data++; //
}
} // Ende void lcd_eep_string(const


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Schreibt ein Zeichen in den Character Generator RAM
// Daten liegen direkt im RAM
void lcd_generatechar(uint8_t code, const uint8_t *data)
{ //
lcd_command(LCD_SET_CGADR|(code<<3)); // Startposition des Zeichens einstellen
for (uint8_t i=0; i<8; i++) // Bitmuster übertragen
{ //
lcd_data(data[i]); //
} //
} // Ende void lcd_generatechar(uint8_t code,

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Viel Erfolg bei Deiner Assemblerarbeit (ich beneide Dich drum, ich hatte anfangs, bei meinem Einstieg in die Mikrocontrollerwelt, fast nur und s..gern in Assembler programmert, aber mit zunehmender Komplexität der Projekte musste dann C her).

HeSt
18.09.2014, 07:30
Hallo an alle!

Na, da hab ich mir ja was vorgenommen! Dieser Tread macht mir nicht gerade Mut! :(
Bin gespannt, ob ich mein Vorhaben hin kriege, wenn ich es überhaupt angehe!??!?

Hab mir dieses LCD (http://www.conrad.at/ce/de/product/183045/LED-Baustein-Weiss-Blau-B-x-H-x-T-80-x-36-x-132-mm-Gleichmann-GE-C1602B-TMI-JTR?queryFromSuggest=true) besorgt und möchte meine Heizungssteuerung (Mega16) von den vielen LEDs auf Display umbauen.
Natürlich bin ich davon ausgegangen, dass alle diese LCDs einen HD44780 Prozessor haben.
Nun lese ich hier, dass dem offenbar nicht so sein MUSS! :(
Im Datenblatt (http://www.produktinfo.conrad.com/datenblaetter/175000-199999/183045-da-01-en-LCD_MODUL_16X2_LED_GE_C1602B_TMI_JT_R.pdf)finde ich leider keinen Hinweis drauf welcher hier verwendet wird.

Wenn ich mir den tread so lese wird mir ganz schwummerig, und ich überlege schon den Umbau bleiben zu lassen.
Zumal ich auch in Assembler programmiere und absolut keine C-Kenntnisse besitze (auch mein Assembler know how ist eher noch begrenzt).

Gruß Heinz

oberallgeier
18.09.2014, 07:57
Hallo Heinz,

Du bist im Forum fast auf den Tag genau sechs Jahre, da wirst DU doch wohl nicht bei so einer Stolperstelle den Mut verlieren. Sooo schlecht ist doch die Betreuung nicht - soweit ich das kenne.


... da hab ich mir ja was vorgenommen ... Tread macht mir nicht gerade Mut ... wird mir ganz schwummerig ... Umbau bleiben zu lassen ...Schaumamal was der Thread neben Problembeschreibungen bietet. Zwei Hexe - alledings für einen mega644. Hinweise darauf, dass man keine zwei Funktionen auf einen Pinn legen soll *ggg*. Damit kann man ja schon was anfangen . . . Und weils grad über Anfang geht: welchen Controller benutzt Du ? Woher stammt DEIN Display? Denn wenn Du Heizungsanlage schreibst muss ich sagen: meine Heizung muss schon jetzt laufen (oberes Allgäu = Alpenrand = schnell s..kühl) und auch bei Dir kommt der nächste Winter ganz bestimmt.

schorsch_76
18.09.2014, 08:16
@HeST: Na das war schon eine schwere Geburt. Muss man schon sagen. Du kannst aber immer davon ausgehen, wenn du dich ans Datenblatt hältst, kommst du ans Ziel.

Apropos: Ich mach auch gerade meine Heizungssteuerung mit einem Atmega168 (falls der Flash nicht reicht, eben 328 ) ;) und einem Display mit KS0073 über einen PCF8574 und I2C. War jetzt nicht so schwer wie es sich hier in dem Thread darstellt ... ;)

29059

Wie man sieht bin ich noch in der Testphase ;)

witkatz
18.09.2014, 08:30
Na, da hab ich mir ja was vorgenommen! Dieser Tread macht mir nicht gerade Mut! :(Gerade dieser Thread zeigt die Hilfsbereitschaft im Forum und müsste einem Mut machen! Also Kopf und Ärmel hoch und ran an die Buletten!

oberallgeier
18.09.2014, 08:52
... meine Heizungssteuerung mit einem Atmega168 (falls der Flash nicht reicht, eben 328 ) ...Die Qual der Wahl zwischen 168 oder 328 habe ich nicht ... wenn ich an die Preise denke: bei CSD (http://www.csd-electronics.de/200/cgi-bin/shop.dll?AnbieterID=2) 168/PDIP oder TQFP -3,95, 328er PDIP 2,95 und TQFP 2,65, beim GULOshop (https://guloshop.de/shop/Mikrocontroller:::3.html?XTCsid=sff4b47hfb8c86hbfv uci3l713) der 328er als PDIP sogar nur 1,80 und TQFP 2,25. Wenn man unbedingt die knappen Flashs und SRAMs möchte - gut, versteh ich. Aber ansonsten lohnt sich der "dickere" in dieser Bauart praktisch immer.


Gerade dieser Thread zeigt ...Genau meine Meinung!

schorsch_76
18.09.2014, 09:01
@oberallgeier: Ich hab halt noch welche da ... Ich weis dass der 328 etwa 1.80€ kostet ... der 168 3.20€ .... ;)

HeSt
18.09.2014, 10:13
Du bist im Forum fast auf den Tag genau sechs Jahre, da wirst DU doch wohl nicht bei so einer Stolperstelle den Mut verlieren.
Hi!
Danke für den Hinweis mit den 6 Jahren! Hab nicht darauf geachtet!
Aber das heißt ja nicht, dass ich 6 Jahre lang "produktiv" bin!! Und genau das ist es.
Ich widme mich immer nur dann den AVRs zu, wenn ich Lösungen brauche, die damit am besten zu realisieren sind.
Meine Heizungssteuerung wird noch eine Weile "schlummern", denn ich heize in der Übergangszeit mit Holz (vor der "Hütte" :wink:).
Sie funktioniert ja auch und bedürfte an sich keiner Änderung. Nur das Feintuning ist etwas mühsam, da ich keine Werte/Parameter ablesen/ändern kann. Dazu muss ich immer zum PC und EEPROM flashen ... :-(
Genau das will ich nun mit dem LCD "erschlagen".


Sooo schlecht ist doch die Betreuung nicht - soweit ich das kenne.
Das wollte ich damit auch nicht gesagt haben!!
Ganz im Gegenteil!! Ich finde die Leute hier im Forum einfach toll, welche Unterstützung die bieten und mit welcher Geduld hier gearbeitet wird!!!
Hut ab und danke für alles bisher!!=D>


welchen Controller benutzt Du ? Woher stammt DEIN Display?
Beim LCD ist der Link hinterlegt und AVR Steht auch oben: Mega16.

@schorsch_76,


Ich mach auch gerade meine Heizungssteuerung mit einem Atmega168 (falls der Flash nicht reicht, eben 328 ) :wink: und einem Display mit KS0073 über einen PCF8574 und I2C. War jetzt nicht so schwer wie es sich hier in dem Thread darstellt ...
Na, da hast aber ein ordenltiches Projekt an der Angel!!
Meine Heizungsanlage ist aus dem Jahr 1973! Sie hatte eine Elektronik (hat das Zeitliche gesegnet), die nur den Mischer regelte.
Kesseltemperatur wurde per Kesselthermostat voreigestellt.
Jetzt regelt meine Steuerung mehr oder weniger gut (bin noch nicht ganz zufrieden) die Kesseltemperatur abhängig von der Außentemperatur, die Raumtemperatur über Mischer und ggf. Kesseltemp, Nachtabsenkung, automatische Sommer-/Winterschaltung und schaltet Warmwasser je nach Temperatur zwischen Solar und Heizung (wenn letztere auch zu kalt <43°C wird sie auch im Sommer angeworfen, Mischer zu und Umwälzpumpe aus). Dazu reicht der Mega16 derzeit aus.
Ob der Flash mit der LCD-Anzeige auch noch reicht? Schaun wir mal ....

Jedenfalls danke an euch für die Ermunterung!!!
Die Realisierung wird noch einige Zeit auf sich warten lassen. Hab noch einiges andere vor. Und außerdem läuft die Heizung ja! ;)

Gruß Heinz

oberallgeier
18.09.2014, 10:55
... Beim LCD ist der Link hinterlegt und AVR Steht auch oben: Mega16 ...Mist - Blackout schon vormittags - oder altersbedingte Leseschwäche :-/ . Gut, der LCD-Controller sei HD44780-konform, steht in Deinem Datenblatt auf Seite 9 unten im Blockschaltbild: "HD44780 or Eqivalent". Dazu passen meine LCD-Routinen.


... Dazu reicht der Mega16 derzeit aus. Ob der Flash mit der LCD-Anzeige auch noch reicht? Schaun wir mal ...Ich hab ja das oben gepostete Miniprogramm am Rechner, habs mal für den mega16 compiliert. Dafür meldet der Compiler:

AVR Memory Usage
----------------
Device: atmega16

Program: 658 bytes (4.0% Full)
(.text + .data + .bootloader)

Data: 34 bytes (3.3% Full)
(.data + .bss + .noinit)Davon geht noch die Litanei der unused Interrupts weg (112 Bytes) und die LCD-Routinen oben fressen auch Strings aus dem EEPROM "void lcd_eep_string(const unsigned char *data);" - WENN Du noch Platz dort hast. Hier die Hexdatei für mega16/8MHz-int-Osz, Pinne wie oben auf PORTB :

:100000000C942A000C943F000C943F000C943F0089
:100010000C943F000C943F000C943F000C943F0064
:100020000C943F000C943F000C943F000C943F0054
:100030000C943F000C943F000C943F000C943F0044
:100040000C943F000C943F000C943F000C943F0034
:100050000C943F0011241FBECFE5D4E0DEBFCDBF1E
:1000600010E0A0E6B0E0E0E7F2E002C005900D92FB
:10007000A238B107D9F70E94EE000C9436010C9417
:10008000000098B3282F22952F70907F292B28BB32
:100090003DE0932F9A95F1F7C59A2AE1922F9A9510
:1000A000F1F7C59898B38F70907F982B98BB3A95CD
:1000B000F1F7C59A2A95F1F7C59880EA8A95F1F784
:1000C00088B3807F88BB0895C4980E94410008953A
:1000D000C49A0E9441000895C59A8AE18A95F1F771
:1000E000C598089581E00E94640080E197E201973D
:1000F000F1F7089587B38F6387BB80E69AEE019787
:10010000F1F788B3807E836088BBC59A9AE1892F16
:100110008A95F1F7C598E0E1F7E23197F1F7C59AD2
:10012000892F8A95F1F7C59820ED37E0F9013197CD
:10013000F1F7C59A892F8A95F1F7C598F90131979A
:10014000F1F788B3807E826088BBF9013197F1F7BF
:10015000C59A9A95F1F7C598C9010197F1F788E218
:100160000E9464008CE00E94640086E00E946400AB
:100170000E9472000895CF93DF93EC0103C00E94A8
:100180006800219688818823D1F7DF91CF91089567
:100190000F931F93CF93DF938B01880F880F880FE6
:1001A00080640E946400C0E0D0E0F801EC0FFD1F05
:1001B00080810E9468002196C830D105B1F7DF9197
:1001C000CF911F910F91089520E436E004C0F9010A
:1001D0003197F1F701970097D1F708951ABA9FEF79
:1001E0009BBB8FE787BB80E888BB80EC84BB8FE339
:1001F00085BB11BA92BB0E947A000E94720088EE01
:1002000093E020E436E0F9013197F1F70197D9F74F
:1002100080E690E00E94BB0088EE93E020E436E0A8
:10022000F9013197F1F70197D9F780EC0E9464004A
:1002300081E790E00E94BB0080E090E00895CF93BA
:10024000DF93EC01CE010E942E01882321F00E9451
:1002500068002196F7CFDF91CF910895E199FECF05
:100260009FBB8EBBE09A99278DB30895F894FFCF7A
:10027000477275DF6F626572616C6C676569657284
:10028000002020536F206765687473203B2D292060
:0202900020004C
:00000001FF


... Die Realisierung wird noch einige Zeit auf sich warten lassen. Hab noch einiges andere vor. Und außerdem läuft die Heizung ja! ...Na ja, wenn Du nen Test machen möchtest - war ja kein wirklicher Aufwand für mich.

White_Fox
18.09.2014, 11:52
Hallo an alle!

Na, da hab ich mir ja was vorgenommen! Dieser Tread macht mir nicht gerade Mut! :(
Bin gespannt, ob ich mein Vorhaben hin kriege, wenn ich es überhaupt angehe!??!?

Ach was, das wird schon werden. Es ist ja nicht jedes LCD so stur wie dieses. Außerdem hast du ja gerade selber auf vier Seiten Thread die Hilfsbereitschaft in diesem Forum sehen können. :)

Außerdem ist das Datenblatt bei Conrad deines LCDs weitaus umfangreicher als das, was Pollin mir geboten hat. ;)

schorsch_76
18.09.2014, 11:55
@Horst: Falls es interssiert, kann ich noch mehr davon zeigen. Das ist aber dann hier offtopic ;) Man sieht es auf dem Foto nicht, aber das sind 3 Leiterplatten übereinander.

Logic mit Atmega, 512 kbit EEPROM, Echtzeituhr DS1307, RS232 und RS485 Schnittstelle
Relaiskarte, welche die unteren Finder Relais steuert
Thermosensorkarte, welche hier oben zu sehen ist. 8 Kanäle a 12 Bit.
Die Displaykarte, an der Türe ...

Wichtig ist mir halt, das das Sicherheitstechnisch, Schutzleiter, Erdung, Einhausung usw. auch alles passt... Es darf nichts passieren ... unfalltechnisch ....

HeSt
18.09.2014, 19:46
Mist - Blackout schon vormittags - oder altersbedingte Leseschwäche :-/
Sowas soll hin und wieder vorkommen ... !! ;)

Gut, der LCD-Controller sei HD44780-konform, steht in Deinem Datenblatt auf Seite 9 unten im Blockschaltbild: "HD44780 or Eqivalent".
Danke, das hab ich wieder überlesen :(

Dazu passen meine LCD-Routinen.
Ich hab ja das oben gepostete Miniprogramm am Rechner, habs mal für den mega16 compiliert.
@oberallgeier, @schorsch_76,
LAAANGSAM Freunde!!!!
Danke für eure Hilfe!!! Ihr schüttet mich ja geradezu damit zu!!
Ich muss mich erst einmal einlesen, wie das Ding funktioniert und was es bedarf, damit es das tut, was man von ihm will ...!!
Muss alles erst ein wenig "behirnen"!!
Ihr seid ja schon viel weiter als ich! Ich steh ja grad gaaaanz am Anfang!


Außerdem hast du ja gerade selber auf vier Seiten Thread die Hilfsbereitschaft in diesem Forum sehen können.
Ja doch! Die Hilfsbereitschaft hab ich schon vor sechs Jahren kennen gelernt! Da hab ich grad mit einem Tiny13 gekämpft, den ich nun schon ganz gut im Griff hab. Auch beim Mega8 und Mega16 hab ich rasche Hilfe bekommen!

@alle
Jetzt bin ich aber noch nicht mitten drin im Problem und somit bedarf es derzeit auch keiner raschen "Behebung".
Wollte nur mal kundtun, dass ich gar nicht gewusst hab, dass es bei den LCDs unterschiedliche Prozessoren gibt.
Und ich grad realisiert hab, dass es nicht ganz so einfach sein wird, wie ich mir das vorgestellt hab ...
Zumindest sehe ich das im Moment so.

Ich darf mich wieder melden, wenn ich die Sache in Angriff nehme, nachdem ich mich eingehend eingelesen hab und in etwa weiß, wie sich das in Assembler abbilden lässt.

Bis dahin heißt es - und bitte nicht böse sein deswegen - "Bitte warten - Bitte warten" ;) DANKE !!!!

|EDIT:|
Zum Einlesen gehört für mich auch das Durchstöbern dieses Forums.
Denn hier gibt es immer gute Tipps!
Und so sieht derzeit noch meine Steuerung aus:2906229063

White_Fox
20.09.2014, 08:24
@oberallgeier:
Sag mal, hast du auch eine gut funktionierende LCD-Bibliothek für den 8-Bit-Modus?

oberallgeier
20.09.2014, 08:30
Sorry Fox, 8bittig, das heißt für mich zu viele belegte/verbrauchte Pinne. Ich habe für viele meiner Platinen eben meinen üblichen LCD-Anschluss auf nem 2x5-Pfosten-(Wannen-)stecker. Selbst 40Beiner wären damit für meinen Geschmack "über"bestückt.

White_Fox
20.09.2014, 17:14
Schade...dann muß ich am 8-Bit-Modus noch etwas rumbasteln. :(

Aber komischerweise laufen meine alten LCD-Routinen jetzt wieder. :eek:
Ja, auch noch nach ab- und wieder einschalten noch. Komisch...

witkatz
20.09.2014, 19:59
Vielleicht fehlt in deinem ersten Projekt einfach eine saubere Register- und Port-Initialisierung?
Nur so als Tipp von einem PIC-user an einen AVR-user ;)

White_Fox
21.09.2014, 17:42
So...ich habe des ganzen Elends gefunden: Es war die JTAG-Schnittstelle.

Für die, die es interessiert und es nicht wissen:
Viele größere AVRs sind bekanntlich mit einer JTAG-Schnittstelle ausgerüstet, welche standardmäßig aktiviert ist. Dies führt dazu, dass manche EA-Pins scheinbar nicht funktionieren. Beim ATMega644 sind das die Pins am Port C 5-2.

Um das Problem zu beheben muß einfach das entsprechende Fusebit JTAGEN geändert werden.