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ß
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.
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?
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)?
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
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...
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.
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
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
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
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...
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!