Forum: Compiler & IDEs Tipps für Lichteffektsteuerung mit ATtiny13 gesucht


von Paul H. (powl)


Lesenswert?

Hi!

Aus besonderen Anlässen habe ich mir eine LED-Kette gebastelt ;-) Diese 
besteht aus jeweils zwei gegenüberliegend angeordneten LEDs in Rot, 
Grün, Gelb und Blau wovon ich jeweils immer eine Farbe per Portpin 
ansteuern kann.

Zum Einsatz kam ein ATtiny13. Da ich das Ding gerne in C programmieren 
würde, ergibt sich nun ein Dickes Problem mit der Codegröße.

Wenn mein Programm aus lauter Einzelanweisungen à la

PORTB = (0 << yellow) | (0 << green) | (1 << red) | (0 << blue);
_delay_ms(100);

besteht, wächst schon nach zwei Effekten der Programmcode auf 500bytes 
an was schon 50% des Speichers vollmachen. Ich hätte jedoch gerne mehr 
verschiedene Effekte. Darunter eventuell auch mal Fading-Effekte. Das 
meiste werden jedoch nur 1/0-Folgen sein die dann wie ein Film ein paar 
mal wiederholt hintereinander ablaufen.

Da ich nicht so der C-Geek bin und mit µCs 2 Monate Pause gemacht hab, 
wollte ich mal Fragen ob jemand eine Idee hat, wie man die 
Programmierung von solchen Folgen mit knappem Code realisieren kann und 
ob das in C überhaupt so möglich ist oder ob ich assembler verwenden 
muss.

Ach ja, es sei noch zu erwähnen dass es da noch einen Taster gibt mit 
dem man z.B. ins nächste Programm springen oder die Geschwindigkeit der 
Programmabfolge bestimmen können soll.

lg PoWl

von Christian L. (lorio)


Lesenswert?

Wenn mit der Delay-Bibliothek gearbeitet wird:
Die Optimierung einschalten.
Sonst werden die .hex mal schnell seeeeehr groß ^^

Aber besser noch: Interrupts verwenden.

von Paul H. (powl)


Lesenswert?

Danke, die Optimierung hat leider keine Codereduktion erbraucht. Mir ist 
das grad was eingefallen

Am besten wäre wohl eine Funktion die ich mit Daten folgender Struktur 
füttern kann:

Jeweils ein Byte

Rot | Grün | Blau | Gelb | 4-Bit Delay

Dann kann ich die ganzen Effekte einfach in einer einfachen Liste 
speichern, das was da vorher 300 Byte lang war wär somit nur noch 20 
byte lang :-) Fragt sich nur wie viel Overhead das produziert. Muss sich 
mal testen

Wenn man fürs Delay nur zwei oder drei Bit einplant könnte man ja noch 
so dinge wie ein/ausfaden mit einplanen :-)

lg PoWl

von Sebastian M. (izaseba)


Lesenswert?

Leg Dir doch mal eine Tabelle im Flash an:
1
const uint8_t Animation[] PROGMEM = { 0x01,0x02,0x04,0x08 };

in einem Timerinterrupt gibst Du das nächste Element auf PORTB aus
1
ISR (TIMER0_OVF_vect) {
2
static uint8_t folge = 0;
3
4
PORTB = pgm_read_byte(&Animation[folge]);
5
folge++;
6
if ( folge >=4 )
7
   folge = 0;
8
}

Du kannst ein 2 Dimensionales Array anlegen, für verschiedene Effekte.
Die Erste Dimension läuft im Timer Durch, die Zweite schaltest Du mit 
Deinem Taster um.

Gruß Sebastian

von Paul H. (powl)


Lesenswert?

ahh danke das werde ich mal so auhsprobieren :)

von AVRFan (Gast)


Lesenswert?

Statt den Flash (= CSEG) zum Speichern von Datenmengen zu verwenden, 
kann man diese auch ins EEPROM (= ESEG) auslagern.  Eine Routine, die 
ein Byte aus der übergebenen EEPROM-Adresse ausliest, ist fix 
geschrieben, und benötigt nur wenig Platz.

von Paul H. (powl)


Lesenswert?

AVRFan wrote:
> Statt den Flash (= CSEG) zum Speichern von Datenmengen zu verwenden,
> kann man diese auch ins EEPROM (= ESEG) auslagern.  Eine Routine, die
> ein Byte aus der übergebenen EEPROM-Adresse ausliest, ist fix
> geschrieben, und benötigt nur wenig Platz.

An sich ne gute Idee aber das EEPROM umfasst beim Tiny13 nur 64 Byte, 
ist leider etwas wenig, das reicht vielleicht für 2-3 Animationen.

Wenn die Ausgaberoutine 200-500Byte braucht hab ich noch 500 Byte nur 
für Animationen, das langt dicke :-)

Bin noch nicht dazu gekommen was zu schreiben, mach ich morgen mal.

das hintere nibble eines solchen Animationsdatenbytes kann man ja 
benutzen um den Delay vorzugeben in 16 Stufen (4 Bit) mit jeweils 
meinetwegen 25ms.

Mit dem Button kann man ja dann noch auswählen wie viel ms ein delay 
wirklich umfasst und die Animation somit schneller und langsamer machen 
:-)

lg PoWl

von Sebastian M. (izaseba)


Lesenswert?

@AVRFan,

Genau, EEPROM ist auch ein guter Ablageort.

> Eine Routine, die
>ein Byte aus der übergebenen EEPROM-Adresse ausliest, ist fix
>geschrieben, und benötigt nur wenig Platz.

Das ist nicht nötig,
ersetze PROGMEM durch EEMEM
und pgm_read_byte durch eeprom_read_byte

fertig.

Gruß Sebastian

von Paul H. (powl)


Lesenswert?

Hi, danke nochmal für die Hilfe! Mein Akutelles Programm sieht so aus 
und funktioniert auch recht ordentlich :-)

Wie kann ich denn nun mehrdimensionale Arrays erstellen? Im 
lightshow-Array sollen nun mehrere Arrays mit den einzelnen Szenen 
eingespeichert sein. Um die szene automatisch neu beginnen zu lassen 
wenn sie fertig durchgelaufen ist brauch ich eine Endemarke 0x00 oder?

lg PoWl
1
#include <avr/pgmspace.h>
2
#include <util/delay.h> 
3
4
#define    yellow  PB3
5
#define    green  PB1
6
#define    red    PB2
7
#define    blue  PB4
8
9
#define    button  PB0
10
11
const unsigned char lightshow[] PROGMEM = { 
12
(0b1000 << 4) | 10,
13
(0b0100 << 4) | 10,
14
(0b0010 << 4) | 10,
15
(0b0001 << 4) | 10
16
};
17
18
int main(void)
19
{
20
  PORTB = (1 << button);
21
  DDRB = (1 << yellow) | (1 << green) | (1 << red) | (1 << blue);
22
23
  unsigned char temp, count, lights, delay;
24
25
  while(1)
26
  {
27
    for(count=0; count<4; count++)
28
    {
29
      temp = pgm_read_byte(&lightshow[count]);
30
31
      lights = (temp >> 4);
32
      delay = temp & ~(0xF0);
33
34
      if(bit_is_set(lights, 3))
35
      {
36
        PORTB |= (1 << yellow);
37
      }
38
      else
39
      {
40
        PORTB &= ~(1 << yellow);
41
      }
42
43
      if(bit_is_set(lights, 2))
44
      {
45
        PORTB |= (1 << green);
46
      }
47
      else
48
      {
49
        PORTB &= ~(1 << green);
50
      }
51
52
      if(bit_is_set(lights, 1))
53
      {
54
        PORTB |= (1 << red);
55
      }
56
      else
57
      {
58
        PORTB &= ~(1 << red);
59
      }
60
61
      if(bit_is_set(lights, 0))
62
      {
63
        PORTB |= (1 << blue);
64
      }
65
      else
66
      {
67
        PORTB &= ~(1 << blue);
68
      }
69
70
      while(delay--)
71
      {
72
        _delay_ms(20);
73
      }
74
    }
75
  }
76
}

von Matthias L. (Gast)


Lesenswert?

> Paul Hamacher schrieb:
1
#define    yellow  PB3
2
#define    green  PB1
3
#define    red    PB2
4
#define    blue  PB4
5
..
6
if(bit_is_set(lights, 3))
7
=> yellow
8
9
if(bit_is_set(lights, 2))
10
=> green
Warum machst du das nicht so. Sortiere doch einfach deine "Farbbits" 
passend zur Anschlussbelegung. Das Delay würde ich durch einen Timer 
ersetzen...
1
ISR (timer overflow)  // alle 20msek
2
{
3
  static uint8_t count;
4
  static uint8_t time;
5
         uint8_t lights;
6
  temp   =   pgm_read_byte(&lightshow[count]);
7
  if ( ++time == (temp & 0x0F) )
8
  {
9
    lights =   (temp >> 4);
10
    PORTB  |=  ( (PORTB & 0x0F) | lights );
11
    if ( ++count >= 4 )  count = 0;
12
  }
13
}

von Paul H. (powl)


Lesenswert?

Matthias Lipinsky wrote:
> Warum machst du das nicht so. Sortiere doch einfach deine "Farbbits"
> passend zur Anschlussbelegung.

Das ist nur für mich so, weil Die Kette so aufgebaut ist: Gelb Grün Rot 
Blau und ich das gerne auch in der Reihenfolge so programmieren würde 
:-)

> Das Delay würde ich durch einen Timer
> ersetzen...

Danke, aber wozu, das wird ja mega kompliziert. Ich möchte doch die 
delay-Zeit durch die Angabe im jeweiligen Szenenschritt bestimmen.

Wie erstellt man denn nun mehrdimensionale Arrays? Mein kleines 
Experiment scheint nicht zu funktionieren:
1
#include <avr/pgmspace.h>
2
#include <util/delay.h> 
3
4
#define    yellow  PB3
5
#define    green  PB1
6
#define    red    PB2
7
#define    blue  PB4
8
9
#define    button  PB0
10
11
const char scene1[] PROGMEM = {
12
10,
13
(0b1000 << 4) | 10,
14
(0b0100 << 4) | 10,
15
(0b0010 << 4) | 10,
16
(0b0001 << 4) | 10,
17
0};
18
19
const char scene2[] PROGMEM = {
20
20,
21
(0b0000 << 4) | 10,
22
(0b1000 << 4) | 9,
23
(0b1100 << 4) | 8,
24
(0b1110 << 4) | 7,
25
(0b1111 << 4) | 6,
26
(0b0111 << 4) | 7,
27
(0b0011 << 4) | 8,
28
(0b0001 << 4) | 9,
29
0};
30
31
const char *lightshow[] PROGMEM = {
32
  scene1,
33
  scene2
34
};
35
36
int main(void)
37
{
38
  PORTB = (1 << button);
39
  DDRB = (1 << yellow) | (1 << green) | (1 << red) | (1 << blue);
40
41
  char currentScene, currentStep;
42
  char temp, lights, repetitions, delay;
43
44
  while(1)
45
  {
46
    for(currentScene=0; currentScene<sizeof(lightshow); currentScene++)
47
    {
48
      repetitions = pgm_read_byte(&(lightshow[currentScene])[0]);
49
50
      while(repetitions--)
51
      {
52
        currentStep = 1;
53
54
        while(1)
55
        {
56
          temp = pgm_read_byte(&lightshow[currentStep]);
57
58
          if(temp == 0)
59
          {
60
            break;
61
          }
62
63
          [...Portbits setzen...]
64
65
          while(delay--)
66
          {
67
            _delay_ms(20);
68
          }
69
        }
70
      }
71
    }
72
  }
73
}

lg PoWl

von Matthias L. (Gast)


Lesenswert?

>Danke, aber wozu, das wird ja mega kompliziert
Das ist wohl ein Scherz...

>Ich möchte doch die delay-Zeit durch die Angabe im jeweiligen Szenenschritt 
>bestimmen.
Kannst du doch. Beispiel siehe mein Post.

>Mein kleines Experiment scheint nicht zu funktionieren:
Das sind ja auch zwei einzelne Arrays.


>Wie erstellt man denn nun mehrdimensionale Arrays?
1
char scene[4][2] PROGMEM  = { {1, 2},
2
                              {3, 4},
3
                              {5, 6},
4
                              {7, 8} };

von Paul H. (powl)


Lesenswert?

Danke schonmal für deine Posts.

Hast Recht, mit deinem Beispiel geht es. Aber ich verstehe nicht ganz, 
was mir das für Vorteile bringen soll? Wozu einen Timer verwenden? Einen 
Linearen Programmablauf finde ich übersichtlicher und einfacher zu 
handlen für den Anfang.

lightshow dient als zeiger auf die beiden arrays. Demnach müsste 
&(lightshow[x]) die Adresse des arrays nummer x haben. Sollte ich die 
Eckige klammer danach noch in die Runde mit reinholen?

Mit deiner Methode, mehrdimensionale Arrays zu erstellen, kann man nur 
Unterarrays gleicher Länge definieren. Meine Einzelnen Lichtszenen sind 
allerdings alle unterschiedlicher Länge.

lg PoWl

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.