Hi Leute!
Ich hab grad ein kleines Problem und hoffe, dass ihr mir helfen könnt.
Ich habe eine 7-Segmentanzeige an meinem uC, welche 6-fach gemuxt wird.
Die Anzeige hängt an zwei 595ern. Ich muss demnach 16 Bits reintakten.
Ich habe leider keinen Pin für SPI frei, daher per Bitbang und ohne
Interrupt fürs Senden.
Mittels Timer erzeuge ich mit 300Hz (50Hz für jede Stelle) einen
Interrupt, in denen ich die aktuelle Stelle raustakte und den
Stellenzähler inkrementiere. In der main wird dann das neue Datenwort
für die nächste Übertragung vorbereitet und beim nächsten Interrupt des
Timers rausgetaktet.
Das ganze funktioniert prinzipiell gut, aber wenn ich jetzt mehrere
Berechnungen durchführe (mit int64, also große Zahlen, aber alles
Festkomma), dann fängt die Anzeige an zu flackern. Es ist deutlich
erkennbar, dass das Flackern abhängig ist von den Zahlen, die verrechnet
werden müssen.
Wo setze ich jetzt an, um das zu beheben? Der Interrupt kommt ja
unabhängig vom Programmablauf, also müsste das raustakten immer im
gleichen Rhytmus erfolgen. Aber wieso verlangsamt sich das ganze dann
so?
Jemand einen Tip?
Dennis schrieb:> Wo setze ich jetzt an, um das zu beheben?
Code herzeigen.
Irgendwo werden die Interrupts per cli()/sei() zu lange abgeschaltet.
Und die Stelle heißt es jetzt zu finden.
> Mittels Timer erzeuge ich mit 300Hz (50Hz für jede Stelle) einen> Interrupt, in denen ich die aktuelle Stelle raustakte und den> Stellenzähler inkrementiere. In der main wird dann das neue Datenwort> für die nächste Übertragung vorbereitet und beim nächsten Interrupt> des Timers rausgetaktet.
Der erste Teil dieses Absatzes klingt soweit ok.
Der zweite Teil allerdings macht mir etwas Kopfzerbrechen. Was genau ist
damit gemeint?
-> Beschreib nicht deinen Code - zeige ihn.
Karl Heinz Buchegger schrieb:> Der zweite Teil allerdings macht mir etwas Kopfzerbrechen. Was genau ist> damit gemeint?
Höchstwahrscheinlich meint er, dass er die langen Berechnungen in der
main-loop durchführt und nur die Daten in der ISR raushaut.
Dennis schrieb:> Aber wieso verlangsamt sich das ganze dann> so?Karl Heinz Buchegger schrieb:> Code herzeigen.
Ingo schrieb:> Höchstwahrscheinlich meint er, dass er die langen Berechnungen in der> main-loop durchführt und nur die Daten in der ISR raushaut.
Genauso meine ich es.
Ich habe gerade mal mit dem Oszi gemessen, indem ich mir hier und da ein
Bein toggeln lasse - die Programmlaufzeit und die Interruptfrequenz
liegen sehr nahe beieinander, ein bisschen Varianz je nach aktuellem
Rechenaufwand natürlich außen vor gelassen. Kann das das Problem sein?
Nachtrag - hab jetzt gerade nochmal was geändert, und zwar in der
Funktion sr_build_data( void ) übergebe ich jetzt die variable
sr_control.digit_nr im Funktionsargument, da es sich ja theoretisch
während der Abarbeitung durch den Interrupt ändern könnte. Dennoch
ändert das nichts. Es flackert trotzdem. Probehalber habe ich mal den
Controller auf 12MHz gestellt (vorher 8), damit geht es dann. Dennoch
wüsste ich gerne, ob da vielleicht einfach ein Fehler im Code ist und es
auch mit 8MHz gehen würde.
Es flackert sogar (wenn auch nurnoch ganz leicht) wenn ich die
Buildfunktion direkt mit in die ISR nehme...das sollte doch nun
eigentlich echt nicht sein?!
Dennis schrieb:> Also hier mal ein Teil, das unwichtige ist raus:
Moment
> Die Timer ISR - 300Hz> [code]> // Timer 1 A1 interrupt service routine> #pragma vector = TIMER1_A1_VECTOR> __interrupt void Timer1_A1_ISR( void )> {> switch( TA1IV )> {> case 4: // CCR2> {> TA1CCR2 += DISPLAY_REFRESH_TIME;>> sr_bitbang_display_data_out();>> if( ++sr_control.digit_nr > 5 )> {> sr_control.digit_nr = 0;> }>> sr_set_flag( SR_FLAG__BUILD_NEW_DATA );
Ähm.
No.
Du willst hier sr_build_data aufrufen und das so zusammengebaute dann
auch tatsächlich auf den Port schreiben.
An dieser Stelle: kein Flag setzen und dann erst in der Hauptschleife
darauf reagieren. Hier - in der ISR - muss der tatsächlie Portzugriff
erfolgen, der dann auch das jeweils nächste Digit (bzw. die LED)
aufleuchten lässt.
> In der main wird dann das neue Datenwort für die nächste Übertragung> vorbereitet und beim nächsten Interrupt des Timers rausgetaktet.
Hat mich mein Gefühl doch nicht getrogen, dass da was nicht stimmt.
Karl Heinz Buchegger schrieb:> Du willst hier sr_build_data aufrufen und das so zusammengebaute dann> auch tatsächlich auf den Port schreiben.
Das passiert auch so. In der main wird die nächste Stelle generiert. In
der ISR wird die Stelle dann rausgeschoben und die Stelle inkrementiert.
Dann ein Flag gesetzt, welches in der main signalisiert, dass die
nächste Stelle zusammengabeut werden muss. In der main wieder
zusammenbauen, in der ISR verschiecken, inkrementieren, ...
Multiplexen geht so:
Der Timerinterrupt gibt die Bitmuster aus, völlig egal, wann die erzeugt
wurden.
Und das Main wandelt ne Zahl in Bitmuster und speichert sie in einem
Array ab.
Braucht es dafür Jahre, gibt der Interrupt eben jahrelang den gleichen
Wert aus.
Flackern tut aber nichts.
Will mans ergonomisch, wartet das Main >=200ms, ehe es ne neue Zahl
berechnet. Dann kann man die Zahlen gut ablesen.
Dennis schrieb:> Es flackert sogar (wenn auch nurnoch ganz leicht) wenn ich die> Buildfunktion direkt mit in die ISR nehme...das sollte doch nun> eigentlich echt nicht sein?!
Hast du dran gedacht, die Flagsteuerung in der Hauptschleife still zu
legen?
Dennis schrieb:> Karl Heinz Buchegger schrieb:>> Du willst hier sr_build_data aufrufen und das so zusammengebaute dann>> auch tatsächlich auf den Port schreiben.>> Das passiert auch so. In der main wird die nächste Stelle generiert.
Die aszugebende Zahl berechnet. Ist ja auch ok.
Aber
> In> der ISR wird die Stelle dann rausgeschoben und die Stelle inkrementiert.> Dann ein Flag gesetzt, welches in der main signalisiert, dass die> nächste Stelle zusammengabeut werden muss.
Nein.
Wenn die main 5 Jahre nicht dazukommt diesen 'Stelle zusammenzubauen',
dann zeigen alle Digits 5 Jahre lang die zuletzt zusammengebaute Stelle
an.
In der ISR passiert alles.
weiterschalten zum nächsten Digit. Was ist dort anzuzeigen.
Das was dort anzuzeigen ist, das richtet man sich in einem Array her.
Bei dir sind es eben 6 Stück, weil du die einzelnen LED im Grunde wie
eine abgespeckte 7_Segment Anzeige behandlen kannst
und in segmentPattern kannst du jetzt in den einzelnen Bytes die Muster
zusammenstellen wann du willst und du kannst dir Zeit lassen so lange du
willst. Deswegen wird da nichts flackern. Aber dieser ISR-Raustakt
Mechanismus mit jeweils dem richtigen Word zum richtigen nextDigit, der
darf nie ins Stocken oder ausser Sync kommen. Dann flackerts
Peter Dannegger schrieb:> Der Timerinterrupt gibt die Bitmuster aus, völlig egal, wann die erzeugt> wurden.
So ist es bei mir. sr_bitbang_data_out() in der ISR mit 300Hz für 6
Stellen.
Peter Dannegger schrieb:> Und das Main wandelt ne Zahl in Bitmuster und speichert sie in einem> Array ab.
Das passiert bei mir auch in der main wird ein Array, welches die
einzelnen Stellen enthält (sr_control.digit_data[4]) in den nächsten
Datensatz umgewandelt. Aber jeweils nur der nächste Datensatz, abhängig
von der Stelle, welche als nächstes gebraucht wird (es liegt nicht schon
für jede Stelle der Datensatz für die SRs vor).
Man kann im Display leicht erkennen, dass es von der einen Seite zur
anderen quasi "durchflackert". Als wenn sich das Flackern immer wieder
einmal durchschiebt und wieder beginnt.
Will man es ergonomisch, muß jede Ziffer mindestens 20-mal angezeigt
werden.
Es wäre Schwachsinn, dann 20-mal wieder und wieder die gleiche Rechnung
auszuführen.
Man berechnet daher einmal und läßt 20-mal anzeigen.
Berechnung und Darstellung sind also 2 völlig getrennte Tasks.
Karl Heinz Buchegger schrieb:> Wenn die mein 5 Jahre nicht dazukommt diesen 'Stelle zusammenzubauen',> dann zeigen alle Digits 5 Jahre lang die zuletzt zusammengebaute Stelle> an.
Nee, das geht eigentlich nicht, da wegen der Schieberegister ja nur
immer eine leuchten kann. Kommt die main z.B. nur einmal dazu, einen
Datensatz für das SR zu berechnen, dann ist da ja sowohl die
Anodeninformation, sowie die Kathodeninformation drin. Es würde dann
wirklich nur die eine Stelle leuchten. OK, sorry, falls die Info
fehlte...mit dem einen SR schalte ich die Anoden, mit dem anderen die
Kathoden.
Karl Heinz Buchegger schrieb:> und in segmentPattern kannst du jetzt in den einzelnen Bytes die Muster> zusammenstellen wann du willst und du kannst dir zeit lassen so lange du> willst. Deswegen wird da nichts flackern.
Also meinst du es liegt daran, dass ich immer nur die Daten für das
nächste anzzeigende Segment generiere und nicht schon für alle vorrätig
habe?
Peter Dannegger schrieb:> Man berechnet daher einmal und läßt 20-mal anzeigen.
Dafür war ja das Flag in der ISR, welches in der main dann nach der
Berechnung gelöscht wird.
Dennis
Du hast dir in der Hauptschleife eine Abhängigkeit vom restlichen
Programm eingehandelt!
Dein 'update' Methode wird erst aufgerufen, wenn die Hauptschleife dazu
Zeit hat. Da kann die ISR 100-mal das bewusste Flag setzen. Wenn die
Hauptschleife nicht bereit ist, dann ist sie nicht bereit und das
korrekte Word für die Ausgabe wird nicht erzeugt.
Du hast nichts davon, wenn du 5 Millionen mal in der ISR immer wieder
das Digit Nummer 2 neu ausgibst, weil die Hauptschleife noch keine Zeit
hatte auf das Flag zu reagieren und die Information für Digit Nummer 3
zusammenzustellen.
Pro ISR AUfruf muss auf das nächste Digit weiter geschaltet werden. Und
zwar zuverlässig!
spontan schrieb:> Ja, aber Du läßt ja jede Stelle nach jedem Interrupt einzeln und neu> berechnen.
Das stimmt.
Karl Heinz Buchegger schrieb:> Du hast dir in der Hauptschleife eine Abhängigkeit vom restlichen> Programm eingehandelt!
OK, also alles im Vorfeld berechnen für jede Stelle und dann in der ISR
nurnoch durchrattern?
Dennis schrieb:> OK, also alles im Vorfeld berechnen für jede Stelle und dann in der ISR> nurnoch durchrattern?
Exakt.
Jetzt kommen wir auf einen grünen Zweig.
So sieht deine ISR aus