Hmm, irgendwie hab ich grad ne Hirnblockade. Ich hab jede Menge Funktionen, die ein unterschiedliches Gefunkel auf einem Ledstripe auslösen. Diese Funktionen sitzen in der Endlosschleife in main. Während des Ablaufs dieser Funktionen ist die CPU (ATmega328p) ziemlich belegt, da es sich um einen digital angesteuerten Stripe (WS2812b) handelt, welches seine Kommandos mit 800kHz erwartet und dann eben dauernd welchselnde Farben an jede LED hingefeuert bekommt. Nun muss aber Zeit für eine Erkennung von Befehlen bleiben. Die CPU ist aber so busy, dass die Befehle, die über UART reinkommen, mehrere 10sek benötigen, um erkannt zu werden. Der UART liest schon ein, das ist interruptgesteuert, aber die Auswertung in main geht halt sehr langsam. Das einzige, was mir dazu einfällt, ist: Die Befehlsauswertung in einem Timerinterupt zu machen, ggfs. eine globale Stop-Variable zu setzen und diese dann in allen Funktionen abzuchecken. Das müsste gehen, aber Auswertung in einem Interrupt ist auch nicht so dolle. Obige Funktionen haben alle irgendwo auch ein delay, damit man den Farbverlauf zeitlich steuert. Die Frage ist, kann man die irgendwie umbauen, so dass die Funktionen 'Zeitscheiben' an main abgeben? Oder wie bekommt man das hin in einem AVR ohne BS? Ideen willkommen. Grüsse PS: Hier mal eine dieser Funktionen (nicht von mir): void LEDStrip::_Show() { //spi_write_lpd8806(fBuffer, fBufferSize); // AR WS_out(fBuffer, fBufferSize, 0);<---- das ist der Zeitfresser } void LEDStrip::ColorChase(rgb_t background, rgb_t color, uint16_t delayTime, uint16_t repeatCount) { _Fill(background); while (repeatCount--) { for (uint16_t i = 0; i <= End(); i++) { _Set(i == 0 ? End() : i - 1, background); _Set(i, color); _Show(); delay(delayTime); } } }
Die Delays die wirklich gewartet wird würde ich gegen eine Variable ersetzen, die die laufende Funktion beendet, für die Dauer deines Delay blockiert und erst nach deiner Zeit wieder frei gibt und dann an der Stelle weiter macht wo sie aufgehört hat. Somit hast du die CPU für die Zeit deines Delays frei. So würde ich das auch mit den Kommandos machen. Evtl. Sogar direkt im Interrupt auswerten
k.A. wie die Ansteuerung der WS2812 in deinem Code gelöst ist, aber "Tim" hat dafür eine Lib entwickelt, die mit einem Minimum an Code auskommt: http://www.mikrocontroller.net/articles/WS2812_Ansteuerung Kürzer geht es per Bitbanging kaum, aber je nach Länge des Stripes kann das trotzdem ein "Weilchen" dauern. Da die Ausgabe jedoch nicht unterbrochen werden darf, mußt du damit leben und deinen Code entsprechend drumrum bauen. Oder eine leistungsfähigere CPU mit DMA verwenden.
:
Bearbeitet durch User
Dein Problem sind die Delay-Aufrufe bzw. das damit verbundene aktive Warten. Besser: Timer verwenden. D.h grob skizziert: - Timer im normal mode mit der passenden Granularität, zb auf 1 tick pro µs, programmieren. - statt delay: TCNT auslesen, gewünschtes Delay draufaddieren, in OCR ablegen, Interrupt auf OCR match scharfmachen. - Kniffeligster Teil: Du musst dir irgendwie merken, wo du nach dem Timerinterrupt weitermachen willst. Z.B. dadurch, daß du in einer glob. Variablen/Struct alle Infos ablegst, die du nach dem Timerinterrupt brauchst um an der passenden Stelle mit den passenden Infos weiterzumachen. - Interrupt-Service-Routine des Timers deaktiviert den OCRmatch Interrupt und setzt ein globales Flag für "Timer OCR match" - mehr nicht. - Main() musst du so umbauen, daß du nur auf Events "lauscht" und entsprechend reagierst. Da der UART schon interruptgesteuert arbeitet, sollte das nicht so schwierig sein. - Events sind "serielles Zeichen empfangen" oder "Timer OCR match" Wenn dein delay nicht gerade im einstelligen µs-Bereich liegt, hast du damit dann jede Menge Zeit, dich um alles mögliche zu kümmern. Gruss, Heinz
Danke an alle. Icke, das Ansteuern der LEDs ist nicht teilbar, da in Assembler und 100 Load. Tims Routine ist da auch nicht anders. Heinz hat recht, der Delay ist das Problem. Ich muss also alles umbauen. Nochmals Danke und Gruss
Der trick wird sein, nicht blokierend zu warten. wenn du einen timer übrig hast, bzw ein system tick timer irgendwo mit läuft, das delay darüber lösen.
1 | for ( ever ) |
2 | {
|
3 | ...
|
4 | if (getTimer() - lastTimer >= 100 ) |
5 | {
|
6 | ...
|
7 | sendeChracter(); |
8 | lastTimer = getTimer(); |
9 | }
|
10 | |
11 | ...
|
12 | handlRS232Commands(); |
13 | ...
|
14 | };
|
aufpassen mit der Integer arytmetik und den überläufen. das ist etwas triki. so sollte es funktonieren, das alle 100 timerteiks einam sendCharacter aufgerufen wird. gruss
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.