mikrocontroller.net

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


Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian L. (lorio)
Datum:

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

Aber besser noch: Interrupts verwenden.

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sebastian Mazur (izaseba)
Datum:

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

in einem Timerinterrupt gibst Du das nächste Element auf PORTB aus

ISR (TIMER0_OVF_vect) {
static uint8_t folge = 0;

PORTB = pgm_read_byte(&Animation[folge]);
folge++;
if ( folge >=4 )
   folge = 0;
}

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

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ahh danke das werde ich mal so auhsprobieren :)

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sebastian Mazur (izaseba)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/pgmspace.h>
#include <util/delay.h> 

#define    yellow  PB3
#define    green  PB1
#define    red    PB2
#define    blue  PB4

#define    button  PB0

const unsigned char lightshow[] PROGMEM = { 
(0b1000 << 4) | 10,
(0b0100 << 4) | 10,
(0b0010 << 4) | 10,
(0b0001 << 4) | 10
};

int main(void)
{
  PORTB = (1 << button);
  DDRB = (1 << yellow) | (1 << green) | (1 << red) | (1 << blue);

  unsigned char temp, count, lights, delay;

  while(1)
  {
    for(count=0; count<4; count++)
    {
      temp = pgm_read_byte(&lightshow[count]);

      lights = (temp >> 4);
      delay = temp & ~(0xF0);

      if(bit_is_set(lights, 3))
      {
        PORTB |= (1 << yellow);
      }
      else
      {
        PORTB &= ~(1 << yellow);
      }

      if(bit_is_set(lights, 2))
      {
        PORTB |= (1 << green);
      }
      else
      {
        PORTB &= ~(1 << green);
      }

      if(bit_is_set(lights, 1))
      {
        PORTB |= (1 << red);
      }
      else
      {
        PORTB &= ~(1 << red);
      }

      if(bit_is_set(lights, 0))
      {
        PORTB |= (1 << blue);
      }
      else
      {
        PORTB &= ~(1 << blue);
      }

      while(delay--)
      {
        _delay_ms(20);
      }
    }
  }
}

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Paul Hamacher schrieb:
#define    yellow  PB3
#define    green  PB1
#define    red    PB2
#define    blue  PB4
..
if(bit_is_set(lights, 3))
=> yellow

if(bit_is_set(lights, 2))
=> green
Warum machst du das nicht so. Sortiere doch einfach deine "Farbbits" 
passend zur Anschlussbelegung. Das Delay würde ich durch einen Timer 
ersetzen...
ISR (timer overflow)  // alle 20msek
{
  static uint8_t count;
  static uint8_t time;
         uint8_t lights;
  temp   =   pgm_read_byte(&lightshow[count]);
  if ( ++time == (temp & 0x0F) )
  {
    lights =   (temp >> 4);
    PORTB  |=  ( (PORTB & 0x0F) | lights );
    if ( ++count >= 4 )  count = 0;
  }
}

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/pgmspace.h>
#include <util/delay.h> 

#define    yellow  PB3
#define    green  PB1
#define    red    PB2
#define    blue  PB4

#define    button  PB0

const char scene1[] PROGMEM = {
10,
(0b1000 << 4) | 10,
(0b0100 << 4) | 10,
(0b0010 << 4) | 10,
(0b0001 << 4) | 10,
0};

const char scene2[] PROGMEM = {
20,
(0b0000 << 4) | 10,
(0b1000 << 4) | 9,
(0b1100 << 4) | 8,
(0b1110 << 4) | 7,
(0b1111 << 4) | 6,
(0b0111 << 4) | 7,
(0b0011 << 4) | 8,
(0b0001 << 4) | 9,
0};

const char *lightshow[] PROGMEM = {
  scene1,
  scene2
};

int main(void)
{
  PORTB = (1 << button);
  DDRB = (1 << yellow) | (1 << green) | (1 << red) | (1 << blue);

  char currentScene, currentStep;
  char temp, lights, repetitions, delay;

  while(1)
  {
    for(currentScene=0; currentScene<sizeof(lightshow); currentScene++)
    {
      repetitions = pgm_read_byte(&(lightshow[currentScene])[0]);

      while(repetitions--)
      {
        currentStep = 1;

        while(1)
        {
          temp = pgm_read_byte(&lightshow[currentStep]);

          if(temp == 0)
          {
            break;
          }

          [...Portbits setzen...]

          while(delay--)
          {
            _delay_ms(20);
          }
        }
      }
    }
  }
}

lg PoWl

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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?
char scene[4][2] PROGMEM  = { {1, 2},
                              {3, 4},
                              {5, 6},
                              {7, 8} };

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.