Forum: Mikrocontroller und Digitale Elektronik Zeitscheiben für main bereitstellen


von Unwissender (Gast)


Lesenswert?

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);
    }
  }
}

von Ingo (Gast)


Lesenswert?

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

von DirkZ (Gast)


Lesenswert?


von Icke ®. (49636b65)


Lesenswert?

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
von katastrophenheinz (Gast)


Lesenswert?

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

von Unwissender (Gast)


Lesenswert?

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

von abc (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.