Hey Leute vielleicht kann mir mal jemand das folgende Verhalten
erklären.
Ich betreibe einige LEDs im Multiplexbetrieb und habe dabei das Problem,
dass ich die betreffenden LEDs nur immer für 100 µs aufleuchten lassen
möchte. Dies funktioniert leider nicht wie gewünscht. Laut Oszilloskop
sind es anstatt den eingestellten 100 µs um die 200 µs. Anbei ein Auszug
aus der gekürzten mux_display Funktion.
Testweise habe ichh noch eine "SIGNAL_ON_LED" eingebaut. Wenn ich an
dieser mit dem Osziloskop messe, stimmen die eingestellten 100 µs
Einschaltdauer.
@ Lars (Gast)
>möchte. Dies funktioniert leider nicht wie gewünscht. Laut Oszilloskop>sind es anstatt den eingestellten 100 µs um die 200 µs. Anbei ein Auszug>aus der gekürzten mux_display Funktion.
Dann ist dein define für F_CPU falsch und stimmt nicht mit dem realen
CPU-Takt überein. Oder du compilierst ohne Optimierung, dann passen die
Zeiten auch nicht.
Lars schrieb:> Laut Oszilloskop> sind es anstatt den eingestellten 100 µs um die 200 µs.
Das ist verständlich. Jede Codezeile kostet zusätzliche Zeit und
besonders die Berechnungen / und %.
Deshalb multiplext niemand bei Verstand mit Delay, sondern immer mit
einem Timerinterrupt. Dann sind die Zeiten unabhängig von
Ausführungszeiten (kein Flackern) und der MC kann noch andere Sachen
machen.
Die Berechnungen zieht man natürlich komplett aus dem Multiplexen raus,
denn kein Mensch kann so schnell Änderungen ablesen. Für ergonomisches
Ablesen verlangsamt man die Rate der Neuberechnung auf 2..5 Werte/s,
damit der Benutzer nicht nur flackernde 8-en sieht.
Wie lange dauert eine Instruktion bei dir? 1us? 100ns? 10ns?
Bei 1us Instruktionzeit würde 100us delay 100 instruktionen kosten. Da
kann man schon relatiev viel machen. Aber wenn nix anderes gemacht wird
dann könnte man noch blockierend den _delay_us verwenden. Bei schnellere
instruktionenzeit würde ich den _delay_us vergessen und sofort auf
interrupt gehen.
Faustregel: alles was delay_ms oder delay_us heisst muss aus der C Code
raus!
OK, nur findet zwischen Einschalten von DIGIT1 und Abschalten von DIGIT1
keine Berechnung statt.
Einleuchtend wäre es hingegen zwischen dem Einschalten SIGNAL_ON_LED und
Abschalten von SIGNAL_ON_LED, denn dort wird SevenSegment(minute%10)
ausgeführt. Allerdings passen gerade hier die 100 µs.
@ kyrk.5 (Gast)
>Faustregel: alles was delay_ms oder delay_us heisst muss aus der C Code>raus!
Unsinn^3. Gerade _delay_us() ist für sehr kurze Zeiten optimal, weil in
der Zeit so oder so nix anderes sinnvoll gemacht werden kann. Und auch
ein _delay_ms() ist, RICHTIG eingesetzt, überaus OK. Man muss nicht
immer mit einem Timer arbeiten, wenn gleich es gerade beim Multip0lexing
der Standardansatz ist.
kyrk.5 schrieb:> Faustregel: alles was delay_ms oder delay_us heisst muss aus der C Code> raus!
Nö. Es hält sich hartnäckig das Gerücht, das diese beiden Funktionen
'blocking' sind, dem ist aber nicht so. Etwaige Interrupts werden
nämlich bedient und deswegen kann _delay_xx() durchaus sinnvoll sein.
Es muss lediglich F_CPU definiert sein, bevor util/delay.h eingebunden
wird.
Allerdings ist ein Timerinterrupt für das Multiplex Display immer
vorzuziehen, vor allem ist es dann ein 'Fire-and-Forget' Ding ohne
Flimmern und als Nebeneffekt hat man dann gleich einen Ticker für z.B.
Tasten- oder Encoderentprellung.
Über den Sinn und Unsinn von _delay wollte ich eigentlich nicht
diskutieren. Viel mehr suche ich eine Erklärung für das eigenartige
Verhalten. Warum passt das Timing bei der SIGNAL_ON_LED, jedoch nicht
bei den DIGITs?
@Matthias S. (Firma: matzetronics) (mschoeldgen)
>Nö. Es hält sich hartnäckig das Gerücht, das diese beiden Funktionen>'blocking' sind, dem ist aber nicht so.
Aber sicher sind sie das. Während der Funktion kommt das Programm nicht
weiter, die CPU dreht Däumchen.
> Etwaige Interrupts werden>nämlich bedient
Das ist aber nicht die Definition einer blockierenden Funktion!
>Testweise habe ichh noch eine "SIGNAL_ON_LED" eingebaut. Wenn ich an>dieser mit dem Osziloskop messe, stimmen die eingestellten 100 µs>Einschaltdauer.
Glaub ich nicht, denn dazwischen liegt noch eine Funktion mit einem
Argument einer Modulo-Operation.
> PORTC |= (1<<SIGNAL_ON_LED);> _delay_us(time_on);> PORTB &= ~(1<<DIGIT1);> SevenSegment(minute%10);> PORTC &= ~(1<<SIGNAL_ON_LED);>Anbei ein Auszug aus der gekürzten mux_display Funktion.
Dort könnte ein Problem liegen. Zeig uns den ORIGINALEN, unmodifizierten
Quelltext.
Gute Frage, müsste ich heute Abend nochmal schauen. Habe bisher
tatsächlich nur an Digit4 gemessen.
Könnte also sein, dass die mux_display-Funktion in der while() nicht
rechtzeitig wieder aufgerufen wird.
Matthias S. schrieb:> Nö. Es hält sich hartnäckig das Gerücht, das diese beiden Funktionen> 'blocking' sind, dem ist aber nicht so. Etwaige Interrupts werden> nämlich bedient und deswegen kann _delay_xx() durchaus sinnvoll sein.
Aber bestimmt nicht, wenn man auf genaues Timing wert legt. Für "xx"
sollte dann insbesondere nicht "us" stehen, sonst wundert man sich über
irgendwelche Ausreißer bei der Länge der Verzögerungszeit.
Wolfgang schrieb:> Matthias S. schrieb:>> Nö. Es hält sich hartnäckig das Gerücht, das diese beiden Funktionen>> 'blocking' sind, dem ist aber nicht so. Etwaige Interrupts werden>> nämlich bedient und deswegen kann _delay_xx() durchaus sinnvoll sein.>> Aber bestimmt nicht, wenn man auf genaues Timing wert legt. Für "xx"> sollte dann insbesondere nicht "us" stehen, sonst wundert man sich über> irgendwelche Ausreißer bei der Länge der Verzögerungszeit.
Man muß sich einfach darüber im Klaren sein, daß auch wenn F_CPU zum
Quarz und der DIV8-Fuse paßt, nicht genau n μs vergehen, sondern
mindestens so viele.
Angenommen F_CPU=1MHz, dann führt _delay_us(100); mehr oder weniger
genau 100 Takte "Blind-Code" aus. Wenn aber ein Int dazwischen kommt,
dann dauert die "Lücke" zwischen zwei Befehlen auch mal deutlich länger
als geplant "Null". Ein minimal Int dauert 12Takte (Tiny25), falls IRET
direkt in der ISR-Tabelle steht.
Wenn man so darauf wartet, daß sich die Datenleitungen zum LCD
stabilisieren, dann ist es egal, ob 10 oder 20μs. Als Uhr taugt das aber
nicht.
Lars schrieb:> Gute Frage, müsste ich heute Abend nochmal schauen. Habe bisher> tatsächlich nur an Digit4 gemessen.> Könnte also sein, dass die mux_display-Funktion in der while() nicht> rechtzeitig wieder aufgerufen wird.
Und?