weihnachtliche-elektronikspielchen

Weihnachtliche Elektronikspielchen

Attiny13 und ein paar BauelementeMikroprozessoren sind ICs, also integrierte Schaltkreise (Engl.: integrated circuits). Sie können meist beliebig Programmiert werden und sind für kleine wie auch große Aufgaben sehr gut geeignet. Am Anfang, nach ein wenig Interessenbekundung steht jedoch immer die Frage: PIC oder ATMEL? Beide Typen sind weit verbreitet, arbeiten sehr zuverlässig, sind mit relativ kleinem Aufwand zu programmieren, benötigen zum Betrieb nur wenige externe Bauteile, sind recht günstig in der Anschaffung und haben eine riesige community die in diversen Internet-Foren organisiert ist.

Meine Entscheidung fiel schlussendlich auf Atmel. Warum? … k.A. …Wie bei vielen anderen auch, sollte mein erstes Projekt irgendwas Leuchtendes, Blinkendes oder einfach etwas für das Auge sein. Was liegt näher als RGB-LEDs als Farbwechsler? Genau, nichts!

Nach ein wenig Vorarbeit und sorgfältiger Recherche hatte ich mir eine Liste aller benötigten Bauteile zusammengetragen, ein Lieferant (mit Katalog und Online-Shop … [Name von der Redaktion geädert] re**helt.de) hatte die benötigten Teile in Windeseile geliefert.

1. Der Programmer – STK-200

Starter Kit 200 - STK200 ProgrammerNotwendig war die einmalige Anschaffung der Bauteile des Programmers/Brenners, den ich am Parallelport betreibe. Er Besteht aus einem Bustreiber, einer Diode, einem Kondensator, einem Widerstand und einem Stecker. Die Kosten für den Programmer lagen somit bei ca. 1,01 Euro.

Menge Bezeichnung Beschreibung
1 D-SUB 25-POL 25-Poliger Stecker für Parallelport
1 74HC244 8-Bit Bustreiber
1 100 nF Kondensator
1 100 kΩ Widerstand
1 1N4148 Diode

1.1. Programmierumgebung

Mein primäres Betriebssystem ist eine Ubuntu-Distribution, somit war ein Compiler nötig der unter Linux lief. Nach einigen Tagen der Informationssammlung traf ich meine Wahl: avrdude ist genau das richtige. Eine Programmier-Suite benötige ich nicht, da ich es gewohnt bin mit dem Editor und der Konsole zu arbeiten.

2. Das erste Projekt

Mein erstes Projekt, der Umbau eines Holz-Fensterbildes von einer konventioneller 15W Glühlampenbeleuchtung auf LEDs, kreiste bereits geraume Zeit in meinem Kopf. Die benötigten Teile waren ein Attiny13, ein acht-Pin IC Sockel, sechs Widerstände (3 mal 10 kΩ, 2 mal 91 Ω, 1 mal 150 Ω), ein 100 nF Kondensator, sechs Dreifarb-LEDs, drei NPN-Transistoren und ein 5V Festspannungsregler alles in allem kostete es nicht einmal 7,50 Euro.

Die Elektronik ist im nu zusammengelötet und voll Funktionsfähig. Die Software auf dem Attiny13 soll die Farben Rot, Grün und Blau langsam ineinander Blenden, möglichst nach keinem auffälligen Schema wie Rot -> Orange -> Grün -> Cyan -> Blau -> Magenta -> …

Am Seitenende befindet sich ein Video, das ich nach der Fertigstellung aufgenommen habe.

2.1. Die Programmierung

Es gibt verschieden Möglichkeiten seine Programme zu schreiben, ich entschied mich Aufgrund meiner Vorkenntnisse für C.

Datei: test1.c

#define F_CPU 9600000UL
#include <avr/io.h>
#include <stdlib.h>

/*** MAX LED VALUE */
#define MAX_VAL 1500
#define FADE_SPEED 1
#define DYNAMIC 0     // higher than 0 change the colors dynamically

/*** LED DEFINITIONS */
#define LED_R   PB2
#define LED_G   PB1
#define LED_B   PB0

/*** LED VARIABLES */
unsigned char LEDcurrent[] = {0, 0, 0};
unsigned int LEDcolor[] = {MAX_VAL, 0, 0};
unsigned int LEDtarget[] = {0, 0, 0};
unsigned char LEDspeed[] = {2, 1, 3};     // different values for random effect
unsigned char LEDready[] = {0, 0, 0};

unsigned int LEDvals[] = {MAX_VAL, 0, 0,          // red
                         MAX_VAL, MAX_VAL, 0,     // orange
                         0, MAX_VAL, 0,           // green
                         0, MAX_VAL, MAX_VAL,     // cyan
                         0, 0, MAX_VAL,           // blue
                         MAX_VAL, 0, MAX_VAL};    // magenta

int main(void){
        unsigned int i, inc, dec = 0;
        unsigned char k, m = 0;

        DDRB |= (_BV(LED_R) | _BV(LED_G) | _BV(LED_B));

        while (1) {

                if(i < LEDcolor[0]) {
                        PORTB |= _BV(LED_R);
                } else {
                        PORTB &= ~_BV(LED_R);
                }

                if(i < LEDcolor[1]) {
                        PORTB |= _BV(LED_G);
                } else {
                        PORTB &= ~_BV(LED_G);
                }

                if(i < LEDcolor[2]) {
                        PORTB |= _BV(LED_B);
                } else {
                        PORTB &= ~_BV(LED_B);
                }

                if(i > MAX_VAL) {
                    i = 0;
                }

                if(k > FADE_SPEED) {
                    k = 0;
                }

                if(i == 0 && k == 0) {

                    for(m = 0; m < sizeof(LEDcurrent); m++) {

                        if( DYNAMIC == 0) {
                            inc = LEDspeed[m];
                            dec = LEDspeed[m];
                        } else {
                            inc = ((MAX_VAL - LEDcolor[m]) / (3 * DYNAMIC * LEDspeed[m]));
                            dec = (LEDcolor[m] / (3 * DYNAMIC * LEDspeed[m]));
                        }

                        if(inc == 0)
                            inc = 1;

                        if(dec == 0)
                            dec = 1;

                        if(LEDcolor[m] >= (LEDtarget[m] - inc) && LEDcolor[m] <= (LEDtarget[m] + dec) || LEDtarget[m] == LEDcolor[m]) {
                            LEDready[m] = 1;
                        }

                        if(LEDready[m] == 1) {
                            LEDcurrent[m] = (LEDcurrent[m] < 5) ? LEDcurrent[m] + 1 : 0;
                            LEDtarget[m] = LEDvals[(3 * LEDcurrent[m]) + m];
                            LEDready[m] = 0;
                        } else if(LEDready[m] == 0 && LEDcolor[m] > LEDtarget[m]) {
                            LEDcolor[m] -= dec;
                        } else if(LEDready[m] == 0 && LEDcolor[m] < LEDtarget[m]) {
                            LEDcolor[m] += inc;
                        }

                    }
                }

                i++;
                k++;
        }

        return 0;
}

2.2. Das Makefile

Der Quellcode muss nun Kompiliert und auf den Chip übertragen werden, um dies zu vereinfachen packe ich den gesamten Vorgang in ein Makefile.

Datei: Makefile

TARGET = test1
MCU    = attiny13
CC     = avr-gcc
 
CFLAGS  =-mmcu=$(MCU) -Wall -Os
LDFLAGS =-mmcu=$(MCU)

$(TARGET): $(TARGET).o

$(TARGET).hex : $(TARGET)
     avr-objcopy -j .data -j .text -O ihex $< $@

load: $(TARGET).hex
    avrdude -p attiny13 -c stk200 -U lfuse:w:0x79:m -U hfuse:w:0xF9:m -U flash:w:$(TARGET).hex -v -F -u

clean:
    rm -f *.o  *.hex $(TARGET)
2.2.1. Den Quellcode Kompilieren

Der Einfachheit halber muss ich jetzt nur noch ein Terminal öffnen und in das Verzeichnis mit dem Quelltext und dem Makefile wechseln…

tamas@tamas-desktop:/$ cd mein_kleines_bastelprojekt/

Ein make kompiliert mir die .hex Datei, oder Zeigt mir Fehler und Warnungen falls bei der Programmierung etwas schief gelaufen ist…

tamas@tamas-desktop:/mein_kleines_bastelprojekt/$ sudo make
2.2.2. Das Programm übertragen

Das abschließende make load überträgt die .hex Datei auf den Mikroprozessor…

tamas@tamas-desktop:/mein_kleines_bastelprojekt/$ sudo make load

3. Das Ergebnis

4. Der Nachtrag

Die letzten Tage hatte ich mit folgenden Meldungen zu kämpfen…

avrdude: reading on-chip lfuse data:
Reading | ################################################## | 100% 0.00s
avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0000
         0x79 != 0x00
avrdude: verification error; content mismatch
avrdude done.  Thank you.
make: *** [load] Error 1

doch, WIESO? Nach langem Hin und Her kam die Erkenntnis!

Denn ich ging davon aus, dass die externe Spannungsversorgung des Attiny13 anliegt. Schwer getäuscht, die Masse des Netzteils hatte keinen Kontakt mit dem Board. Nach der Fehlerbehebung funzte alles wieder wie es sollte…