Forum: Mikrocontroller und Digitale Elektronik LCD Inhalt regelmässig aktualisieren


von Sebastian (Gast)


Lesenswert?

Guten morgen zusammen,

Ich habe ein Problem mit einem LCD. Und zwar habe ich in uregelmässigen
Abständen (1 Monate bis 11 Monate) das Problem das das LCD plötzlich nur
noch Hyroglyphen anzeiget. Der uC selbst läuft aber ohne probleme in
seiner Software weiter das erkenne ich an LEDs und ich kann noch "Blind"
durch das Menu steuern welches eigentlich auf dem LCD angezeigt werden
sollte.


Ich weiss nicht woher das kommt und es Tritt sooo selten auf das ich es
nicht nachvollziehen kann Wie schon geschrieben Zeitspanne ist so
zwischen 1 bis 11 Monate.


Meine Idee war jetzt das LCD Regelmässig neu zu initialisieren und den
Inhalt der drauf stand wieder aufs LCD zu schreiben.

Um festzustellen was mal auf dem Display stand würde ich gerne Jegliche
Ausgabe die ich auf das LCD schreibe in meinen Speicher des uC speichern

Das wäre bei meinem 4x20 Zeichen Display 80 Bytes. und dann hätte ich
ein komplettes abbild des LCDs in meinem Speicher drin.


Ich habe schon etwas dazu geschrieben aber das ist noch sehr
unausgereift. und ich wollte erstmal eure Meinung anhören was ihr so
dazu denkt.


Schöne Grüße

von gfhf (Gast)


Lesenswert?

statische ladungen ?

die typischen LCDs sind da recht empfindlich ...

ich beschreibe dazu gerne eine ungenutzte RAMzelle
und lese diese zyklisch aus.

stimmt der wert ==  ist es egal
ist der wert !=  dann folgt ein LCD reset

witzigerweise ist selbst das manchen LCDs egal ..
dann hilft nur LCD über einen PIN aus/einschalten

von Frank M. (frank_m35)


Lesenswert?

Das Display wird wohl kurzzeitig gestoert werden, bspw. durch 
Spannungsschwankungen. Wie sieht deine Beschaltung aus? Kondensatoren 
ausreichend vorhanden, gut gewaehlt und gut platziert?

Was passiert sonst noch auf deiner Schaltung? Schaltest du irgendwas 
groesseres ein/aus. Wo ist deine Schaltung platziert, ist in der nahen 
Umgebung etwas besonderes?

Warum musst du das Display so umstaendlich neu laden? Weisst du nicht 
was drauf ist? Also dein uC schreibt doch auf das Display Werte. Warum 
das Display nicht resetten und die Werte eben einfach neu drauf 
schreiben?

Ansonsten kannst eben so einen Pseudo-Double-Buffer implementieren, als 
ein 80 Byte Array.
Wenn du Display-Interne Funktionen verwendest bietet es sich vielleicht 
an das Array immer nach einer dieser Funktionen durch Auslesen des 
Display-RAM vom Display direkt zu laden. Zur Sicherheit kannst du 
ueberpruefen ob der Inhalt Hyroglyphen enthaelt.

von Falk B. (falk)


Lesenswert?

@Sebastian (Gast)

>Abständen (1 Monate bis 11 Monate) das Problem das das LCD plötzlich nur
>noch Hyroglyphen anzeiget.

LCD Controller abgestürzt.

>Ich weiss nicht woher das kommt und es Tritt sooo selten auf das ich es
>nicht nachvollziehen kann Wie schon geschrieben Zeitspanne ist so
>zwischen 1 bis 11 Monate.

Sehr lange.

>Meine Idee war jetzt das LCD Regelmässig neu zu initialisieren und den
>Inhalt der drauf stand wieder aufs LCD zu schreiben.

Jo. Hab ich auch schon gemacht.

>Um festzustellen was mal auf dem Display stand würde ich gerne Jegliche
>Ausgabe die ich auf das LCD schreibe in meinen Speicher des uC speichern

Kann man machen, ist aber nur eine von vielen Möglichkeiten.

>Das wäre bei meinem 4x20 Zeichen Display 80 Bytes. und dann hätte ich
>ein komplettes abbild des LCDs in meinem Speicher drin.

Jo.

>Ich habe schon etwas dazu geschrieben aber das ist noch sehr
>unausgereift. und ich wollte erstmal eure Meinung anhören was ihr so
>dazu denkt.

Je nach Programm hat man so oder so eine Funktion, welche einen 
vollständigen Update des LCDs macht. Die kann man dafür nutzen, dann 
braucht man nicht die 80 Byte zusätzlichen Speicher. Wenn man 1x pro Tag 
das LCD neu initialisiert und dann einen kompletten Update macht, passt 
das schon. Wenn man es richtig macht, kriegt das auch keiner mit.

Bei der Variante mit den 80 Byte Extra Puffer im uC hat man ach das 
Problem, das man alle LCD-Zufriffe auf diesen Puffer ändern muss. 
Allerdings sind die dann deutlich schneller, was in eingen Fällen 
vorteilhaft sein kann.

Bei meiner schaltung habe ich einmal pro Sekunde das LCD neu 
initialisiert ;-), weil ich das EMV-Problem nicht beheben konnte. Aber 
auch dort sieht man das im Normalbetrieb nicht, nur wenn der Absturz 
eingetreten ist.

von Sebastian (Gast)


Lesenswert?

Die herkömmlichen HD44780-Displays sind meist empfindlich gegen 
Störeinstrahlungen. Wie empfindlich, hängt oft vom Layout des Displays 
ab, ich habe schon miterlebt, daß eine spätere Revision eines 
Herstellers schlechter war als eine frühere.
Zum Ausfall (vergessen der Initialisierung, softwaremäßig 
zurückzusetzen) können leitungsgebundene Störungen führen (Relaisspulen 
u.ä.), aber auch elektrostatische Entladungen in Displaynähe, oder 
ausreichend starke HF-Einstrahlung.
Neben zyklischer Re-initialisierung kann auch eine letifähig 
beschichtete Schutzscheibe vor dem Display helfen.

von Sebastian (Gast)


Lesenswert?

Jo nur habe ich ein Problem: Für die erklärung reduzieren ich es mal auf 
eine Zeile:

gehen wir von folgendem fiktiven szenario aus.
Ich gebe auf meinem Display folgendes aus:
1
char out[21];
2
  sprintf(out, "Menu1: TEST"); 
3
  set_cursor(0,1);
4
  lcd_string( out );
5
  
6
  char bufferuC[21];
7
  strcpy( &bufferuC[0], out);

dadurch steht in meinem bufferuC das was im string out steht und das 
steht nun auch auf dem LCD

Es kommt in der Software vor das ich dann meinen Cursor auf
set_cursor(5,1);
stelle
und nun das "Menu1" auf "Menu2" als Faktisch ändere ich nur die 1 auf 2

Wie sage ich das meinem Buffer das sich nun an der stelle 5 etwas 
gehändert hat ?

Wie füge ich die Beiden Strings so ein einander das sich nur das eine 
byte in dem String ändert ?

Schöne Grüße

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:

> Wie sage ich das meinem Buffer das sich nun an der stelle 5 etwas
> gehändert hat ?

Ich denke da liegt ein Missverständnis vor.

Du hast in deinem Programm ein

char LCDBuffer[4][20];

und dieses Char-Array IST ab sofort dein LCD!
Alle Ausgaben landen ausnahmslos in diesem Buffer, egal wie sie zu 
STande kommen.

Und ein anderer Mechanismus sorgt dann dafür, dass dieser Buffer 
regelmässig an das LCD upgedatet wird. Aber für dein Programm ist dieses 
char-Array die Ausgabefläche. D.h. du musst dein Programm derart 
umbauen, dass erst mal
* es einen Mechanismus gibt, der laufend das LCD von diesem Buffer
  aus nachzieht. Zb mit einem Timer-Interrupt, in dem laufend 1, 2
  Zeichen aus dem Buffer ans LCD übertragen werden, bis alles draussen
  ist und dann läuft alles wieder von vorne
* alle Ausgaben deines Programmes ausnahmslos in diesem Buffer
  landen.
  Ja das bedeutet auch, dass du dir Ersatz für Funktionen wie
  lcd_clear oder set_cursor oder lcd_string machst, die diese
  Operation dann eben in diesem Buffer abbilden.
  Du programmierst dir Funktionen, so dass der Inhalt des Buffers für
  dein Programm sich wie ein LCD verhält.

>
> Wie füge ich die Beiden Strings so ein einander das sich nur das eine
> byte in dem String ändert ?

Gar nicht.
Warum sollte man das machen wollen?

Wenn du am LCD sen String "Menü 1" stehen haben willst, dann gibst du 
den Text "Menü 1" aus. Soll dort "Menü 2" stehen, dann wird eben der 
Text "Menü 2" ausgegeben. Soll dort "Schnurdibur" stehen, dann wird eben 
der Text "Schnurdibur" ausgegeben.

von ah. (Gast)


Lesenswert?

Ich habe auch einen Buffer, der automatisch ans LCD ruebergeschrieben 
wird. Und zwar im Timer Tick. Jede 10ms wird ein Zeichen aus dem Buffer 
in das Display geschrieben. Und meine Software Funktionalitaet muss 
daher nur den Buffer beschreiben.
Falls man nun auch den Fall abdecken will, in dem der LCD Controller 
aussteigt, muss man nur alle Minuten oder so die komplette 
Initialisierungs Sequenz ans LCD wiederholen.

von Sebastian (Gast)


Lesenswert?

Achso Karl Heinz,

Das hört sich sehr gut an. Nur muss ich dann das gesammte programm ja 
umschreiben.

Da fehlt mir gerade ein wenig der Denkansatz zu der umwandlung von 
Setcurser auf das Array
denn ich Rufe ja immer Set_curser auf und bestimme die Position des 
Cursers auf dem LCD.

Diese information ist natürlich auch enorm Wichtig den Buffer. Denn der 
Text String der dann an die Position des Cursors auf dem LCD geschrieben 
werden soll. Soll dann natürlich in den Buffer geschrieben werden.

Bei dieser Umwandlung hängts gerade gedanklich bei mir.


ah. könntest du deinen Qullcode fuer die Umwandlung mal posten ?

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:

> Das hört sich sehr gut an. Nur muss ich dann das gesammte programm ja
> umschreiben.

Tja.

> Da fehlt mir gerade ein wenig der Denkansatz zu der umwandlung von
> Setcurser auf das Array
> denn ich Rufe ja immer Set_curser auf und bestimme die Position des
> Cursers auf dem LCD.

Na komm so schwer ist das nicht
1
char LCDBuffer[4][20];
2
uint8_t actLine;
3
uint8_t actColumn;
4
5
6
void set_cursor( uint8_t line, uint8_t column )
7
{
8
  actLine = line;
9
  actColumn = column;
10
}
11
12
void lcd_data( char c )
13
{
14
  LCDBuffer[actLine][actColumn] = c;
15
  actColumn++;
16
}
17
18
void lcd_string( const char* str )
19
{
20
  while( *str )
21
    lcd_data( *str++ );
22
}
23
24
void lcd_home()
25
{
26
  actLine = 0;
27
  actColumn = 0;
28
}
29
30
void lcd_clrs()
31
{
32
  uint8_t i, j;
33
34
  for( i = 0; i < 4; i++ )
35
  {
36
    for( j = 0; j < 20; j++ )
37
      LCDBuffer[i][j] = ' ';
38
  }
39
40
  lcd_home();
41
}
42
43
....

Sicherheitshalber sollte noch ein wenig Absicherung da rein, so dass man 
nicht out of bounds ans Array zugreift. Hab ich mir jetzt mal gespart.


EDit:
Und ob das so schlau ist, die Funktionen 1:1 gleich zu nennen, wie die 
originalen LCD Funktionen ... nach ein wenig Sinnieren finde ich das 
keine so gute Idee mehr.

von oh. (Gast)


Lesenswert?

Man muss sich den fuer den Benutzer stehenden Cursor merken.

von Sebastian (Gast)


Lesenswert?

Oh mann stehe ich auf dem Schlauch. Ja natürlich Vielen Dank.

Ich glaube ich sollte erstmal was die sonne geniessen ich habe ja eine 
ganze holz huette vorm kopp xD


Vielen Vielen Dank

von Sebastian (Gast)


Lesenswert?

Nein ich habe an alle funktionen ein _buffer drangehangen also so siehts 
aus:
1
void set_cursor_buffer( uint8_t line, uint8_t column )
2
{
3
  actLine = line;
4
  actColumn = column;
5
}
6
7
void lcd_data_buffer( char c )
8
{
9
  LCDBuffer[actLine][actColumn] = c;
10
  actColumn++;
11
}
12
13
void lcd_string_buffer( const char* str )
14
{
15
  while( *str )
16
    lcd_data_buffer( *str++ );
17
}
18
19
void lcd_home_buffer()
20
{
21
  actLine = 0;
22
  actColumn = 0;
23
}

von Karl H. (kbuchegg)


Lesenswert?

und halt die ganzen anderen Funktionen, die du sonst noch so vom LCD 
benutzt. Wenn du benutzerdefinierte Zeichen benutzt, dann musst du die 
zwischenspeichern, wenn du Display-Shift benutzt, dann musst du dir das 
merken, etc. etc.

Eben: Du schreibst einen Ersatz für ein LCD, der sich aus Sicht deines 
Programms wie ein LCD verhält und sich alles merkt, damit er
a) das LCD in genau diesen Zustand bringen kann
b) und das zu jeder Zeit
c) im laufenden Betrieb, denn schliesslich will der Benutzer ja auch
   was sehen :-)


wobei c) durchaus auch 'in Raten passieren kann'. Wie weiter oben schon 
mal wer geschrieben hat, updatet er das LCD alle 1ms mit jeweils dem 
nächsten Zeichen aus dem Buffer. 1ms, das sind 1000 Update pro Sekunde, 
du hast 80 Zeichen, schaffst also in 1 Sekunde mehr als 10 komplette 
Refreshes des LCD. Das reicht dicke, weil sowieso kein Mensch schneller 
lesen kann.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz Buchegger (kbuchegg) (Moderator)

>mal wer geschrieben hat, updatet er das LCD alle 1ms mit jeweils dem
>nächsten Zeichen aus dem Buffer. 1ms, das sind 1000 Update pro Sekunde,

1000 Zeichen / s

>du hast 80 Zeichen, schaffst also in 1 Sekunde mehr als 10 komplette
>Refreshes des LCD.

12,5 ;-)

> Das reicht dicke, weil sowieso kein Mensch schneller
> lesen kann.

Schon gar nicht auf einem einfachen LCD, welches selber recht träge ist.

von Sebastian (Gast)


Lesenswert?

jo genau daran begebe ich mich jetzt es funktioniert jetzt so das ich 
meinen LCDBuffer fülle.

Nun kommt es gleich dazu das der Inhalt vom LCDBuffer an das LCD 
gesendet wird.

Dafür müsste ich doch erstmal den inhalt von sagen wir mal Zeile 1 im 
Buffer zu einem String formatieren den ich dann mit lcd_string senden 
kann oder?

von spess53 (Gast)


Lesenswert?

Hi

>Dafür müsste ich doch erstmal den inhalt von sagen wir mal Zeile 1 im
>Buffer zu einem String formatieren den ich dann mit lcd_string senden
>kann oder?

Wozu? Der String wird auch nur zeichenweise an das LCD gesendet. Also 
kannst du auch gleich die Zeichen einzeln aus dem Puffer senden.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Sebastian schrieb:

> Dafür müsste ich doch erstmal den inhalt von sagen wir mal Zeile 1 im
> Buffer zu einem String formatieren den ich dann mit lcd_string senden
> kann oder?

machs nicht so kompliziert
1
uint8_t refreshLine;
2
uint8_t refreshColumn;
3
4
ISR( ..... )
5
{
6
  lcd_data( LCDBuffer[refreshLine][refreshColumn] );
7
8
  refreshColumn++;
9
  if( refreshColumn == 20 )
10
  {
11
    refreshColumn = 0;
12
    refreshLine++;
13
    if (refreshLine == 4 )
14
      refreshLine = 0;
15
16
    set_cursor( refreshLine, refreshColumn );
17
  }
18
}
(hier sind natürlich die originalen LCD ROutinen gemeint. Denn hier muss 
ja wirklich ans LCD übertragen werden.

Einzig bei den Wartezeiten nach einer LCD-Übertragung muss man ein wenig 
aufpassen. zb wird man nach lcd_data im Normalfall (wenn kein set_cursor 
hinten nach kommt), keine Wartezeit mehr benötigen, weil ja ohnehin 
sicher gestellt ist, dass das nächste Zeichen erst mit dem nächsten 
Interrupt (zb 1 ms später) kommt.

von Frank M. (frank_m35)


Lesenswert?

Ich bin der Meinung du brauchst keinen echten Zwischen-Buffer. 
Schließlich hast du ja kein Grafikdisplay, das flackert wenn du zu 
langsam das Display updatest. Und immer das ganze Display neu aus dem 
Buffer zu beschreiben finde ich persönlich für unnötig.
Ebenso das ständige Updaten mittels eines Interrupts ist recht sinnfrei.


Du hast deine Displayroutinen mit SetCursor, lcd_Data, ...
Was spricht dagegen, in diese Routinen zusätzlich zur Ausgabe auf das 
Display das Zeichen in einen Buffer zu schreiben? (Diese Funktionen hast 
du ja hier schon bekommen). Also in der Art zwei Displays, eines ist das 
reale, das andere der Buffer, in beide wird gleichzeitig geschrieben.

Falls das Display sich verabschiedet hat, dann kannst du es resetten und 
mit dem Buffer abgleichen.

von Ich (Gast)


Lesenswert?

Frank M. schrieb:
> Ebenso das ständige Updaten mittels eines Interrupts ist recht sinnfrei.

Das entkoppelt die ganze Geschichte.
Wenn man in Hintergrund einen Puffer hat der immer wieder an das Display 
geschickt wird, dann können alle Funktionen ohne jede Verzögerung 
arbeiten.

Verschiedene Programmteile können unabhängig voneinander ohne 
ausgebremst zu werden dröfmal+x pro Sekunde den Puffer beschreiben, die 
Änderungen kommen dann irgendwann mal auf dem Display an.

So Funktionen mit Namen wie lcd_write_string() die direkt ins Display 
schreiben müssen nach jedem Zeichen ein delay() einwerfen oder in einer 
Schleife nachfragen ob das Display schon fertig ist.

Wenn der Anwender in dieser Zeit z.B. einen Taster betätigt kann der 
Controller auf sowas garnicht reagieren.

von Pete K. (pete77)


Lesenswert?

Gibt es schon Rückmeldung zum Thema Hardware? Einen Kondensator 
hinzuzufügen kann einfacher sein, als das Programm umzuschreiben und zu 
testen.

von Peter D. (peda)


Lesenswert?

Man sollte auch SW-Fehler nicht außer acht lassen (Race-Conditions).
Z.B. Zugriffe auf andere Pins der LCD-Ports.
Oder LCD-Ausgaben im Interrupt und Main.

von oh. (Gast)


Lesenswert?

>Falls das Display sich verabschiedet hat, dann kannst du es resetten und
mit dem Buffer abgleichen.


Und wie stellt man fest, ob sich das Display verabschiedet hat ? Das 
Ready auswerten ? Vielleicht. Ich verwende das Ready allerding nie.

von oh. (Gast)


Lesenswert?

>Wenn der Anwender in dieser Zeit z.B. einen Taster betätigt kann der
Controller auf sowas garnicht reagieren.

Eine Taste ist nie so schnell wie das display. Zudem sollte man eine 
Taste eh entprellen.

von Axel S. (a-za-z0-9)


Lesenswert?

Frank M. schrieb:
> Ich bin der Meinung du brauchst keinen echten Zwischen-Buffer.
> Schließlich hast du ja kein Grafikdisplay, das flackert wenn du zu
> langsam das Display updatest. Und immer das ganze Display neu aus dem
> Buffer zu beschreiben finde ich persönlich für unnötig.

Im Prinzip auch meine Meinung - man sollte IMHO immer nur machen, was 
auch nötig ist. Es gibt aber durchaus noch Möglichkeiten:

1. man führt eine Statusvariable, die Veränderungen des Buffers trackt. 
So lange der Buffer nicht verändert wird, braucht man das LCD auch nicht 
zu aktualisieren.

2. Wie 1. aber mit feinerer Granularität, bspw. für einzelne Zeilen 
eines Textdisplays.

Ebenso würde ich den Refresh des Displays eher am Stück machen als in 
einem (langsamen) Timerinterrupt. Ein Schreiber erwähnte mal 10ms. Ein 
4x20 Display braucht dann schon satte 800ms für den Refresh. Das sieht 
man, gerade wenn große Änderungen dabei sind. Ideal wäre ein Interrupt 
vom Display, wenn es das letzte Zeichen "gefressen" hat. Andererseits 
braucht ein HD44780 gerade mal ~40µs für einen Schreibzugriff auf das 
Display-RAM.


XL

von Peter D. (peda)


Lesenswert?

Axel Schwenke schrieb:
> Ebenso würde ich den Refresh des Displays eher am Stück machen als in
> einem (langsamen) Timerinterrupt.

Nö.
Der Trick an der Timerlösung ist ja gerade, daß alles Warten wegfällt.
Der Timerinterupt schreibt nur ein Byte und kümmert sich garnicht um das 
Busy. Und das Main schreibt alle Ausgaben sauschnell in das SRAM.
Die CPU hat also viel mehr Zeit für andere Tasks übrig.

von Sebastian (Gast)


Lesenswert?

Eine Hardware Lösung wärenatürlich Optimal. Aber Die üblichen Puffer 
Elkos sowie Kondensatoren befinden sich direkt an der Verbindung zum LCD 
so wie am Eingang der Versorgungspannung vom uC.



Die Software ist jetzt übernacht auch soweit angepasst worden das jede 
funktion die Früher das LCD angesprochen hat nun meinen Buffer anspricht 
jetzt gucken ich nur noch nach einer angenehmen zeit in der das Display 
kontinuirlich beschrieben werden soll

von Roman (Gast)


Lesenswert?

Hallo zusammen,

was meiner Meinung nach in der gesamten Diskussion nicht genügend 
beachtet wurde, ist die Frage wie stelle ich fest das sich das Display 
verabschiedet hat und neu initialsiert werden muss.

Gruss

Roman

von Sebastian (Gast)


Lesenswert?

Da habe ich leider Keine möglichkeit zu ich werde es in regelmässigen 
abständen "einfach" neu initialisieren.

Muss mal schauen wie ich das am geschicktesten anstelle

von Roman (Gast)


Lesenswert?

Hallo zusammen,

ich habe mich da noch mal schlau gemacht. Mit der Kombination aus RS und 
RW Pin kann, laut AVR LCD Tutorial , der Inhalt des LCD's gelesen werden 
und theoretisch mit dem Inhalt des Buffers verglichen werden. Nur so als 
Idee, eine Umsetzung ist sicherlich ein Herausforderung für unsere 
Profis.

Gruss

Roman

von gfhf (Gast)


Lesenswert?

wenn der LCD µC komplett weg ist hilft auch eine neu-init manchmal nicht 
...
dann kann dein buffer noch so tolle zeichen enthalten
da hilft dann nur ein HW reset

Aus genau diesem grund hatte ich das wie oben geschrieben gemacht
das LCD war extrem empfindlich und bei berühren war das LCD leer

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.