Forum: Compiler & IDEs LED-Blinker eleganter?


von Bastler (Gast)


Lesenswert?

Hallo,

ich breche mir hier einen ab mit einer möglichst eleganten & vielseitig 
einsetzbaren Pulserzeugung z.B. für eine Signal-LED die mehrere Zustände 
anzeigen soll.

Das Problem: Ich kann's nicht elegant & vielseitig.
Daher würde ich mich über Verbesserungen des folgenden Codes sehr freuen 
und hoffentlich etwas lernen.

Denkbar wär' auch dass die Zeiten in einer Tabelle (Array) stehen, und 
ggf. wiederholt werden. Dann könnte man noch vielseitigere Pulsfolgen 
erzeugen.

Der folgende Code funktioniert, in einer Timer ISR findet ca. alle 10ms 
das eigentliche Blinken statt.
1
  uint8_t led_on   = 0;
2
  uint8_t led_off   = 0;
3
  uint8_t led_cycles   = 0;
4
  uint8_t led_tick_ref   = 0;
5
  uint8_t led     = 0;
Die Funktion:
1
void flash(uint8_t on, uint8_t off, uint8_t cycles)
2
{
3
  led      = 1;
4
  led_on    = on;
5
  led_off     = off;
6
  led_cycles  = cycles;
7
  
8
  led_tick_ref = tick + led_on;
9
}
Alle x ms = 1 tick in einer Timer ISR :
1
  if (led_cycles > 0)
2
  {
3
    if(tick == led_tick_ref)
4
    {
5
      led = !led;
6
      
7
      if(led)
8
      {
9
        PORTB &= ~(1<<PB0);
10
        led_tick_ref = tick + led_off;
11
        led_cycles--;cycle
12
      }
13
      else
14
      {
15
        led_tick_ref = tick + led_on;
16
        PORTB ^= 1<<PB0;
17
      }
18
    }
19
  }

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dann leg doch für jeden Zustand ein Array an mit sagen wir 32 Bits
(also 4 Bytes).  Mit deinen 10 ms Abtastzeit hättest du dann eine
Periode von 32 ˙ 10 ms = 320 ms, das müsste optisch OK sein.  Ein
eingeschaltetes Bit bedeutet dabei jeweils eine eingeschaltete
LED, mehrere zusammenhängende Bits ergeben eine längere Einschalt-
dauer.  Durch das ganze Array schiebst du ein ,,Abtastbit'' durch,
wenn das hinten rausfällt, musst du vorn wieder anfangen.

Indem du verschiedene Arrays vorhälst und innerhalb der ISR nur
einen Zeiger auf das aktuelle, kannst du verschiedene Blinkmuster
verwalten.

Bei 32 bits kannst du das vom Schreibaufwand her ganz elegant lösen,
indem du statt eines Arrays und statt des Abtastbits jeweils 32-bit-
Zahlen benutzt (uint32_t).  Das ist zwar nicht wirklich effektiv im
Hintergrund dessen, was der Compiler daraus macht, aber dafür sehr
einfach aufzuschreiben, und möglicherweise stört die Ineffektivität
hier gar nicht.  Ungefähr so:
1
uint32_t blink1 = 0xfff00fff;
2
uint32_t blink2 = 0xf0f0f0f0;
3
uint32_t blink3 = 0xfff00000;
4
uint32_t *blinkp = &blink1;
5
6
ISR(TIMER0_COMPA_vect)
7
{
8
  static uint32_t mask = 1;
9
10
  if (*blinkp & mask)
11
    LED_ON();
12
  else
13
    LED_OFF();
14
15
  mask <<= 1;
16
  if (mask == 0) mask = 1;
17
}

Eine Änderung des angezeigten Musters erfolgt, indem man blinkp
jeweils auf eine der Adressen von blink1, blink2 oder blink3
umschaltet.  Wenn dich die kurze Inkonsistenz beim Umschalten
nicht stört (es blinkt dann eine Periode lang ,,irgendwie''),
dann würde ich mir nicht einmal die Mühe machen, das Umschalten
mit der kompletten Periode (mask läuft über und wird wieder auf
1 gesetzt) zu synchronisieren.

von Bastler (Gast)


Lesenswert?

Danke für den Vorschlag! Auf den ersten Blick würde ich sagen, dass 
beide Wege etwa gleich 'groß' sind, aber ich kenne mich nicht damit aus, 
deswegen werde ich das bei Gelegenheit erstmal ausprobieren.
Zeiger habe ich bisher immer verdrängt, ich werde mich nochmal einlesen 
müssen.

von Bastler (Gast)


Lesenswert?

Also, dein Verfahren ist in meinem Programm mit einem Muster und dem 
Aufruf über

*blinkp = &blink1;
mask = 1;

erstaunlicherweise ca. 20 Bytes größer als mein umständliches Gerechne 
(834+10 vs. 822+4 Bytes).

Ich hatte gedacht, dass es auch schneller sein müsste - allerdings 
werden immer zwei 32 bit Operationen durchgeführt.
Leider kann ich das nicht tiefergehend analysieren, daher werde ich mich 
erstmal anderen Baustellen in meinem Programm zuwenden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Die 32-bit-Operationen im AVR-GCC sind nicht sonderlich toll optimiert,
das heißt: eigentlich sind sie es gar nicht.  Das ist automatisch
generierter C-Code, der da in der Bibliothek sitzt.  Aber solange du
nicht die letzten 20 Bytes an Flash-ROM-Größe brauchst und es auf ein
paar CPU-Takte nicht ankommt, hast du damit zumindest einen (meiner
Meinung nach) relativ gut überschaubaren Quellcode und eine einfache
Möglichkeit, verschiedene Blinkmuster unterzubringen.

von Bastler (Gast)


Lesenswert?

Hallo Jörg,

danke für die Info. Dein Code ist auf jeden Fall kompakter zu schreiben 
und ich freue mich, dass ich jetzt auch diese Möglichkeit kennengelernt 
habe.
Wenn, dann kommt es bei mir auf die Rechenzeit an, da ist aber auch noch 
Luft.
Ich werde mir heute nachmittag mal ein C-Buch vornehmen und nochmal 
Zeiger studieren ;-)

Dankeschön für die Hilfe!

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.