Forum: Mikrocontroller und Digitale Elektronik LCD verhaspelt sich sporadisch


von Andreas (Gast)


Lesenswert?

Hallo,

ich hab ein kleines Problem und ich komme nicht darauf wovon es kommt.
Den Code zu posten würde denk ich keinen Sinn machen da das Programm zu 
umfangreich ist.

Es geht um folgendes:

Ein Timer1 löst alle 1ms eine ISR aus:
    In dieser ISR ist ein counter, der bis 1000zählt.
    Ist der Counter 1000 wird mein 2x16 Display upgedated.

So, nun baue ich mein Hexfile (auf einem ATMEGA32) und spiele es drauf. 
Das Programm läuft zu 100% fehlerfrei.

Wenn ich nun ein anderes mal baue und das programm lade/starte läuft es 
zu 90%. Die funktionalität ist komplett gegeben. Allerdings Zeigt dass 
Display ca. alle 10s etwas falsches an (nur bis zu nächsten update in 
1s).

Bsp.1: (sende string an lcd function)
aus:
"Decontamination end " wird
"mination nation end " .

Bsp.2: (sende integer an lcd function)
aus:
"Operating hours" (zeile 1 ohne fehler / string function)
"0" oder "255" statt (zeile 2 /int function)
"33"

Also irgendwie scheint wohl was durcheinander zu laufen, Aber ich weiß 
nicht wo. Denn die update lcd function wird nur jede sekunde aufgerufen, 
also was soll da schief laufen?

Das LCD benutzt einen anderen Timer.


Ich weiß dass es recht wenig informationen sind, allerdings möchte ich 
auch keinen fertigen Quellcode, sondern nur eine Richtung wie ich den 
Fehler (was wohl ein Timingfehler ist) eingrenzen kann.

Gruß

von Johannes O. (jojo_2)


Lesenswert?

Was ist das für ein Display? Frägst du das Busy-Flag ab bevor du 
sendest?
Du musst auch das Timing des Displays generell beachten, mache an ein 
paar Stellen testweise(!) einfach mal kurze Wartezeiten rein und schaue 
ob es sich dann bessert.

von cskulkw (Gast)


Lesenswert?

Die sollten aber schon reichen.

Also wenn Du das Display asynchron zur Datenerfassung betreibst, dann 
muß du Semaphoren nutzen.

Sprich, wenn Dein Erfassungsalgorithmus alle 1ms sprich 1000 in der 
Sekunde einen String erstellt, den das arme Display ausgeben soll, kotzt 
es irgendwann mal ab oder mit andern Worten ist einfach noch nicht mit 
dem lezten Job fertig. Das würde

Andreas schrieb:
> "Decontamination end " wird
>
> "mination nation end " .

erklären.

Als sofortmassnahme solltest Du mal die 1ms auf 100ms hochschrauben und 
schauen, ob dann dieser Fehler auftritt. Wenn nein, dann muß Du mit 
Ausgabepuffern arbeiten. Ich habe mir für das LC-Display eine 
Serviceroutine geschrieben, die im Leerlauf while(1){Arbeitejobs ab...} 
läuft.
LC_Print() ist die Schnittstelle und liefert false, wenn der Puffer voll 
und noch nicht abgearbeitet ist.

Als zweite Massnahme solltest Du mal überprüfen, ob nur Teile der 
Strings aktualisiert werden müssen. Das spart Ausführungszeit.

Temperatur: xxx

-> Temperatur nur zur Ini oder Modiwechsel einmal ausgeben und xxx den 
Wert also, so oft aktualisieren, wie Du es für notwendig hälst.

Aber ein 1ms- Task ist schon heftig. Ist die wirklich notwendig? Oder 
willst Du nur wissen, was geht?

von Andreas (Gast)


Lesenswert?

Das display Treiber ist ein HD44780 2x16.

Es hat (natürlich) nichts mit dem bauen/draufladen zu tun. Hatte grad 
den Fehler im Programm drin, durch ab und zu schalten von der Versorgung 
des Boards funktioniert es jetzt einwandfrei.

Kommt also eher drauf an, wann welcher button gedrückt wird, und dieser 
"schlägt" wohl in die Display routine.

Ob das busyflag ausgelesen wird kann ich nicht sagen, da lib nicht von 
mir, aber ich schaue mal rein. Wäre es eine alternative (sicher nicht 
perfekt) während das Display sendet (in string und int function) die 
globalen interrupts zu sperren und dann wieder freizugeben (also am 
anfang und ende jeder funktion)?

von Peter D. (peda)


Lesenswert?

Man kann nicht von 2 verschiedenen Funktionen auf ein Stream-Device 
zugreifen, wenn eine die andere unterbrechen kann.
Durch das Unterbrechen wird der gerade laufende Stream zerstückelt.

- LCD nur im Main: geht
- LCD nur im Interrupt: geht
- LCD im Main und Interrupt: verboten!


Peter

von cskulkw (Gast)


Lesenswert?

Wenn Du im LCD-Timerinterrupt die Zeile ausgibst könnte es klappen, dass 
der andere Interrupt nicht unterbricht. Wenn der Ausfall dieser 
Erfassung Dir nicht weh tut, mach es...

von Andreas (Gast)


Lesenswert?

Das könnte die richtige Richtung sein Peter!

Wie gesagt das LCD wird per ISR alle sekunde upgedated.
Allerdings möchte ich es auch beim Druck von bestimmten Buttons aus 
aktualisieren.

Beispielsweise wenn ich den Button (switch display) drücke möchte ich 
dass sich das Display SOFORT updated - fernab vom Interrupt.

Mal schauen wie ich das umstricken kann.

Jedenfalls konnte ich so durch die Bedienung im Programm den Fehler 
bannen, bzw. mal reproduzieren.

von dunno.. (Gast)


Lesenswert?

das für mich naheliegendste verfahren wäre dann, eine task/funktion zu 
haben, die exklusiv das display ansteuert, und ihre daten eben aus den 
beiden anderen tasks/funktionen, zb per ringbuffer, bezieht...

mfg

von Peter D. (peda)


Lesenswert?

Als elegante Lösung kann man einen Timerinterrupt aufsetzen, der z.B. 
alle 1ms ein Byte aus nem Puffer ausgibt.

Und alle Ausgabefunktionen schreiben nur in diesen Puffer. Wenn sie an 
verschiedene Adressen des Puffers schreiben, kommen sie sich nicht in 
die Quere.
Als angenehmen Nebeneffekt hat man auch keine Verzögerungen durch das 
langsame LCD mehr.

Z.B.:
Beitrag "Formatierte Zahlenausgabe in C"


Peter

von Thorsten S. (thosch)


Lesenswert?

Andreas schrieb:

> Beispielsweise wenn ich den Button (switch display) drücke möchte ich
> dass sich das Display SOFORT updated - fernab vom Interrupt.
>
> Mal schauen wie ich das umstricken kann.

Verlege doch einfach die Displayausgaberoutine aus dem Interruptservice 
in die Hauptprogrammschleife.
Deine Interrupt-Service-Routine setzt dann einfach nur eine globale 
Flag-Variable, um eine Ausgabe anzufordern, wenn wieder eine Sekunde 
abgelaufen ist.

Die Displayroutine macht nur bei gesetztem Flag die Ausgabe und löscht 
das Flag wieder.

Bei einem Druck auf einen der Buttons, setzt Du auch das Flag oder 
machst direkt eine entsprechende Displayausgabe, das wäre ja nun auch 
möglich, da keine konkurrierende Displayausgabe mehr im Interrupt 
erfolgt.

Gruß,
Thorsten

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Andreas schrieb:
> Das Programm läuft zu 100% fehlerfrei.
Das möchte ich mal von meinen Programmen auch behaupten können. Aber 
damit hättest du eine große Sorge weniger, und das Problem kann ja nur 
noch in der Hardware sein. Glaubst du das?

> allerdings möchte ich auch keinen fertigen Quellcode
Du könntest allerdings DEINEN posten. Aber der kanns ja nicht sein...

von Andreas (Gast)


Lesenswert?

Thorsten S. schrieb:
> Andreas schrieb:
>
>> Beispielsweise wenn ich den Button (switch display) drücke möchte ich
>> dass sich das Display SOFORT updated - fernab vom Interrupt.
>>
>> Mal schauen wie ich das umstricken kann.
>
> Verlege doch einfach die Displayausgaberoutine aus dem Interruptservice
> in die Hauptprogrammschleife.
> Deine Interrupt-Service-Routine setzt dann einfach nur eine globale
> Flag-Variable, um eine Ausgabe anzufordern, wenn wieder eine Sekunde
> abgelaufen ist.
>
> Die Displayroutine macht nur bei gesetztem Flag die Ausgabe und löscht
> das Flag wieder.
>
> Bei einem Druck auf einen der Buttons, setzt Du auch das Flag oder
> machst direkt eine entsprechende Displayausgabe, das wäre ja nun auch
> möglich, da keine konkurrierende Displayausgabe mehr im Interrupt
> erfolgt.
>
> Gruß,
> Thorsten

Gute Idee!
Genau die selbe hatte ich beim Hochfahren des PCs heute morgen auch. 
Trotzdem vielen vielen Dank!

Mit dem Flag das alle s in der ISR gesetzt wird fühle ich mich auch um 
einiges wohler als in der ISR direkt das Display zu aktualisieren.

Merci, und einen schönen Tag noch!

von Falk B. (falk)


Lesenswert?

Siehe Interrupt

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.