MezData-Logo

Muster auf LED-Zeile ausgeben

Grundprinzip

MusterAn PB eines ATtiny2313 mit 1MHz Systemtakt soll eine Folge von Mustern nacheinander auf der LED-Zeile ausgegeben werden.

Die LED leuchten bei log. 0 (neg. Logik)

Die Zeit zwischen den Mustern (400 ms) soll mit _delay_ms(400) realisiert werden.

Einfache Lösung

Für jedes Muster ein Befehl

Quellcode [muster_einfach.c]
#include <avr/io.h>     //Definitionen
#include <util/delay.h> //Delay-Bibliothek
 
int main(){         // Hauptprogramm 
  PORTB=0xff;       // alle LED aus 
  DDRB=0xff;        // PB als Ausgang 
  while(1){         // Endlosschleife 
    PORTB=PORTB&~0b111 | 0b011;
    _delay_ms(400);  
    PORTB=PORTB&~0b111 | 0b101;
    _delay_ms(400);
    PORTB=PORTB&~0b111 | 0b110;
    _delay_ms(400);
    PORTB=PORTB&~0b111 | 0b101;
    _delay_ms(400);  
  } 
  return 0; 
}

Lösung mit Array

Die Muster werden in ein Array geschrieben und ausgeben

Quellcode [muster_array.c]
#include <avr/io.h>     // Definitionen laden 
#include <util/delay.h> // CPU Frequenz einstellen! 
 
unsigned char muster[]={0b100,0b010,0b001,0b010};
unsigned char musterzaehler=0;
int main(){         // Hauptprogramm 
  PORTB=0xff;       // alle LED aus 
  DDRB=0xff;        // PB als Ausgang 
  while(1){         // Endlosschleife 
    PORTB=(PORTB|0b111) & ~muster[musterzaehler]; // Array-Muster
    _delay_ms(400);
    musterzaehler++;
    if(musterzaehler>=sizeof(muster)){//sizeof ergibt Byte-Groesse
      musterzaehler=0;
    }
  } 
  return 0; 
}

Zwischen mehreren Mustern umschalten

Zwei MusterMittels Taste an PD0 soll zwischen zwei Musterfolgen umgeschaltet werden können.

Als Lösung könnten zwei Felder muster1[] und muster2[] angelegt werden und mittels switch-Anweisung wird die Ausgabe umgeschaltet. Eleganter und besser erweiterbar ist die Verwendung eines 2-Dimensionalen Arrays, siehe Quelltext.

Da die Muster unterschiedlich lang sind wird zum Erkennen des Musterendes ein geeignetes Verfahren benötigt:

So wird muster[2][6]={{4,0b100,0b010,0b001,0b010},{5,0b000,0b110,0b011,0b010,0b111}} im Speicher abgelegt:

muster [0][0] [0][1] [0][2] [0][3] [0][4] [0][5] [1][0] [1][1] [1][2] [1][3] [1][4] [1][5]
relative Adresse 0 1 2 3 4 5 6 7 8 9 10 11
Dateneingabe 4 0b100 0b010 0b001 0b010   5 0b000 0b110 0b011 0b010 0b111
gespeichert 4 4 2 1 2 0 5 0 6 3 2 7

Es werden 12 Byte im SRAM belegt weil das Muster im SRAM gespeichert wird

Quellcode [muster_multi.c]
#include <avr/io.h>     // Definitionen laden 
#include <util/delay.h> // CPU Frequenz einstellen! 
 
#define KEYREADER ~PIND & 0b01111111 // Einlesen, invertieren, maskieren zurecht schieben 
#include "keycheck.inc"              // http://mezdata.de/avr/083_c-entprellen/keycheck.inc 
 
unsigned char muster[2][6]={{4,0b100,0b010,0b001,0b010},{5,0b000,0b110,0b011,0b010,0b111}};
unsigned char musterzaehler=1,musternummer=0;
int main(){         // Hauptprogramm 
  PORTB=0xff;       // alle LED aus 
  DDRB=0xff;        // PB als Ausgang 
  while(1){         // Endlosschleife 
    keyCheck();
    if(keyEnter&1){ // Taste gedrueckt?
      musterzaehler=0;
      musternummer++;
      if(musternummer>=sizeof(muster)/sizeof(muster[0])) musternummer=0;
    }
    PORTB=(PORTB|0b111) & ~muster[musternummer][musterzaehler]; // Muster aus Array
    _delay_ms(400);
    musterzaehler++;
    if(musterzaehler>muster[musternummer][0]){ // 
      musterzaehler=1;
    }
  } 
  return 0; 
}

Fragen

Welche relativen Byte-Adressen haben die Elemente bla[2][0] und bla[3][3] in einem Feld char bla[4][5] ?

Beim Vergleich mit einem Koordinatensystem, nach welchem Prinzip werden die Daten im zweidimensionalen Feld abgelegt: [x][y] oder [y][x] ?

Welche relativen Byte-Adressen haben die Elemente blub[0][2] und blub[1][0] in einem Feld int blub[4][5] ?

C-Datentypen

Datentyp Alternativ Bit Dezimalbereich Bemerkung
unsigned char uint8_t 8 255 vorzeichenlose kleine Zahlen
char int8_t 8 -128..+127 kleine Zahlen mit Vorzeichen
unsigned int uint16_t 16 65535  
int int16_t 16 -32768..+32767  
unsigned long   32 4294967295 *Hinweis: 9600UL
long   32 -2147483648..+2147483647 *Hinweis: 9600L
float   32 ±10-37 .. ±10+38  
void       leer oder unbestimmt

Die Bitbreite der Datentypen kann auf unterschiedlichen Systemen variieren, deshalb gibt es alternative Bezeichnungen, aus denen die Bitbreite hervorgeht.

sizeof() gibt die Byte-Grösse einer Variablen zurück.

Speichern von char und int

Little Endian, Big Endian

Speichern von char -Feldern

Mit PROGMEM Daten im Flash-Programmspeicher speichern

Mit PROGMEM können konstante Daten im Flash-Speicher untergebracht werden, im SRAM wird nichts belegt. Gelesen werden die Daten mit besonderen Funktionen, denen die Speicheradresse der Daten mittels des &-Operators übergeben wird.

Quellcode [muster_progmem.c]
#include <avr/io.h>     // Definitionen laden 
#include <util/delay.h> // CPU Frequenz einstellen! 
#include <avr/pgmspace.h>  // Flashzugriffe laden 
 
#define KEYREADER ~PIND & 0b01111111 // Einlesen, invertieren, maskieren zurecht schieben 
#include "keycheck.inc"              // http://mezdata.de/avr/083_c-entprellen/keycheck.inc 
 
unsigned char PROGMEM muster[2][6]={{4,0b100,0b010,0b001,0b010},{5,0b000,0b110,0b011,0b010,0b111}};
unsigned char musterzaehler=1,musternummer=0;
int main(){         // Hauptprogramm 
  PORTB=0xff;       // alle LED aus 
  DDRB=0xff;        // PB als Ausgang 
  while(1){         // Endlosschleife 
    keyCheck();
    if(keyEnter&1){ // Taste gedrueckt?
      musterzaehler=0;
      musternummer++;
      if(musternummer>=sizeof(muster)/sizeof(muster[0])) musternummer=0;
    }
    PORTB=(PORTB|0b111) & ~pgm_read_byte(&muster[musternummer][musterzaehler]); // Muster aus Array
    _delay_ms(400);
    musterzaehler++;
    if(musterzaehler>pgm_read_byte(&muster[musternummer][0])){ // 
      musterzaehler=1;
    }
  } 
  return 0; 
}

Denken Sie sich zwei Musterfolgen aus und erstellen Sie die Werte für muster[][].