Forum: Mikrocontroller und Digitale Elektronik Pollin LCD1602 keine Anzeige


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Axel H. (mf-futzi)


Lesenswert?

Hallo Forum,

ich habe mir bei Pollin dieses LCD 16x2 besorgt: LCD-Modul POWERTIP 
PC1602LRM-LSO-C (Best.Nr 120508)
Ich habe das LCD mit Hilfe des Datenblattes angeschlossen und in BASCOM 
foldenden Code eingegeben:

$regfile = "m8def.dat"
$crystal = 3686400

Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portd.0 , Db5 = Portd.1 , Db6 = Portd.2 , 
Db7 = Portd.3 , E = Portd.5 , Rs = Portd.4
Config Lcdbus = 4

Cls
Locate 1 , 1
Lcd "test"

Pins 5,7,8,9,10 sind auf GND gelegt.

Zum Einstellen des Kontrast verwende ich ein 10k Poti. Aber das kann ich 
stellen wie ich will, es erfolgt keine Ausgabe (dunkel). Das einzige was 
funzt ist das backlight.

Ich habe schon das Forum durchsucht, aber keinen passenden Hinweis 
gefunden. Ist denn der Code OK?

von Thorsten F. (thorsten)


Lesenswert?

Hallo,

Das Display braucht ne negative Kontrastspannung.
Ich habe mir mit nem ICL7660 -5V erzeugen lassen und das Kontrastpoti 
zwischen VCC und -5V gehängt.

Gruß
Thorsten

von Axel H. (mf-futzi)


Lesenswert?

Hallo Thorsten,

danke für Deine Antwort. Das mit -5V ist im Datenblatt nicht ersichtlich 
(Pin3 Vo Contrast Adjust) :-(
Also ich werde mir den ICL7660 erst besorgen müssen und probier es dann 
nochmal.

von Björn W. (bwieck)


Lesenswert?

Thorsten Fritzke wrote:
> Hallo,
>
> Das Display braucht ne negative Kontrastspannung.
> Ich habe mir mit nem ICL7660 -5V erzeugen lassen und das Kontrastpoti
> zwischen VCC und -5V gehängt.


Warum nimmst Du nicht GND und -5V ?
So wie Du das machst, funktioniert es zwar auch, verbraucht aber unnötig 
viel Strom.

Grüße
Björn

von Uwe .. (uwegw)


Lesenswert?

Für den ersten Test kannst du auch einfach ne Batterie dranhängen, wenn 
du nicht erst auf die Teile warten willst. Es fließt ja nicht besonders 
viel Strom...

von Thorsten F. (thorsten)


Lesenswert?

@Björn

Hast natürlich recht, dass weniger Strom fliessen würde, wenn das Poti 
zwischen GND und -5V hängt.

Ich habe bei meinem Steckbrettaufbau nicht lange drüber nachgedacht und 
den GND Pin vom Poti auf die -5V gehängt. Funktionierte -> bin 
zufrieden.

Gruß

von Axel H. (mf-futzi)


Lesenswert?

Hallo,

habe zu hause noch ein anderes LCD, von Reichelt (161F BL), und dieses 
angesteckt. Funzt leider auch nicht. :-(

Hier mein Code:
$regfile = "m8def.dat"
$crystal = 3686400

Config Lcd = 16 * 1
Config Lcdpin = Pin , Db4 = Portd.0 , Db5 = Portd.1 , Db6 = Portd.2 , 
Db7 = Portd.3 , E = Portd.5 , Rs = Portd.4
Config Lcdbus = 4

Display On
Cls

Do
 Locate 1 , 1
 Lcd "test"
 Waitms 100
Loop

Habe nun mein Display sauber auf einem bread board verdrahtet und dieses 
mit meinem ATMega8 board verbunden. Also Anschlüsse sind korrekt.
Wenn ich am Poti den Kontrast einstelle, so sehe ich eine Veränderung 
nur an den ersten acht Stellen. Die Stellen 9-16 verändern ihren 
Kontrast nicht. Was mache ich nur falsch?

von Axel H. (mf-futzi)


Lesenswert?

Hallo,

ich möchte euch nochmal um Hilfe bitten. Ich bringe dieses LCD (161F BL) 
nicht zum Laufen. Ich hab jetzt noch den externen Quarz abgeklemmt und 
zuvor die Fuse bits wieder auf den Ausgangzustand gestellt. Dann hab ich 
alle Anschlüsse mal auf den Port B angeklemmt. Ich hab schon sämtliche 
Tips hier im Forum probiert -ohne Erfolg.

Was kann ich denn noch falsch gemacht haben?

von Hannes L. (hannes)


Lesenswert?

Axel Hüser wrote:
> Wenn ich am Poti den Kontrast einstelle, so sehe ich eine Veränderung
> nur an den ersten acht Stellen.

Das ist korrekt. Das 1x16-LCD ist in 2 Zeilen zu 8 Zeichen organisiert.

> Die Stellen 9-16 verändern ihren
> Kontrast nicht. Was mache ich nur falsch?

Die meisten Text-LCDs stellen die Hälfte ihrer Pixel aktiv dar, solange 
das LCD noch nicht richtig initialisiert ist. Das kann man gut nutzen, 
um den Kontrast richtig einzustellen. Er ist richtig, wenn aktive und 
inaktive Pixel gut zu unterscheiden sind.

Bei der "Inbetriebnahme" versorgt man also erstmal das LCD mit 
Betriebsspannung und stellt den Kontrast so ein, dass die Hälfte der 
Pixel aktiv ist, die andere Hälfte nicht.

Nachdem der Kontrast richtig eingestellt ist, kann man die Software in 
Betrieb nehmen. Hier geht es erstmal nur um die Initialisierung. Die zur 
Initialisierung erforderliche Sequenz (Befehle und erforderliche Pausen) 
findest Du im Datenblatt des jeweiligen LCDs.
Das erste Zeichen, dass die Initialisierung erfolgreich gewesen sein 
könnte, ist das Verschwinden der aktivierten Pixel. Gewissheit 
verschafft dann ein Schreibtest.

Zu Deinem Programmbeispiel kann ich nichts sagen, da daraus nicht 
hervorgeht, welche Befehle in welchem Zeitabstand an das LCD gesendet 
werden. Ich bin es gewohnt, die Initialisierung gemäß Datenblatt (in 
Assembler) selbst zu schreiben, da kann ich wenigstens nachvollziehen, 
was wirklich passiert.

Übrigens sind Text-LCDs recht unterschiedlich schnell, es ist also 
völlig normal, dass man das Timing an das LCD anpassen muss.

...

von Axel H. (mf-futzi)


Angehängte Dateien:

Lesenswert?

Hallo hannes,

nachdem beim Datenblatt von Reichet nur eine Bemaßnug enthalten ist habe 
ich ich nach einem Datenblatt des Herstellers gesucht - und eines 
gefunden. Auf diesem ist nun auch die Pinbelegung anders (siehe Anhang).
Jetzt weis ich leider nicht , wie man das LCD mit den Ports verbindet. 
Beginnt man mit Datenleitung0 oder Datenleitung1, oder einer anderen. 
Müssen die Leitungen dann auf PORTB0 bis PORTB3 gelegt werden? Müssen 
die nicht verwendeten Leitungen auf GND oder nicht?

Es wäre sehr nett, wenn mir jeamd helfen würde!

von Spess53 (Gast)


Lesenswert?

Hi

an deiner Stelle würde ich mehr dem Datenblatt vertrauen. Die Belegung 
dort entspricht dem Standartsnschluss für Text-LCDs.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

Axel Hüser wrote:
> Auf diesem ist nun auch die Pinbelegung anders (siehe Anhang).

Was ist da anders? Das ist die übliche Pinbelegung.

> Jetzt weis ich leider nicht , wie man das LCD mit den Ports verbindet.

Das hängt von der Konfiguration der Software und den verfügbaren 
AVR-Ports ab. Es bringt z.B. nix, das LCD beim Tiny2313 mit PortC 
verbinden zu wollen.

> Beginnt man mit Datenleitung0 oder Datenleitung1, oder einer anderen.

Bei diesen Defiziten solltest Du Dir vielleicht mal das AVR-Tutorial auf 
dieser Webseite hier ansehen. Es ist zwar für Assembler, sollte Dir aber 
das allgemeine Hardware-Wissen vermitteln können.

> Müssen die Leitungen dann auf PORTB0 bis PORTB3 gelegt werden? Müssen
> die nicht verwendeten Leitungen auf GND oder nicht?

Die meisten LCDs haben PullUp-Widerstände für ihre Datenleitungen, was 
Du durch messen der Pegel in Erfahrung bringen könntest. Diese Leitungen 
lässt man dann offen. Es soll aber auch LCDs geben, die keine PullUps 
haben, dann legt man die Leitungen (sicherheitshalber über Widerstände) 
auf GND oder Vcc.

>
> Es wäre sehr nett, wenn mir jeamd helfen würde!

Das scheint in Deinem Fall sehr schwierig zu sein, wir sprechen 
unterschiedliche Sprachen...

Ich habe es gerne konkret und nachvollziehbar und programmiere AVRs 
daher sehr hardwarenah in Assembler.

Du möchtest es Dir leicht machen und benutzt den Baukasten BASCOM. Als 
Nebenwirkung verschleiert Dir Deine Programmierumgebung, was wirklich 
passiert, da sie Dich auf Abstand zur realen Hardware hält und Dich zum 
Rätselraten animiert.

Müsste ich ein unbekanntes Text-LCD anschließen, dann würde ich so 
vorgehen:
- GND-Anschluss ermitteln (ist meist 'ne dicke Masseleiterbahn rund
  um die Platine)
- Vcc-Anschluss ermitteln (hat meist Elko und Abblock-Cs gegen GND).
- Betriebsspannung anlegen, Spannungsteiler für Kontrast erstmal auf 0V.
- Kontrast vorsichtig verändern, bis die Hälfte der Pixel gut zu sehen
  ist, nun weiß ich, ob die Kontrastspannung negativ oder positiv sein
  muss und kann die Schaltung dementsprechend planen. Ich hatte schon
  LCDs von -12V bis +12V (gegen GND) Kontrastspannung.
- Am AVR ein freies Nibble suchen, an das ich D4 bis D7 anschließe.
- Am AVR zwei freie Portpins suchen, an die ich RS und E anschließe.
- R/W auf GND legen, da ich nur schreiben will.
- Einer Kopie meines Muster-LCD-Treibers (selbst geschriebene
  ASM-Routinen) per .equ-Direktiven mitteilen, an welchen Portpins das
  LCD angeschlossen ist.
- Kurzes Testprogramm schreiben (Init, LCD-Init, Textausgabe,
  Endlosschleife) und LCD testen, falls es nicht will, die Timing-
  Parameter der LCD-Initialisierung und des Schreibens auf LCD
  entsprechend ändern, bis alles stabil läuft.
- Kopie des modifizierten Treibers (Include-Datei) zur späteren
  Verwendung sichern.
- Programm fertigschreiben.

...

von Paul Baumann (Gast)


Lesenswert?

Versuche es mal damit:

$regfile = "m8def.dat"
$crystal = 3686400

Config Lcd = 16 * 1
Config Lcdpin = Pin , Db4 = Portd.0 , Db5 = Portd.1 , Db6 = Portd.2 ,
Db7 = Portd.3 , E = Portd.5 , Rs = Portd.4
Config Lcdbus = 4

Initlcd

Cls

Do
 Locate 1 , 1
 Lcd "test"
 Waitms 100
Loop

Das Display ist vorher nicht initialisiert worden, da der Befehl 
"Initlcd"
fehlte.

MfG Paul

von Hannes L. (hannes)


Lesenswert?

> Das Display ist vorher nicht initialisiert worden, da der Befehl
> "Initlcd"
> fehlte.

Tja, sowas fällt natürlich nur dem eingefleischten BASCOM-Profi auf...

;-)

Gruß in die Mitte Deutschlands...
Hannes

von Paul Baumann (Gast)


Lesenswert?

Ach Hannes, lange nicht mehr "gesehen". ;-)

Ja, das ist immer so eine Sache, die man schnell mal übersieht, denn das 
Programm läuft ja trotzdem, nur gibt es nichts aus.

Ich habe aber auch schon Displays gehabt, die selbst mit 128Khz getaktet
waren und dann haut der Standardbefehl nicht mehr hin. Da habe ich nur 
zum Initialisieren ein Stück Assemblerprogramm hineinsetzen müssen. Aber 
das geht auch ganz gut mit:
$Asm
.....

$ End Asm

Gruß in die Börde

Paul

von Uhu U. (uhu)


Lesenswert?

Hab nur geguckt, ob Paul wieder was gereimtes hinterlassen hat... leider 
diesmal nicht.

von Paul Baumann (Gast)


Lesenswert?

Uhu, Du mußt versteh'n,
das kann nicht immer geh'n.

Manches erfordert klaren Text,
wie Bascom zwischen FOR und NEXT.


duck und weg
Paul

von Uhu U. (uhu)


Lesenswert?

Schön... hat der Trick funktioniert...

von Hannes L. (hannes)


Lesenswert?

Paul Baumann wrote:
> das geht auch ganz gut mit:
> $Asm
> .....
>
> $ End Asm

Das brauchst Du doch gar nicht. Wenn ich Roland Walter sein Online-Buch 
richtig verstanden habe, interpretiert BASCOM alles, was nicht 
BASCOM-Syntax ist, erstmal als Assembler. Man kann also die ASM-Befehle 
ohne Vorwarnung (Anmeldung) unter die BASCOM-Anweisungen mischen.

Achja, gut gereimt (oder gedichtet?)... ;-)
Bit- & Bytebruch,
Hannes

von Axel H. (mf-futzi)


Lesenswert?

Hallo an alle,

ich habe meine Schaltung nochmal neu aufgebaut und mit dem Code von Paul 
getestet und - es funzt.

Manchmal möchte man als Einsteiger aufgeben, wenn man nicht mehr weiter 
kommt. Aber nach einem Erfolgserlebnis geht's mit grösserem Eifer wieder 
weiter.

Ganz besonderen Dank an Paul und Hannes. Werde mich nun mal mit dem 
Tutorial befassen.

von Paul Baumann (Gast)


Lesenswert?

Na siehste! ;-) Das ist das Gute an solchen Sachen: Den gemachten Fehler 
merkt man sich und beim nächsten Programm kann man dann neue einbauen. 
:-))

MfG Paul

von Axel H. (mf-futzi)


Lesenswert?

Hallo,

ich bin's nochmal. Hab jetzt festgestellt, dass nur die ersten 8 Zeichen 
angezeigt werden (LCD 1x16). Bei längerem Text werden Zeichen 
abgeschnitten.

Muß ich da bei Config Lcd etwas verändern? Wenn ich eingebe Config 
Lcd=16*1a wird der Text zweimal angezeigt.

von Hannes L. (hannes)


Lesenswert?

Axel Hüser wrote:
> Hallo,
>
> ich bin's nochmal. Hab jetzt festgestellt, dass nur die ersten 8 Zeichen
> angezeigt werden (LCD 1x16). Bei längerem Text werden Zeichen
> abgeschnitten.

Das ist korrekt. Die Erklärung hatte ich Dir bereits genannt:
Beitrag "Re: Pollin LCD1602 keine Anzeige"
Im Datenblatt des LCDs wirst Du den DD-RAM-Adressbereich für die zweiten 
8 Zeichen finden.

>
> Muß ich da bei Config Lcd etwas verändern? Wenn ich eingebe Config
> Lcd=16*1a wird der Text zweimal angezeigt.

Tja, die genialen Config-Anweisungen von BASCOM... Da ist wohl wieder 
unser Paul gefragt... ;-)

Vielleicht musst Du aber nur den Cursor (die LCD-Ausgabeposition, 
LCD-Kommando "Set DD-RAM-Adress") korrekt setzen...

Bit- & Bytebruch...
...

von Simon K. (simon) Benutzerseite


Lesenswert?

Hannes Lux wrote:
> Vielleicht musst Du aber nur den Cursor (die LCD-Ausgabeposition,
> LCD-Kommando "Set DD-RAM-Adress") korrekt setzen...

Jetzt überforder ihn doch nicht ;) Das HD44780 Datenblatt hat er sich 
sicher noch nicht angeschaut.

von Hannes L. (hannes)


Lesenswert?

Simon Küppers wrote:
> Hannes Lux wrote:
>> Vielleicht musst Du aber nur den Cursor (die LCD-Ausgabeposition,
>> LCD-Kommando "Set DD-RAM-Adress") korrekt setzen...
>
> Jetzt überforder ihn doch nicht ;) Das HD44780 Datenblatt hat er sich
> sicher noch nicht angeschaut.

Das ist sein gutes Recht. Denn ich habe mir die Doku zum JTAG-ICE MK II 
auch nicht angeschaut... ;-)

Wobei es da einen kleinen Unterschied gibt: Ich habe mit dem MK II nix 
vor und muss daher auch nicht Bescheid wissen. ;-)

...

von Axel H. (mf-futzi)


Lesenswert?

Hallo,

also ich kann ja die Profis und Fortgeschrittenen unter euch verstehen, 
wenn sie von Anfängerfragen etwas genervt sind. Aber bitte versteht auch 
mal die andere Seite.
Ich befasse mich seit wenigen Wochen mit uC und habe mich für 
Basic/Bascom entschieden, weil mir Basic schon etwas vetraut ist. (Im 
Forum habe ich für Asm, C und Basic jeweils Vor- und Nachteile 
gefunden). So, die Tutorials (Asm und C) hier im Forum haben mir da 
nicht viel geholfen. Da es mich selber nervt, wegen jeden Problems hier 
im Forum zu fragen, habe ich mir das AVR-Buch von Roland Walter 
zugelegt, um auch Grundlagen zu bekommen. Leider ist da über LCD's 
nichts enthalten.
Lange Rede kurzer Sinn, ich würde mich freuen wenn mir jemand einen 
Lösungsweg gibt, es muss nicht die Lösung auf dem Silbertablett sein.

Axel

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Axel, du kämpfst an mehreren Fronten

Was CONFIG LCD von BASCOM intern macht, ist für den User eine Blackbox. 
Blackboxen mögen viele nicht, vielleicht ein Grund für die Häme hier.

BASCOM funktioniert für viele LCDs direkt aus der Kiste, für andere 
funktioniert es nicht. Bei genügend Druck seitens der User wird vom 
BASCOM-Hersteller ein weiterer Fummelparameter (CHIPSET=..., 16*1a...) 
in die Sprache eingeführt und ein paar mehr Displays funktionieren.

Leider habe ich noch keine Datenbank gesehen, in der steht, welches 
Display mit BASCOM garantiert funktioniert, wenn man es so und so 
betreibt. Dieses Wissen sammeln und das wäre wahrscheinlich der 
bestbesuchte Wiki-Artikel oder das Verkaufsargument für Displays ;-)

Du kannst eigentlich nur mit den Parametern vom CONFIG LCD rumfummeln 
und hoffen, eine praktikable Lösung herauszufinden. Wenn kein Parameter 
passt, tja...

...anderes LCD holen mit dem es bekanntermassen geht oder

...die komplette Ansteuerung selbst machen, d.h. auf die unbequeme Tour 
(Datenblatt lesen, Portleitungen klappern, Timing einhalten) so wie die 
Assembler-Leute oder die C-Leute (OK, die haben Libraries, die aber auch 
nicht immer passen). Tja und da wollen dich Hannes & Co, hinlocken ;-)

von Hannes L. (hannes)


Lesenswert?

> habe mich für
> Basic/Bascom entschieden, weil mir Basic schon etwas vetraut ist.

Ich habe mich gegen BASCOM entschieden, weil mir BASIC (in mehreren 
Dialekten auf mehreren Systemen) sehr vertraut ist und ich daher sehr 
schnell festgestellt habe, dass mir BASCOM (aufgrund seiner 
hardwarefernen Blackbox-Baukastenstruktur) mehr Probleme schafft, als es 
lösen kann.

> Tja und da wollen dich Hannes & Co, hinlocken ;-)

Das kann (und will) ich nicht bestreiten. ;-)
Ich bin nunmal davon überzeugt, dass man mit etwas Detailwissen direkt 
an der Hardware (also unter direkter Nutzung der Hardware-Gegebenheiten) 
mehr erreichen kann und ggf. sogar besser zum Ziel kommt, als unter 
Benutzung eines Software-Baukastens, der nur eine beschränkte Bibliothek 
zur Verfügung stellt, mir aber wichtige Informationen vorenthält. Und 
dafür soll ich auch noch zahlen, während ich das AVR-Studio (also 
Assembler) durch den Kauf der AVRs sowiso mitfinanziere...

...

von Paul Baumann (Gast)


Lesenswert?

Versuche mal, das Display mit "Config LCD = 16*2" zu initialisieren. Es 
kann sein, daß Dein Display so aufgebaut ist, daß praktisch 2 Stück 8*1
Displays dort drin nacheinander angeordnet sind, so daß das Ding 
zweizeilig
initialisiert werden muß. Da 8*1 standardmäßig nicht vorgesehen ist, 
guck mal, ob es so geht. Wenn nicht, mußt Du in den sauren Apfel beißen 
und
Dir aus dem Datenblatt die Initialisierungs-Sequenz raussuchen und ein
eigenes "Initlcd" in Assembler dafür schreiben.

MfG Paul

von Axel H. (mf-futzi)


Lesenswert?

Hallo an alle,

danke nochmal für euere verständlichen Antworten.
Mit dem LCD hab ich das jetz so gelöst:
Do
Locate 1,1
LCD "TextEins"
Locate 2,1
LCD "TextZwei"
Waitms 50
Loop

Auf dem LCD erscheint dann 'TextEinsTextZwei'
(Alle anderen Versuche mit 16*1,16*1a, 16*2 brachten keinen Erfolg)

Also so wie ich das sehe wird es doch besser sein, mich in Assembler 
einzuarbeiten. Sieht für einen Anfänger nur ziemlich schwierig aus. Aber 
was hilft's. Besser jetzt als nie.

Axel

von Axel H. (mf-futzi)


Angehängte Dateien:

Lesenswert?

Hallo an alle,

ich nun den Tipp von einigen von Euch (Hannes und stefb) beherzigt und 
mich in der vergangenen Woche an Assembler herangewagt. Ich habe dazu 
mit dem Tutorial gearbeitet. Ich bin nun bis zu den LCD-Routines 
vorgestoßen und habe versucht mein LCD zur Anzeige zu bringen. Aber es 
tut's leider nicht. (Alle Pixel des LCD sind hell; es sollte aber 'T' 
angezeigt werden.
Programmiert habe ich mit AVR-Studio 4
geflashed mit Ponyprog
ATMEGA8, intern 1 MHz

(Hardware ist OK; Wenn ich eine Hex-Datei, mit Bascom programmiert, 
flashe, wird mein Text angezeigt.)

Und hier mein Code:
.include "m8def.inc"

.def temp1 = r16
.def temp2 = r17
.def temp3 = r18

  ldi temp1, LOW(RAMEND)    ;LOW-Byte der obersten RAM-Adresse
  out SPL, temp1
  ldi temp1, HIGH(RAMEND)    ;HIGH-Byte der obersten RAM-Adresse
  out SPH, temp1

  ldi temp1, 0xFF      ; Port D als Ausgang
  out DDRD, temp1

  rcall lcd_init      ; Display initialisieren
  rcall lcd_clear      ; Display löschen

  ldi temp1, 'T'      ; 'T' anzeigen
  rcall lcd_data

loop:
  rjmp loop

.include "lcd-routines.asm"

Kann mir jemand von Euch auf die Sprünge helfen?

von Axel H. (mf-futzi)


Lesenswert?

nochmal nach oben...

von Karl H. (kbuchegg)


Lesenswert?

Im LCD Code ist noch immer 1Mhz als Taktfrequenz eingetragen
(XTAL)
Wenn du da nicht den korrekten Wert einträgst, werden die
Verzögerungsschleifen falsch (zu kurz) berechnet. Dadurch
stimmt dann das Timing in der heiklen Initialisierungsphase
nicht mehr.

von Uwe (Gast)


Lesenswert?

Hi!
Das schaut auf den ersten Blick nicht schlecht aus, aber
In Bascom:
>Config Lcdpin = Pin , Db4 = Portd.0 , Db5 = Portd.1 , Db6 = Portd.2 ,
>Db7 = Portd.3 , E = Portd.5 , Rs = Portd.4
In ASM
>.equ PIN_E    = 6
>.equ PIN_RW   = 5
>.equ PIN_RS   = 4

Wo haste denn jetzt Pin_E ?

Viel erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hi Uwe,

ich glaub, ich weis, was du meinst. E, RW und RS habe ich nicht richtig 
einem Pin zugeordnet

.equ PIN_E    = 6       (E = Portd.5)
.equ PIN_RW   = 5       (GND)
.equ PIN_RS   = 4       (Rs = Portd.4)

Da muss ich erstmal nachlesen, was ich an Stelle von 4, 5 und 6 
schreiben muss.

von Thomas Forster (Gast)


Lesenswert?

Du schreibst am Anfang:

.def temp1 = r16 usw...,
jedoch taucht die gleiche Definition in den LCD-Routines mit anderen 
Registern nochmal auf.

Ach ja, schreibe am Ende unter das .include lcd-routines.asm noch ein 
NOP oder RET. Bei mir hat das AVR-Studio ohne dies die Routinen nicht 
eingebunden, aber auch keinen Fehler gemeldet.

Beim Powertip-LCD musste ich R/W auf Masse legen, damit es funzt.
Thomas

von Uwe (Gast)


Lesenswert?

Hi,
Wenn es in Bascom geht dann sollte "Pin_RW" auf GND sein und bleibt 
deshalb in ASM ebenfalls unbeachtet. "Pin_E" müsste also auf Pin 5 zu 
finden sein, also:
.equ PIN_E    = 5       (E = Portd.5)
.equ PIN_RS   = 4       (Rs = Portd.4)

Viel Erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hallo,

habe nun den Befehl 'ret' ganz am Ende eingesetzt und die Portzuweisung 
korrigiert:
(RW war bereits auf Masse gelegt)


.equ PIN_RW   = 5      ; GND
.equ PIN_E    = PD5      ; PD5, pin 11
.equ PIN_RS   = PD4      ; PD4, pin 6

und fogende Anweisung ergänzt:

  ldi ZL, LOW(text*2)
  ldi ZH, HIGH(text*2)

    rcall lcd_flash_string

loop:
  rjmp loop

text:
  .db "TestABCDEFGHIJKL",0        ; Mein String

Ein erster Erfolg :-D
Die ersten acht Zeichen (TestABCD) werden angezeigt. Für den Rest muß 
ich noch suchen (Display 8+8)

von Hannes L. (hannes)


Lesenswert?

> Ein erster Erfolg :-D
> Die ersten acht Zeichen (TestABCD) werden angezeigt. Für den Rest muß
> ich noch suchen (Display 8+8)

Die wirst Du dort (im DD-RAM) finden, wo bei zweizeiligen Displays Zeile 
2 beginnt (Datenblatt fragen).

...

von Karl H. (kbuchegg)


Lesenswert?

Axel Hüser wrote:
> (RW war bereits auf Masse gelegt)
>
>
> .equ PIN_RW   = 5      ; GND
> .equ PIN_E    = PD5      ; PD5, pin 11
> .equ PIN_RS   = PD4      ; PD4, pin 6

Das ist nicht sehr schlau.
In deiner Definition benutzen jetzt RW und E denselben Pin.
Dein Glück ist es, dass die Tutorial Routinen RW nicht benutzen.
Würden sie das tun, dann würde sich die Ansteuerung von RW mit
der Ansteuerung von E in die Haare kommen.

Mal angenommen das wäre anders und die Routinen würden
RW ansteuern:
Dann würde das Programm versuchen auf dem Pin 5 mit der RW
Leitung zu wackeln. Gleichzeitig würde besagte Routine aber
auch versuchen auf dem Pin 5 mit der E Leitung zu wackeln.
Und das kann so nicht gut gehen.

Wie gesagt: Im konkreten Fall ist das kein Problem, weil die
Funktionen RW gar nicht ansteuern. Aber für die Zukunft solltest
du die Dinge auch mal aus Sicht deines Programms betrachten und
nicht nur aus der Sicht wie du das Display angelötet hast.

von Uwe (Gast)


Lesenswert?

Hi,
>.equ PIN_RW   = 5      ; GND
>.equ PIN_E    = PD5      ; PD5, pin 11
halte ich für recht gefährlich, weil PD5 ist PortD, Pin 5 also genauso 
wie
Pin_RW = 5. Wenn du irgendwann RW benutzen solltest wird der selbe Pin 
angesprochen.
- 2.Zeile: versuche mal mit
ldi temp1 ,$c0 ;=ADR $40+$80 für ADR DDRam set
rcall lcd_command
ob du da die 2. Zeile erreichen kannst.
Wenn ja, musst du nach 8 Zeichen die neue Adresse setzen und dann weiter 
ausgeben.

Übrigens
>           in    temp3, LCD_PORT
>           andi  temp3, 0x80
>           or    temp1, temp3
Was hast du denn eigentlich an PD7 drann, das du es nicht verändern 
möchtest(0x80 ist die Wertigkeit von Bit7)?
Wenn da nichts ist, einfach weglassen, "push/pop temp3" ebenfalls

Viel Erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe,

langsam, langsam, dass ein Oldie auch noch mitkommt ;-)

1.Problem - falsche Portzuweisung:

Also wenn ich RW dauerhaft auf GND lege (nicht am uC anschliesse), was 
muß ich dann zuweisen?

.equ PIN_RW   = ?

oder kann ich diese Zeile weglassen und dann

lcd_init:
           ...
           ...
           ori   temp1, (1<<PIN_E) | (1<<PIN_RW) | (1<<PIN_RS) | 0x0F
           ...


verändern?

von Karl H. (kbuchegg)


Lesenswert?

Axel Hüser wrote:
> Hallo Uwe,
>
> langsam, langsam, dass ein Oldie auch noch mitkommt ;-)
>
> 1.Problem - falsche Portzuweisung:
>
> Also wenn ich RW dauerhaft auf GND lege (nicht am uC anschliesse), was
> muß ich dann zuweisen?

Im Idealfall kommt dann RW in deinem Code gar nicht mehr vor!
Du hast ihn ja nicht am µC angeschlossen, also sollte es im
Code auch nicht auftauchen.

Nun weis ich natürlich, dass du den Democode aus dem Tutorial
genommen hast. Dort ist RW drinnen, eventuell in der Absicht
das Tut mal dahingehend zu erweitern, dass RW auch wirklich
angesteuert wird.

Aber: Wie auch immer, solltest du dafür sorgen, dass in 1 Jahr
keine Verwirrung aufkommt, wenn jemand deinen Code studiert.
Der sieht im Code: "RW ist an Pin 5 angeschlossen. Aha. Pin E
ist ebenfalls an Pin 5 angeschlossen. Oha! Das kann aber nicht
funktionieren!"

Wenn du RW nicht aus dem restlichen Code entfernen willst, dann
gib ihm eine Pin Nummer, die nicht benutzt wird und schreib im
Kommentar dazu, dass RW hardwaremaessig nicht angeschlossen ist.

>
> .equ PIN_RW   = ?
>
> oder kann ich diese Zeile weglassen und dann
>
> lcd_init:
>            ...
>            ...
>            ori   temp1, (1<<PIN_E) | (1<<PIN_RW) | (1<<PIN_RS) | 0x0F
>            ...
>
>
> verändern?

Ja, das könntest du zb. tun.


Wie gesagt: Es geht darum, Verwirrungen in absehbarer Zeit zu
vermeiden. Irgendwann weist du nämlich nicht mehr, ob du jetzt
beim LCD den RW angeschlossen hast oder nicht. Und wie das Leben
so spielt, sieht man dann gerne einfach im Code nach, ob RW irgendwo
verwendet wird anstatt dass Messgerät herauszukramen und die Leitung
zu verfolgen.

Am allerbesten wäre es:
RW komplett aus dem Code herausoperieren.

Am zweitbesten:
Einen Kommentar dazu, dass RW nicht benutzt wird.

von Axel H. (mf-futzi)


Lesenswert?

Hallo an alle,

habe jetzt meine Zuordnung so umgeschrieben:

.equ PIN_RW   = PD6      ; PD6 nc
.equ PIN_E    = PD5      ; PD5, pin 11
.equ PIN_RS   = PD4      ; PD4, pin 6

Nun zum 2. Problem - die 2. Hälfte des Displays:
Hier mein aktueller Code:

 ; sendet einen Befehl an das LCD
lcd_command:
           ...
     mov   temp2, temp1    ; temp1 nach temp2 kopieren
           swap  temp1      ; nibbles vertauschen
           andi  temp1, 0b00001111
           in    temp3, LCD_PORT
           andi  temp3, 0x80
           or    temp1, temp3
           out   LCD_PORT, temp1  ; Daten an LCD ausgeben
           rcall lcd_enable    ; Enable-Routine aufrufen
           andi  temp2, 0b00001111
           or    temp2, temp3
           out   LCD_PORT, temp2  ; Daten an LCD ausgeben
           rcall lcd_enable    ; Enable-Routine aufrufen
           rcall delay50us    ; warten
      ...
           ret        ; zurück zum Hauptprogramm

Also im Datenblatt steht unter 'Zuornung DD-RAM Adressen...':

1x16(8+8)
1.Zeile $00-$07  (linke Hälfte)
1.Zeile $40-$47  (rechte Hälfte)

Also müssten diese Adressen doch im obigen Code aufgeführt werden???

von Uwe (Gast)


Lesenswert?

Hi!
>1.Zeile $00-$07  (linke Hälfte)
>1.Zeile $40-$47  (rechte Hälfte)

>Also müssten diese Adressen doch im obigen Code aufgeführt werden???

Nein, du übergibst sie in temp1. Meine Vorahnung war also richtig
ldi temp1 ,$c0 ;=ADR $40+$80 für ADR DDRam set
rcall lcd_command

Adresse $40 ist 2.Zeile Zeichen1(die 2-ten 8 Zeichen) Dazu das Bit für
"ADR DDRam set" = Bit7 = $80-> $40+$80 = $C0
Also $C0 an "lcd_command:" übergeben und an der Stelle dann weitere 
Zeichen ausgeben.
>           in    temp3, LCD_PORT
>           andi  temp3, 0x80
>           or    temp1, temp3
Die Frage steht immernoch. Was ist an PD7 drann?
Viel Erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe,

tut mir wirklich leid, ich check im Moment gar nichts mehr. 
Wahrscheinlich hab ich mir zu Beginn mit den LCD's doch zu viel 
zugemutet. Ich such auch schon seit Stunden im Forum nach einem 
Beispielcode oder -zeilen, ohne Erfolg.

Also mir ist klar, dass zuerst die acht Zeichen augegeben werden, danach 
eine Adressänderung und nun die zweiten acht Zeichen. Aber an welcher 
Stelle ? In den lcd-routines oder im Hauptprogramm?  -Sorry-

(Wenn ich im Programm einen ultralangen String eingebe, dann werden alle 
Zeichen (16) angezeigt. Also liegts nur an der Adresse für die 2.Zeile)

...Achso PD7? Das LCD ist neben der Stromversorgung nur mit den 4 
Datenleitungen, E und RS angeschlossen. Die restlichen Pins des uC sind 
nicht belegt.

Danke für Eure Geduld

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe und alle,

nach einem Tag Ruhe versuch ich's mal wieder mit meinem LCD.

Ich hab da immer noch meine Probleme wirklich zu verstehen, was da der 
Reihenfolge nach abläuft (ablaufen soll).

Die Routine lcd_flash_string ruft für jedes Zeichen meines Strings die 
Routine lcd_data auf, bis Register '0' (Ende des Strings).

Die Routine lcd_data gibt die ersten 8 Zeichen an das LCD - 1.Zeile. 
Wenn ich bis jetzt richtig läge, müßte ich doch am Ende der lcd_data die 
Anweisungen

ldi temp1 ,$c0         ; Adresse für die 2.Zeile setzen
rcall lcd_command

schreiben und alle Anweisungen innerhalb von lcd_data wiederholen - 
Ausgabe der 2.Zeile? Ist das so falsch? Ich bitte Euch nochmal um Hilfe.


Vielen Dank

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Ich gehe mal davon aus, dass Du jetzt immernoch das 1x16 (2x8) LCD 
meinst, von dem ja auch die Rede war (hoffentlich verwechsele ich jetzt 
nichts, es laufen ja mehrere LCD-Threads parallel).

Der HD44780 (und seine Kompatiblen) unterstützt (intern) erstmal ein LCD 
mit 2 Zeilen und 40 Zeichen. Diese sind je nach LCD anders angeordnet. 
Das 1x16 ist meist als 2x40 organisiert, wobei von den 40 Zeichen nur 8 
dargestellt werden und die zweite Zeile rechts neben der ersten (siehe 
angehängtes Datenblatt Seite 15).

Um den ganzen DD-RAM (Bildschirmspeicher, 2 mal 40 Zeichen) nutzen zu 
können, gibt es die Möglichkeit, die (meist kleinere) Anzeigeeinheit wie 
ein Fenster (Lupe) über den DD-RAM zu scrollen (Shift Display, 
Datenblatt Seite 14). Der DD-RAM ist dadurch auch bei kleineren Displays 
nicht verloren. Ich persönlich nutze dieses Feature aber (bewusst) 
nicht.

Bei der Ausgabe (besonders von Strings aus Flash oder SRAM/EEPROM, aber 
auch aus zu ASCII-Strings umgewandelten Zahlen) ist also immer darauf zu 
achten, dass die Anzeigeposition "nicht aus dem Fenster läuft". Das LCD 
hat nämlich keinen Zeilenumbruch. Das ist erst der Fall, wenn die 
Anzeigeeinheit des LCDs den gesamten Inhalt des DD-RAMs gleichzeitig 
darstellen kann, wie das 2x40 oder das 4x20. Wobei das 4x20 meist so 
organisiert ist, dass die erste DD-RAM-Zeile in den Zeilen 1 und 3 
dargestellt wird, die zweite DD-RAM-Zeile in den Zeilen 2 und 4. Also 
wieder kein Fließtext...

Ich helfe mir (bei neueren Projekten) mit einem Bildschirmspeicher im 
AVR, der für jede Anzeigeposition ein Byte hat, dazu noch einige Bytes 
für die Verwaltung. LCD_DATA schreibt nur noch in diesen 
Bildschirmspeicher und wird aufgrund der fehlenden Warterei auf das 
Display verdammt schnell. Zusätzlich gibt es einen Job der Mainloop, der 
über einen Timer (über Semaphore) synchronisiert wird (1 bis 10 ms), der 
reiherum den Inhalt des Bildschirmspeichers an das LCD ausgibt, dabei 
die Adressen des Bildschirmspeichers prüft und die Ausgabepositionen 
entwirrt. Dies ermöglicht sorgenfreien Umgang mit dem LCD. Es versteht 
dadurch Fließtext (wenn das Display voll ist, fängt es von vorn an), das 
Positionieren der Ausgabeposition erfolgt durch einfaches Manipulieren 
des Printpointers (der von LCD_DATA benutzt wird).

Leider habe ich lange nichts mit kleinen LCDs gemacht, daher habe ich 
dafür keine (erprobte) Routinensammlung für kleine LCDs. Die gibt es zur 
Zeit nur für das 8x24 (Controller M50530) und das 4x40 (2x HDD44780).

...

von Uwe (Gast)


Lesenswert?

Hi,
Ich mache es mal kurz:
  ldi ZL, LOW(text1*2)
  ldi ZH, HIGH(text1*2)

  rcall lcd_flash_string
  ldi temp1 ,$c0 ;=ADR $40+$80 für ADR DDRam set
  rcall lcd_command
  rcall lcd_flash_string
loop:
  rjmp loop

text1:
  .db "TestABCD",0
text2:
  .db "EFGHIJKL",0        ; Mein String

lcd_flash_string liest bis eine 0 kommt. Mit
  ldi ZL, LOW(text2*2)
  ldi ZH, HIGH(text2*2)
könnte man die Adresse für den 2.Teil direkt anwählen(vor dem 2.rcall 
lcd_flash_string)
Du kannst also noch weitere feste Texte anlegen und über die 
"Marken"(text2:) aufrufen.
Wenn du erneut in "Zeile1" schreiben willst musst du nur die 
Schreibadresse neu setzen:
  ldi temp1 ,$80 ;=ADR $00+$80 für ADR DDRam set
  rcall lcd_command

Viel Erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe, meinst Du so?

    ldi temp1, LOW(RAMEND)      ;LOW-Byte der obersten RAM-Adresse
    out SPL, temp1
    ldi temp1, HIGH(RAMEND)      ;HIGH-Byte der obersten RAM-Adresse
    out SPH, temp1

  rcall lcd_init          ; Display initialisieren
    rcall lcd_clear          ; Display löschen

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


  ldi ZL, LOW(text1*2)
  ldi ZH, HIGH(text1*2)

   rcall lcd_flash_string          ;text1 ausgeben

  ldi temp1 , $c0
  rcall lcd_command

  ldi ZL, LOW(text2*2)
  ldi ZH, HIGH(text2*2)

   rcall lcd_flash_string          ;text 2 ausgeben

loop:
    rjmp loop

text1:
  .db "TESTABCD",0      ; String, durch '0' angeschlossen

text2:
  .db "EFGHIJKL",0      ; String, durch '0'

....


Axel :-(

von Uwe (Gast)


Lesenswert?

Hi!
Ja, so wäre die absolut richtige Schreibweise. In deinem Fall könnte die 
2. Adresszuweisung entfallen, weil "lcd_flash_string" mit der richtigen 
Z-Adresse zurückkommt. Bei mehreren Texten geht nur deine Art.
Übrigens:

  ldi ZL, LOW(text1*2+4)
  ldi ZH, HIGH(text1*2+4)

  ldi temp1,$84                   ;Zeile1,Zeichen5
  rcall lcd_command

   rcall lcd_flash_string          ;text1 ausgeben

  ldi temp1 , $c0
  rcall lcd_command

  ldi ZL, LOW(text2*2)
  ldi ZH, HIGH(text2*2)

   rcall lcd_flash_string          ;text 2 ausgeben

loop:
    rjmp loop

text1:
  .db "TESTABCD",0      ; String, durch '0' angeschlossen

text2:
  .db "EFGHIJKL",0      ; String, durch '0'
sollte "____ABCDEFGHIJKL" auf dein Displ. schreiben.
Ohne:
  ldi temp1,$84                   ;Zeile1,Zeichen5
  rcall lcd_command
sollte "ABCD____EFGHIJKL" erzeugen.

Viel Erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe,

bin schon langsam am verzweifeln :-(

Wenn ich den Code verwende, den ich vorhin gepostet habe, gehen nur die 
ersten 8 Zeichen.

Wenn ich deinen letzten Code eingebe, wird bei den ersten acht Stellen 
eine unterschiedliche Anzahl von Zeichen angezeigt. Mal 5, mal 6, mal 2 
Zeichen. Und immer nur die Buchstaben aus Text2.

Wenn ich neu flashe oder die Reset-Taste drücke, ist die Anzeige immer 
anders.
Kann das vielleicht am ISP-Kabel liegen oder stimmt etwas mit den delays 
nicht?

von Hannes L. (hannes)


Lesenswert?

Axel Hüser wrote:
> Kann das vielleicht am ISP-Kabel liegen oder stimmt etwas mit den delays
> nicht?

Was für einen ISP-Programmer benutzt Du?
Gibt der nach dem Flashen die Leitungen wieder frei (hochohmig)?
Schau doch mal, was passiert, wenn Du das ISP-Kabel abziehst.
Vielleicht ist auch einfach Deine Leitung zum LCD zu lang?

...

von Axel H. (mf-futzi)


Angehängte Dateien:

Lesenswert?

Hallo hannes,

hier mal ein Foto von meinem Aufbau. Als ISP-Programmer nutze ich diesen 
hier: 
http://www.roboternetz.de/wissen/index.php/AVR-ISP_Programmierkabel.

Wie weiter oben schon mal gesagt, wenn ich eine hex-Datei, von Bascom 
erzeugt, flashe, funktionierts einwandfrei. Deshalb habe ich angenommen, 
dass der Aufbau selbst OK ist.

Axel

von Axel H. (mf-futzi)


Lesenswert?

Hallo an alle,

also der einzige Code, bei dem die Anzeige korrekt erscheint, ist:

    ldi temp1, LOW(RAMEND)      ;LOW-Byte der obersten RAM-Adresse
    out SPL, temp1
    ldi temp1, HIGH(RAMEND)      ;HIGH-Byte der obersten RAM-Adresse
    out SPH, temp1

  rcall lcd_init          ; Display initialisieren
    rcall lcd_clear          ; Display löschen

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ldi ZL, LOW(text1*2)
  ldi ZH, HIGH(text1*2)

   rcall lcd_flash_string
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ldi temp1 , $c0
  rcall lcd_command

  ;ldi ZL, LOW(text2*2)          ;deaktiviert
  ;ldi ZH, HIGH(text2*2)         ;deaktiviert

   ;rcall lcd_flash_string        ;deaktiviert

        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
loop:
    rjmp loop

text1:
  .db "TESTABCD                                EFGHIJKL",0      ; 
String, durch '0' angeschlossen

text2:
  ;.db "EFGHIJKL",0      ;deaktiviert

Ich habe in text1 32 Lehrzeichen eingegeben und danach die 2.Hälfte des 
Strings. Es erscheint dann die Anzeige 'TESTABCDEFGHIJKL' mit blinkendem 
Cursor und Unterstrich (wie eingestellt). Nach jedem flashen oder Reset 
erscheint immer die gleiche Anzeige.
Aber trotzdem sollte es auch ohne die 32 Leerzeichen gehen, oder?

Axel

von Karl H. (kbuchegg)


Lesenswert?

Axel Hüser wrote:

> Aber trotzdem sollte es auch ohne die 32 Leerzeichen gehen, oder?

Im Grunde schon.
Ich vermute mal, dass nach dem Neusetzen der Cursorposition
das nachfolgende Ausgeben das Textes zu schnell erfolgt.
(Jedes LCD braucht eine gewisse Zeit um ein Kommando zu
verarbeiten).
Mach doch mal hier eine kleine Verzögerung hinein (ein paar ms,
vielleicht so um die 10 ms, in der Init-Funktion werden doch
solche Warteschleifen verwendet).

  ldi ZL, LOW(text1*2)
  ldi ZH, HIGH(text1*2)

  rcall lcd_flash_string          ;text1 ausgeben

****** Hier etwas warten ******    <<<<<<<<--------

  ldi temp1 , $c0
  rcall lcd_command

****** Hier etwas warten ******    <<<<<<<<--------

  ldi ZL, LOW(text2*2)
  ldi ZH, HIGH(text2*2)

   rcall lcd_flash_string          ;text 2 ausgeben

loop:
    rjmp loop

von Axel H. (mf-futzi)


Lesenswert?

Hallo karlheinz,

habe jetzt jeweils dreimal die Anweisung

rcall delay5ms

eingefügt, Anzeige ohne Veränderung.

Axel

von Uwe (Gast)


Lesenswert?

Hi!
>1.Zeile $00-$07  (linke Hälfte)
>1.Zeile $40-$47  (rechte Hälfte)

>Ich habe in text1 32 Lehrzeichen eingegeben und danach die 2.Hälfte des
>Strings. Es erscheint dann die Anzeige 'TESTABCDEFGHIJKL

Das passt aber nicht ganz, 32 + 8 Zeichen sind 40(dezimal!)=$28
$40 = 64(dez)
$28+$80=$A8
Dann versuche doch mal bitte:
  ldi ZL, LOW(text1*2)
  ldi ZH, HIGH(text1*2)

   rcall lcd_flash_string          ;text1 ausgeben

  ldi temp1 , $A8
  rcall lcd_command

  ldi ZL, LOW(text2*2)
  ldi ZH, HIGH(text2*2)

   rcall lcd_flash_string          ;text 2 ausgeben

loop:
    rjmp loop

text1:
  .db "TESTABCD",0      ; String, durch '0' angeschlossen

text2:
  .db "EFGHIJKL",0      ; String, durch '0'

Das wäre trotzdem eine recht ungewöhnliche Adresse.

Viel Erfolg, Uwe

von Hannes L. (hannes)


Lesenswert?

Uwe wrote:
> Hi!
>>1.Zeile $00-$07  (linke Hälfte)
>>1.Zeile $40-$47  (rechte Hälfte)
>
>>Ich habe in text1 32 Lehrzeichen eingegeben und danach die 2.Hälfte des
>>Strings. Es erscheint dann die Anzeige 'TESTABCDEFGHIJKL
>
> Das passt aber nicht ganz, 32 + 8 Zeichen sind 40(dezimal!)=$28
> $40 = 64(dez)

Der Controller hat aber keine zwei mal 64 Bytes DD-RAM sondern nur zwei 
mal 40 Bytes. Unter diesem Aspekt passt das schon. Auch wenn die 
Adressen einen Versatz von 64 Bytes haben.

> $28+$80=$A8
> Dann versuche doch mal bitte:
>   ldi ZL, LOW(text1*2)
>   ldi ZH, HIGH(text1*2)
>
>    rcall lcd_flash_string          ;text1 ausgeben
>
>   ldi temp1 , $A8
>   rcall lcd_command
>
>   ldi ZL, LOW(text2*2)
>   ldi ZH, HIGH(text2*2)
>
>    rcall lcd_flash_string          ;text 2 ausgeben
>
> loop:
>     rjmp loop
>
> text1:
>   .db "TESTABCD",0      ; String, durch '0' angeschlossen

Und bitte die Strings nicht "ANschließen", dann können die ja nicht 
weg...
;-)

Wobei die Anweisung ".db "TESTABCD",0" auch nicht korrekt ist und 
zumindest eine Warnung beim Assemblieren verursachen müsste, denn jede 
auf Flash angewendete .db-Anweisung muss eine gerade Anzahl von Bytes 
haben, was hier nicht der Fall ist. Der Assembler hängt also eine 
weitere Null an und gibt eine Warnung aus.

>
> text2:
>   .db "EFGHIJKL",0      ; String, durch '0'

Auch diese .DB-Anweisung provoziert eine Warnung.

>
> Das wäre trotzdem eine recht ungewöhnliche Adresse.
>
> Viel Erfolg, Uwe

...

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Mir ist gerade eingefallen, dass ich März einen Termostat für meinen 
Boiler mit LCD 16x2 gebaut hatte und dabei schon mit Bildschirmspeicher 
gearbeitet hatte. Es gibt also doch schon einen LCD-Treiber für 16x2, 
der die üblichen Nachteile kompensiert. Im Anhang sind die LCD-Routinen, 
das Hauptprogramm folgt, in dem man sehen kann, wie die Routinen 
eingebunden werden.

...

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Hier das Hauptprogramm, es ist etwas verwurschtelt, da es Bau-Ruine ist 
und seine Arbeit tut, obwohl es nicht an allen Stellen optimal ist.

...

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe, Hannes,

vielen, vielen Dank für Eure Mühe und Geduld ;-)

Bin jetzt mal für eine Woche beruflich weg und würde mich danach nochmal 
im Forum melden.

Axel

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Die anderen Include-Dateien für die Ausgabeformatierung habe ich jetzt 
mal zu einer Textdatei zusammengefasst, um nicht noch 6 Beitäge posten 
zu müssen.

...

von Uwe (Gast)


Lesenswert?

Hi,
@Hannes Du meinst das Displ. hat eine Adresslücke die automatisch 
übersprungen wird? Wäre auf jedenfall eine Erklärung.
Muss mal das pdf ansehen.....neenee Die Adressen sind dez. 
angegeben.(jedenfalls nicht in hex) Meine letzte Aussage(ldi temp1 , 
$A8) sollte also passen.

>Wobei die Anweisung ".db "TESTABCD",0" auch nicht korrekt ist und
>zumindest eine Warnung beim Assemblieren verursachen müsste
Das stimmt, bis auf die 2 verlorenen Byte entsteht aber kein Schaden und 
für Axel ists übersichtlicher. Besser wäre natürlich:

   ldi ZL, LOW(text*2)
   ldi ZH, HIGH(text*2)
          :
          :
   ldi ZL, LOW(text*2+9)
   ldi ZH, HIGH(text*2+9)
          :
          :

text:
   .db "TestABCD",0,"EFGHIJKL",0

Du musst zugeben, das ist etwas unübersichtlicher.

Viel Erfolg, Uwe

von Hannes L. (hannes)


Lesenswert?

Uwe wrote:
> Hi,

Low... ;-)

> @Hannes Du meinst das Displ. hat eine Adresslücke die automatisch
> übersprungen wird? Wäre auf jedenfall eine Erklärung.

Ich weiß es nicht, halte es aber für möglich...

> Muss mal das pdf ansehen.....neenee Die Adressen sind dez.
> angegeben.(jedenfalls nicht in hex) Meine letzte Aussage(ldi temp1 ,
> $A8) sollte also passen.

Die "Nullpunkte" beider LCD-Zeilen liegen 64 Bytes auseinander, bei 
gesetztem Bit7 (Kommando-Ident) sind das $80 und $C0. Mit $A8 kann ich 
nichts anfangen...

>
>>Wobei die Anweisung ".db "TESTABCD",0" auch nicht korrekt ist und
>>zumindest eine Warnung beim Assemblieren verursachen müsste
> Das stimmt, bis auf die 2 verlorenen Byte entsteht aber kein Schaden und
> für Axel ists übersichtlicher. Besser wäre natürlich:
>
>    ldi ZL, LOW(text*2)
>    ldi ZH, HIGH(text*2)
>           :
>           :
>    ldi ZL, LOW(text*2+9)
>    ldi ZH, HIGH(text*2+9)
>           :
>           :
>
> text:
>    .db "TestABCD",0,"EFGHIJKL",0

Nööö, einfach bei Bedarf die zweite Null selbst anhängen. Dann weiß man 
wenigstens, dass der erzeugte Binärcode mit dem Quelltext übereinstimmt 
und vermeidet nebenbei noch die Warnung:

.db "TestABCD",0,0
.db "EFGHIJKL",0,0

Solange es nur um Text-Terminierung geht, ist das eigentlich schnuppe, 
trotzdem habe ich mir angewöhnt, Code so zu schreiben, dass weder 
Fehlermeldungen noch Warnungen entstehen. Wenn man sich erstmal (durch 
fehlende Disziplin) an Warnungen gewöhnt hat, dann übersieht man schnell 
mal wichtige Warnungen... 8-(

>
> Du musst zugeben, das ist etwas unübersichtlicher.

Na so würde ich es ja auch nicht machen... ;-)

>
> Viel Erfolg, Uwe

Wobei? (Erfolg), meine LCDs laufen... ;-)

...

von Uwe (Gast)


Lesenswert?

Hi!
@Hannes
>trotzdem habe ich mir angewöhnt, Code so zu schreiben, dass weder
>Fehlermeldungen noch Warnungen entstehen.
Und wie machst du das wenn du zb.XL/XH mit einem neuen Namen austattest?
Das erzeugt ja auch Warnungen.;-) Ich lese mir das jedenfalls durch und 
beurteile ob es wichtig ist. Ob du nun die 2 Nullen anhängst oder der 
Assembler ist doch egal. Wichtiger wäre mir im Bedarfsfall die 2 Byte 
noch zu haben. Ich habe mich heute erst mächtig über 26 Byte gefreut die 
ich freisetzen konnt. Das sind immerhin 13 Befehle.

>Die "Nullpunkte" beider LCD-Zeilen liegen 64 Bytes auseinander
Hoffentlich irrst du dich da nicht. Schaue dir doch das Datenblatt, 
welches Axel oben angehangen hat, mal richtig an. Ich vermisse 
jedenfalls ein 0x.. oder $ oder Hex in der Darstellung.

Schönen Tag noch, Uwe

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Uwe wrote:
> Hi!
> @Hannes

Ach, Uwe, eigentlich habe ich für solche Spielchen gar keine Zeit...

>>trotzdem habe ich mir angewöhnt, Code so zu schreiben, dass weder
>>Fehlermeldungen noch Warnungen entstehen.
> Und wie machst du das wenn du zb.XL/XH mit einem neuen Namen austattest?

Warum sollte ich das tun? - Die haben doch Namen.

Und wenn ich es doch mal tun müsste, würde ich mich daran erinnern, dass 
es entsprechende Directiven im Präprozessor des Assemblers gibt, würde 
in der Hilfe nachschaun und die entsprechenden Directiven verwenden (ich 
habe jetzt absolut keine Lust zum Nachschaun, da ich diese Info selbst 
nicht brauche...).

> Das erzeugt ja auch Warnungen.;-)

Die lassen sich aber vermeiden...

> Ich lese mir das jedenfalls durch und
> beurteile ob es wichtig ist.

Das mache ich auch, falls welche auftreten. Es versuche es aber zu 
vermeiden.

> Ob du nun die 2 Nullen anhängst oder der
> Assembler ist doch egal.

Solange es nur eine Stringterminierung ist, ist das völlig egal, habe 
ich auch nie anders behauptet. Aber wenn man sich das angewöhnt, dann 
macht man das (unbewusst, aus Routine) auch dann, wenn die Tabelle Daten 
enthält und die zusätzliche (im Quelltext nicht vorhandene!!!) Null den 
Index durcheinander bringt.

> Wichtiger wäre mir im Bedarfsfall die 2 Byte
> noch zu haben. Ich habe mich heute erst mächtig über 26 Byte gefreut die
> ich freisetzen konnt. Das sind immerhin 13 Befehle.

Naja, sooooo knapp ist es bei mir selten.

>
>>Die "Nullpunkte" beider LCD-Zeilen liegen 64 Bytes auseinander
> Hoffentlich irrst du dich da nicht. Schaue dir doch das Datenblatt,
> welches Axel oben angehangen hat, mal richtig an.

Irrtum...
Im Datenblatt, das Axel angehangen hat
Beitrag "Re: Pollin LCD1602 keine Anzeige"
stehen gar keine Adressen. Aber da steht (auf Seite 2 oben) etwas 
gaaaaaanz Wichtiges betreffs Länge der Leitungen zum LCD. ;-)

Du meinst vermutlich das Pollin-Datenblatt, das ich gepostet habe:
Beitrag "Re: Pollin LCD1602 keine Anzeige"

> Ich vermisse
> jedenfalls ein 0x.. oder $ oder Hex in der Darstellung.

Die vermisse ich auch.

Aber ich halte das für einen Fehler beim Abschreiben. Denn ich mag nicht 
glauben, dass man beim 1601-LCD eine "Spezialversion" des HD44780 
eingesetzt hat, bei der die (Set DD-RAM-Address-) Basisadresse der 
zweiten DD-RAM-Zeile anders ist als bei allen anderen HD44780-LCDs.

Ich verlasse mich da eben nicht nur auf eine einzige Informationsquelle. 
Im Datenblatt des HD44780 (Seite 11/12) sehe ich, dass die 
Adresszuordnung bei Initialisierung als einzeilig oder zweizeilig 
unterschiedlich ist. Bei einzeilig ist der DD-RAM von Adresse $00 bis 
$4f durchgehend ansprechbar.

Die meisten LCDs sind aber zweizeilig adressiert, da teilt sich der 
DD-RAM in zwei Bereiche auf, $00 bis $27 für die erste Zeile und $40 bis 
$67 für die zweite Zeile.

Ich hänge mal ein anderes Dokument an, in dem die Adressen ganz gut 
beschrieben sind. Man beachte die Tabelle auf Seite 6.

Achja, wenn es sein muss, kann ich Dir noch ein paar Datenblätter zu 
HD44780-LCDs posten (2x16, 2x24), in denen die Basis-Adresse für die 
zweite Zeile auch mit 64 (192) angegeben ist.

>
> Schönen Tag noch, Uwe

Den wünsche ich Dir auch...
Hannes

von Axel H. (mf-futzi)


Lesenswert?

Hallo an alle,

ich wende mich nun nochmal an euch. Ich habe nun meinen Code so 
geändert:

.include "m8def.inc"

.def temp10 = r16


  ldi temp10, LOW(RAMEND)        ;LOW-Byte der obersten RAM-Adresse
      out SPL, temp10
      ldi temp10, HIGH(RAMEND)        ;HIGH-Byte der obersten 
RAM-Adresse
      out SPH, temp10

      rcall lcd_init            ; Display initialisieren
      rcall lcd_clear            ; Display löschen

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ldi ZL, LOW(text1*2)
     ldi ZH, HIGH(text1*2)

      rcall lcd_flash_string          ;text1 ausgeben

     ldi temp1 , $A8
     rcall lcd_command

     ldi ZL, LOW(text2*2)
     ldi ZH, HIGH(text2*2)

      rcall lcd_flash_string          ;text 2 ausgeben

 loop:
     rjmp loop

   text1:
       .db "TESTABCD",0,0       ; String, durch '0' angeschlossen
   text2:
       .db "12345678",0,0      ; String, durch '0' angeschlossen


.include "lcd-routines.asm"

Mein Display zeigt nun 'TESTABCD12345678'    :-)

Nur sollte nach meiner Einstellung in den LCD-Routines der Cursor 
blinken. Tut er aber nicht.

ldi   temp1,    0b00001111   ; Display on, Cursor on, Cursor blinken
rcall lcd_command

Das ist doch OK?

Axel

von Axel H. (mf-futzi)


Lesenswert?

Hallo,

kann mir nochmal jemand einen Tipp geben, warum der Cursor nicht blinkt?

Vielen Dank
Axel

von Uwe (Gast)


Lesenswert?

Hi!
Hatte ich also doch recht, $A8 ist 2.Zeile Zeichen1. Wohl doch nicht so 
ganz HD44780.
>kann mir nochmal jemand einen Tipp geben, warum der Cursor nicht blinkt?
Gegenfrage: An welcher Stelle würdest du den Kursor denn vermuten?
Mal so als Tip, momentan ist autoshift eingeschaltet.
Schreibe mal:
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ldi ZL, LOW(text1*2)
     ldi ZH, HIGH(text1*2)

      rcall lcd_flash_string          ;text1 ausgeben

     ldi temp1 , $A8
     rcall lcd_command

     ldi ZL, LOW(text2*2)
     ldi ZH, HIGH(text2*2)

      rcall lcd_flash_string          ;text 2 ausgeben

    ldi temp1 , $80
     rcall lcd_command
            :
            :
Wenn es jetzt nirgends blinkt müssen wir nochmal schauen, aber ich denke 
es blinkt.

Viel Erfolg, Uwe

von Axel H. (mf-futzi)


Lesenswert?

Hallo Uwe,

jetzt bin ich richtig happy :-), es funzt. Text korrekt. Der Cursor 
blinkt an der ersten Stelle. Cursor ein- und ausschalten funzt prima.

Für alle, die auch das LCD 161F BL verwenden hier mein Code:

.def temp10 = r16
    ldi temp10, LOW(RAMEND)        ;LOW-Byte der obersten 
RAM-Adresse
      out SPL, temp10
      ldi temp10, HIGH(RAMEND)        ;HIGH-Byte der obersten 
RAM-Adresse
      out SPH, temp10

      rcall lcd_init              ; Display initialisieren
      rcall lcd_clear              ; Display löschen

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ldi ZL, LOW(text1*2)
     ldi ZH, HIGH(text1*2)

  rcall lcd_flash_string            ;text1 ausgeben

     ldi temp1 , $A8
     rcall lcd_command


     ldi ZL, LOW(text2*2)
     ldi ZH, HIGH(text2*2)

        rcall lcd_flash_string            ;text 2 ausgeben

     ldi temp1 , $80
     rcall lcd_command


 loop:
     rjmp loop

   text1:
       .db "Hallo, i",0,0           ; String, durch '0' angeschlossen
   text2:
       .db "ch bin's",0,0          ; String, durch '0' angeschlossen


.include "lcd-routines.asm"

Besten Dank an Uwe

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.