Helligkeit der LEDs mit Pulsweitenmodulation regeln
Das Prinzip wird hier am Beispiel von 4 Helligkeitsstufen verdeutlicht. Ein Zyklus dauert 3 Takte, die LED leuchtet von 0 Takte (gar nicht) bis 3 Takte (ständig).
0
1
2
0
1
2
0
1
2
0
1
2
0
Dunkel
33%
66%
100%
Die LEDs sollen mit 100Hz angesteuert werden, damit kein Flackern wahrnehmbar ist. Zwei Lösungsvarianten bieten sich an:
Realisierung per Software. Das Signal wird mittels Warteschleife oder ISR erzeugt.
Vorteile: Beliebige PortPins als Ausgabe möglich. Keine Begrenzung durch Anzahl der PWM-Einheiten
Nachteile: Zykluszeit kann zu lang sein. Hohe Rechenbelastung.
Realisierung mit Hardware (Timer PWM System). Die µC habe bereits eine geeignete Hardware zur Erzeugung von PWM-Signalen eingebaut. An bestimmten Ausgängen können diese Signale abgegriffen werden.
Vorteile: Auch kurze Zykluszeiten realisierbar, Signalerzeugung geschieht im Hintergrund, Hauptprogramm wird nicht belastet
Nachteile: Festlegung auf bestimmte PortPins, Begrenzte Anzahl von Ausgängen
PWM per Software mit ISR
Eine LED an PB0 eines ATtiny 2313 @1MHz soll 4 Helligkeitsstufen {0..3} annehmen können und mit einer Frequenz von 100Hz angesteuert werden. In einer CTC-ISR des 8Bit Timer0 werden die Helligkeitslevel durchgezählt. Solange der gewünschte Helligkeitslevel nicht erreicht ist, ist die LED eingeschaltet. Bei 4 Werten sind 3 ISR-Aufrufe pro Zyklus nötig, die ISR wird 300 mal pro Sekunde aufgerufen werden (300Hz). Per Tasten an PD0(runter) und PD1(hoch) soll die Helligkeit eingestellt werden (checkKeys.h verwenden).
Erstellen Sie eine Lösung!
Lösung anzeigen..
Quellcode [LED_PWM0.c ]#include <avr/io.h> // Definitionen laden
#include <util/delay.h> // CPU Frequenz einstellen!
#include <avr/interrupt.h>
#include "checkKeys.h" // Header einbinden
/*
Taktzahl: 1MHz/300Hz = 3333
Vorteiler: 3333/256 = 13 -> 64 -> 3
OCR0A: 3333/64 -1 = 51
Probe: (51+1)*64 = 3328 ok
*/
unsigned char helligkeit = 0 ; // Helligkeit der LED
int main( ) { // Hauptprogramm
PORTB= 0x1 ; // alle LED0 aus
DDRB= 0x1 ; // PB0 als Ausgang
TCCR0A |= 1 << WGM01; // Timer im CTC-Mode
TCCR0B |= 3 ; // Vorteiler 1: Phi/1; 2: Phi/8; 3: Phi/64; 4: Phi/256; 5: Phi/1024
TIMSK |= 1 << OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 51 ; // Wert bei dem der Timer wieder auf 0 gesetzt wird
sei( ) ; // globale Interruptfreigabe
while ( 1 ) { // Endlosschleife
checkKeys( 0b11 , 0b11 ) ; // Maske,NLogik
if ( keyEnter& 1 ) { // Taste0 gedrueckt?
if ( helligkeit> 0 ) helligkeit--;
}
if ( keyEnter& 2 ) { // Taste1 gedrueckt?
if ( helligkeit< 3 ) helligkeit++;
}
}
return 0 ;
}
ISR( TIMER0_COMPA_vect) { // Interrupt Service Routine
static unsigned char level = 0 ; // zaehlt die Helligkeitslevel
if ( level>= helligkeit) PORTB|= 1 ; // LED0 aus
else PORTB&= ~1 ; // LED0 an
level++;
if ( level >= 3 ) level = 0 ;
}
Die LED an PB0 soll nun 16 Helligkeitsstufen {0..15} annehmen können, ATtiny 2313 @1MHz, Timer0 CTC-Interrupt .
Erstellen Sie eine Lösung! Lösung anzeigen..
Quellcode [LED_PWM1.c ]#include <avr/io.h> // Definitionen laden
#include <util/delay.h> // CPU Frequenz einstellen!
#include <avr/interrupt.h>
#include "checkKeys.h" // Header einbinden
/*
Taktzahl: 1MHz/1500Hz = 667
Vorteiler: 667/256 = 2,6 -> 8 -> 2
OCR0A: 667/8 -1 = 82
Probe: (82+1)*8 = 664 ok
*/
unsigned char helligkeit = 0 ; // Helligkeit der LED
int main( ) { // Hauptprogramm
PORTB= 0x1 ; // alle LED0 aus
DDRB= 0x1 ; // PB0 als Ausgang
TCCR0A |= 1 << WGM01; // Timer im CTC-Mode
TCCR0B |= 2 ; // Vorteiler 1: Phi/1; 2: Phi/8; 3: Phi/64; 4: Phi/256; 5: Phi/1024
TIMSK |= 1 << OCIE0A; // Timer/Counter0 Output Compare Match A Interrupt Enable
OCR0A = 82 ; // Wert bei dem der Timer wieder auf 0 gesetzt wird
sei( ) ; // globale Interruptfreigabe
while ( 1 ) { // Endlosschleife
checkKeys( 0b11 , 0b11 ) ; // Maske,NLogik
if ( keyEnter& 1 ) { // Taste0 gedrueckt?
if ( helligkeit> 0 ) helligkeit--;
}
if ( keyEnter& 2 ) { // Taste1 gedrueckt?
if ( helligkeit< 15 ) helligkeit++;
}
}
return 0 ;
}
ISR( TIMER0_COMPA_vect) { // Interrupt Service Routine
static unsigned char level = 0 ; // zaehlt die Helligkeitslevel
if ( level>= helligkeit) PORTB|= 1 ; // LED0 aus
else PORTB&= ~1 ; // LED0 an
level++;
if ( level >= 15 ) level = 0 ;
}
PWM mit Hardware
Quellcode [LED_PWM2.c ] #include <avr/io.h> // Definitionen laden
#include <util/delay.h> // CPU Frequenz einstellen!
#include <avr/interrupt.h>
#define KEYREADER ~PIND & 0b11 // Einlesen, invertieren, maskieren zurecht schieben
#include "keycheck.inc" // http://mezdata.de/avr/083_c-entprellen/keycheck.inc
unsigned char helligkeit = 0 ; // Helligkeit der LED
/*
Timer0 Ausgang OC0A(PB2) Timer laeuft im FastPWM-Mode mit TOP = 0xff, Vorteiler 1
Zykluszeit ist 256 us Pulbreite kann in 256 Schritten eingestellt werden.
*/
int main( ) { // Hauptprogramm
PORTB= 0xff ; // alle LED aus
DDRB= 0xff ; // PB als Ausgang
PORTD= 0xff ; // PullUps an
TCCR0A = 1 << COM0A1 | 1 << COM0A0 | 1 << WGM01 | 1 << WGM00;
TCCR0B = 1 ; // Systemtakt durch 1
while ( 1 ) { // Endlosschleife
keyCheck( ) ;
if ( keyEnter& 1 ) { // Taste0 gedrueckt?
if ( helligkeit> 0 ) helligkeit--;
}
if ( keyEnter& 2 ) { // Taste1 gedrueckt?
if ( helligkeit< 15 ) helligkeit++;
}
OCR0A= helligkeit<< 4 ;
}
return 0 ;
}
7LED mit Software dimmen
MIttels eines ATtiny2313 @ 1MHz sollen auf dem STK200 7 LED einstellbar in ihrer Helligkeit verändert werden können. Die LED an PB0..PB6 leuchten bei log. 0. Die Helligkeit der ersten 6 LED soll in Stufen von 0 bis 15 über die Taster PD0..PD5 eingestellt werden können. Die 7. LED gibt pulsierendes Licht ab. Da hier 7 LEDs angesteuert werden sollen, reicht der PWM-Ausgang des ATiny2313 nicht aus, die Steuerung der LED geschieht per Software in einer ISR. Der bereits vorhandene Code soll vervollständigt und weiter entwickelt werden:
Quellcode [6LED_mit_PWM_vorgabe.c ] #include // Definitionen laden
#include // Interrupts laden
#include // Delay-Bibliothek laden
// ** mit STK 200 (LED neg. Logik) und ATtiny2313 @ 1MHz
/* 6 LEDs sollen in ihrer Helligkeit gesteuert werden
Helligkeit soll Werte von 0 bis 15 annehmen
Wiederholung 100 mal pro Sekunde: ISR muss 1500 * pro Sekunde aufgerufen werden
*/
unsigned char helligkeit[ ] = { 7 , 15 , 14 , 0 , 1 , 2 , 3 } ; // Helligkeitswerte der LED
ISR( TIMER0_OVF_vect) {
static unsigned char level = 0 ; // zaehlt die Helligkeitslevel
unsigned char i, ausgabe= 0 ;
PORTB |= 128 ; // PB7 an
TCNT0= ?; // wieder richtig vorspannen
for ( i= 0 ; i< 7 ; i++ ) {
if ( level>= helligkeit[ i] ) ausgabe |= 1 << i; // LED aus
}
PORTB = ( PORTB & 0b10000000 ) | ausgabe;
if ( level >= 14 ) level = 0 ;
else level++;
PORTB &= ~128 ; // PB7 aus
}
#define KEYREADER ~PIND & 0b00111111 // Einlesen, invertieren, maskieren zurecht schieben
#include "keycheck.inc" // http://mezdata.de/avr/083_c-entprellen/keycheck.inc
unsigned char auswerteTaste( ) { // ermittelt die Nummer der niedrigsten Taste
unsigned char i;
for ( i= 0 ; i< 6 ; i++ ) {
if ( keyEnter& ( 1 << i) ) break ;
}
return i;
}
int main( ) { // Hauptprogramm
unsigned char i, up = 1 ;
PORTB= 0xff ; // alle LED aus
DDRB= 0xff ; // PB als Ausgang
TCCR0B = ?; // Phi / ?
TIMSK = 1 << TOIE0; // Interrupt frei geben
sei( ) ; // globale Interruptfreigabe
while ( 1 ) { // Endlosschleife
keyCheck( ) ;
if ( keyEnter) {
i = auswerteTaste( ) ;
if ( helligkeit[ i] >= 15 ) helligkeit[ i] = 0 ;
else helligkeit[ i] ++;
}
else {
if ( up) {
if ( helligkeit[ 6 ] >= 15 ) up= 0 ;
else helligkeit[ 6 ] ++;
}
else {
if ( helligkeit[ 6 ] <= 0 ) up= 1 ;
else helligkeit[ 6 ] --;
}
_delay_ms( 50 ) ;
}
}
return 0 ;
}
Ermitteln sie die richtigen Einstellungen des ISR: Vorteiler, Vorspannen. Wie genau sind Sie rechnerisch am Ideal?
Erstellen Sie ein Struktogramm für auswerteTaste() .
Implementieren und testen Sie die Lösung.
PB7 wird beim Eintritt in die ISR eingeschaltet und beim Ende ausgeschaltet. Messen Sie die Periodendauer und die Ausführungszeit der ISR.
Begutachten Sie den vom Compiler erzeugten Assembler-Code für die ISR.
Die Helligkeitsabstufungen sollen nun auf 100 erhöht werden, die ISR müsste dafür alle 100µs aufgerufen werden. Bislang braucht die ISR bis zu 232µs für ihre Ausführung. Neben der Erhöhung des Systemtaktes gibt es die Möglichkeiten das Programm in Assembler zu schreiben oder zu versuchen es in C zu optimieren.
Versuchen Sie das Programm in C zu optimieren und messen Sie die Zeiten.
Lösung anzeigen..
Quellcode [6LED_mit_PWM.c ]// *** LED Helligkeitssteuerung mit PWM 1.1 (c) Oliver Mezger 26.6.2014
#include <avr/io.h> // Definitionen laden
#include <avr/interrupt.h> // Interrupts laden
#include <util/delay.h> // Delay-Bibliothek laden
// ** mit STK 200 (LED neg. Logik) und ATtiny2313 @ 1MHz
/* 6 LEDs sollen in ihrer Helligkeit gesteuert werden
Helligkeit soll Werte von 0 bis 15 annehmen
Wiederholung 100 mal pro Sekunde: ISR muss 1500 * pro Sekunde aufgerufen werden
Soll-Zeit: 1000000us/1500 = 666us
Vorteiler 666/256 = 2,6 gewaehlt: 8
Vorspannen des Timers 666/8 = 83,25 gewaehlt 83 somit Vorspannwert = 256-83 = 173
Tatsaechliche Zeit zwischen ISR-Aufruf: 8us*83= 664us
*/
#define optimierung 1 // kleine Anderungen mit erstaunlicher Wirkung
unsigned char helligkeit[ ] = { 7 , 15 , 14 , 0 , 1 , 2 , 3 } ; // Helligkeitswerte der LED
#if optimierung
ISR( TIMER0_COMPA_vect) { // bei 1MHZ Aufruf alle 646us Dauer 100us
static unsigned char level = 0 ; // zaehlt die Helligkeitslevel
asm volatile ( "sbi 0x16,7" ) ; // sbi PINB,7
unsigned char i, ausgabe= 0 ;
unsigned char k= 1 ;
for ( i= 0 ; i< 7 ; i++ ) {
if ( level>= helligkeit[ i] ) ausgabe |= k; // LED aus
k= k<< 1 ;
}
level++;
if ( level >= 15 ) level = 0 ;
PORTB = ( PORTB & 0b10000000 ) | ausgabe;
asm volatile ( "sbi 0x16,7" ) ; // sbi PINB,7
}
#else
ISR( TIMER0_OVF_vect) { // bei 1MHZ Aufruf alle 664us Dauer 120-232us
static unsigned char level = 0 ; // zaehlt die Helligkeitslevel
PINB= 128 ; // PB7 invertieren
TCNT0= 173 ; // wieder richtig vorspannen
unsigned char i, ausgabe= 0 ;
for ( i= 0 ; i< 7 ; i++ ) {
if ( level>= helligkeit[ i] ) ausgabe |= 1 << i; // LED aus
}
level++;
if ( level >= 15 ) level = 0 ;
PORTB = ( PORTB & 0b10000000 ) | ausgabe;
PINB= 128 ; // PB7 invertieren
}
#endif
#define KEYREADER ~PIND & 0b00111111 // Einlesen, invertieren, maskieren zurecht schieben
#include "keycheck.inc" // http://mezdata.de/avr/083_c-entprellen/keycheck.inc
int auswerteTaste( ) { // ermittelt die niedrigste Taste
unsigned char i;
for ( i= 0 ; i< 6 ; i++ ) {
if ( keyEnter& ( 1 << i) ) break ;
}
return i;
}
int main( ) { // Hauptprogramm
unsigned char i, up = 1 ;
PORTB= 0xff ; // alle LED aus
DDRB= 0xff ; // PB als Ausgang
TCCR0B = 2 ; // Phi / 8
#if optimierung
TCCR0A= 1 << WGM01; // CTC Mode mit OCR0A als TOP
TIMSK = 1 << OCIE0A; // Interrupt frei geben
OCR0A= 82 ; // bei 82 Interrupt ausloesen
#else
TIMSK = 1 << TOIE0; // Interrupt frei geben
#endif
sei( ) ; // globale Interruptfreigabe
while ( 1 ) { // Endlosschleife
keyCheck( ) ;
if ( keyEnter) {
i = auswerteTaste( ) ;
if ( helligkeit[ i] >= 15 ) helligkeit[ i] = 0 ;
else helligkeit[ i] ++;
}
else {
if ( up) {
if ( helligkeit[ 6 ] >= 15 ) up= 0 ;
else helligkeit[ 6 ] ++;
}
else {
if ( helligkeit[ 6 ] <= 0 ) up= 1 ;
else helligkeit[ 6 ] --;
}
_delay_ms( 50 ) ;
}
}
return 0 ;
}
Übersetzen Sie die ISR und die notwendingen Bestandteile zum Testen der Ausführungszeit in Assembler. Messen Sie die Ausführungszeit der ISR.
Lösung anzeigen..
Quellcode [6LEDmitPWMasm.asm ]; *** LED Helligkeitssteuerung mit PWM 1.0 (c) Oliver Mezger 22.6.2014
.include "tn2313def.inc"
;* mit STK 200 (LED neg. Logik) und ATtiny2313 @ 1MHz
.dseg ;Datenbereich
helligkeit: .byte 7 ;Platz fuer Helligkeitsfeld {7,15,14,0,1,2,3}
.cseg ;Programmbereich
.equ clk = 1 ;CPU-Takt in MHz
.equ TIMERVORSPANN = 256 - 83 ;Wert mit dem der Zaehler startet
.def tmp = R16 ;Hilfsregister
.def itmp = R17 ;Hilfsregister fuer Interrupt
.def ii = R18 ;Register fuer Interrupt
.def iaus = R19 ;Register fuer Interrupt
.def ilevel = R20 ;Register fuer Interrupt
.def innen = R21 ;Hilfsregister fuer Warteschleife
.def aussen = R22 ;Hilfsregister fuer Warteschleife
.def up = R23
.def keyold = R2 ;Taster die gedrueckt waren
.def keynew = R25 ;Taster die gedrueckt sind R>=16
.def keyenter = R3 ;Taster, die neu gedrueckt wurden
.def keyexit = R4 ;Taster, die neu losgelassen wurden
rjmp reset ;Sprung zur Initialisierung
.org OVF0addr ;naechter Befehl an der Interrupteinsprungadresse
rjmp isrOVF0 ;Sprung zur Interruptbehandlungsroutine
.org INT_VECTORS_SIZE ;weiter nach Interrupttabelle
reset: ;Initialisierung nach Reset
ldi tmp,low( RAMEND) ;oberste RAM-Adresse laden
out SPL,tmp ;Stackpointer initialisieren
ldi tmp,$ff
out PORTB,tmp ;alle LED aus
out DDRB,tmp ;PB als Ausgang
ldi tmp,2 ;Vorteiler auf Phi/8 setzen
out TCCR0B,tmp ;alle 8us ein Zaehl-Impuls
ldi tmp,1 << TOIE0 ;Timer Overflow Interrupt Enable 0 setzen
out TIMSK,tmp ;Timer kann nun Interrupt ausloesen
;* Helligkeitsfeld mit Startwerten initialisieren
ldi XH,HIGH( helligkeit) ;Datenzeiger High
ldi XL,LOW( helligkeit) ;Datenzeiger Low
ldi tmp,7 ;
st x + ,tmp ;
ldi tmp,15
st x + ,tmp
ldi tmp,14
st x + ,tmp
ldi tmp,0
st x + ,tmp
ldi tmp,1
st x + ,tmp
ldi tmp,2
st x + ,tmp
ldi tmp,3
st x + ,tmp
sei ;globale Interrupt Freigabe
loop:
ldi YH,HIGH( helligkeit) ;Datenzeiger High
ldi YL,LOW( helligkeit) ;Datenzeiger Low
ldd tmp,Y + 6 ;lade helligkeit[6]
cpi up,1
brne coutdown
inc tmp
cpi tmp,14
brne moon
clr up
rjmp moon
coutdown:
dec tmp
brne moon
ldi up,1
moon:
std Y + 6 ,tmp
ldi tmp,50
nana:
rcall warte10ms
dec tmp
brne nana
rjmp loop ;Endlos-Schleife
isrOVF0: // Aufruf alle 654us Dauer 92us
ldi itmp,TIMERVORSPANN ;Wert zum Vorspannen des Timers laden
out TCNT0,itmp ;in den Timer schreiben
sbi PINB,7 ;PB7 invertieren zwechs Zeitmessung
in itmp,SREG ;Statusregister sichern
push itmp
clr iaus
ldi ii,1
ldi XH,HIGH( helligkeit) ;Datenzeiger High
ldi XL,LOW( helligkeit) ;Datenzeiger Low
ifor:
cpi ii,0b10000000
breq iendfor
ld itmp,x + ;lade Feldelement
cp ilevel,itmp
brlo iendif
or iaus,ii
iendif:
lsl ii
rjmp ifor
iendfor:
in itmp,PORTB ;ausgeben
andi itmp,0b10000000
or itmp,iaus
out PORTB,itmp
inc ilevel
cpi ilevel,14
brlo iend
clr ilevel
iend:
pop itmp
out SREG,itmp ;Statusregister wieder herstellen
sbi PINB,7 ;PB7 invertieren zwechs Zeitmessung
reti ;Interruptbehandlung ist zu Ende
warte10ms: ;Unterprogramm 10ms warten
ldi aussen,clk* 10 ;anpassen an CPU-Takt
loop_aussen:
ldi innen,250
loop_innen:
nop
dec innen
brne loop_innen
dec aussen
brne loop_aussen
ret
keycheck: ;Unterprogramm zur Tastaturabfrage
clr keyenter
clr keyexit
in keynew,PIND ;Lade PD
com keynew ;invertieren
andi keynew,0b00111111 ;Maskieren der nicht verwendeten Pins
cpse keyold,keynew ;Test ob Veraenderung
rjmp keyaction ;Veraenderung
ret ;alles gleich
keyaction:
rcall warte10ms ;etwas warten
in tmp,PIND ;nochmal einlesen
com tmp ;invertieren bei neg. Logik
andi tmp,0b00111111 ;maskieren der nicht verwendeten Pins
cpse keynew,tmp ;ist es stabil
ret ;war nix, da nicht stabil
mov keyenter,keyold
com keyenter ;invertieren
and keyenter,keynew ;steigende Flanken, !alt & neu
mov keyexit,keynew
com keyexit ;invertieren
and keyexit,keyold ;fallende Flanken, alt & !neu
mov keyold,keynew ;alt := neu
ret
Anschluß einer RGB-LED an PB0..PB2 gegen GND
R
D0
1
2
D1
G
B
D2
3
4
D3
D4
5
6
D5
D6
7
8
D7
GND
GND
9
10
VCC
ATtiny2313
STK200 I/O Port B
Nach Anschluß einer RGB-LED wurde der Programmcode erweitert:
Quellcode [6LED_mit_PWM2.c ] // *** LED Helligkeitssteuerung mit PWM 2.0 (c) Oliver Mezger 29.6.2014
#include <avr/io.h> // Definitionen laden
#include <avr/interrupt.h> // Interrupts laden
#include <util/delay.h> // Delay-Bibliothek laden
#include <avr/pgmspace.h> // Flashzugriffe laden
// ** mit STK 200 (LED neg. Logik) und ATtiny2313 @ 4MHz
/* 6 LEDs sollen in ihrer Helligkeit gesteuert werden
Helligkeit soll Werte von 0 bis 255 annehmen
Wiederholung 100 mal pro Sekunde: ISR muss 25500 * pro Sekunde aufgerufen werden
Soll-Zeit: 4000000us/25500 = 39,2us
Vorteiler 4*39,2/256 = 0,6 gewaehlt: 1
TOP-Wert des Timers 4*39,2 = 156,8 gewaehlt 156
Tatsaechliche Zeit zwischen ISR-Aufruf: 0,25us*156= 39us
*/
unsigned char helligkeit[ ] = { 127 , 255 , 254 , 0 , 1 , 2 , 3 } ; // Helligkeitswerte der LED
ISR( TIMER0_COMPA_vect) { // bei 4MHZ Aufruf alle 39us Dauer 24,2us
static unsigned char level = 0 ; // zaehlt die Helligkeitslevel
asm volatile ( "sbi 0x16,7" ) ; // sbi PINB,7 zum Messen der ISR Dauer
unsigned char i, ausgabe= 0 ;
unsigned char k= 1 ;
for ( i= 0 ; i< 7 ; i++ ) {
if ( level>= helligkeit[ i] ) ausgabe |= k; // LED aus
k= k<< 1 ;
}
level++;
PORTB = ( PORTB & 0b10000000 ) | ausgabe;
asm volatile ( "sbi 0x16,7" ) ; // sbi PINB,7
}
#define KEYREADER ~PIND & 0b00111111 // Einlesen, invertieren, maskieren zurecht schieben
#include "keycheck.inc" // http://mezdata.de/avr/083_c-entprellen/keycheck.inc
int auswerteTaste( ) { // ermittelt die niedrigste Taste
unsigned char i;
for ( i= 0 ; i< 6 ; i++ ) {
if ( keyEnter& ( 1 << i) ) break ;
}
return i;
}
// Helligkeitswerte dem Empfinden anpassen
const unsigned char PROGMEM anpassung[ ] = { 0 , 1 , 2 , 3 , 4 , 5 , 7 , 8 , 10 , 12 , 14 , 16 , 20 , 23 , 28 , 33 , 39 , 46 , 55 , 65 , 77 , 91 , 108 , 128 , 151 , 179 , 212 , 255 } ;
void pulsierendWeis( ) {
static unsigned char up= 1 , move= 0 ;
if ( up) {
move++;
if ( move>= sizeof ( anpassung) - 1 ) up= 0 ;
}
else {
move--;
if ( move<= 0 ) up= 1 ;
}
helligkeit[ 0 ] = helligkeit[ 1 ] = helligkeit[ 2 ] = pgm_read_byte( & anpassung[ move] ) ;
}
typedef enum { Rup, Rdown, Gup, Gdown, Bup, Bdown} fadeRichtung;
const fadeRichtung fadeIt[ ] = { Rup, Gup, Rdown, Bup, Gdown, Rup, Gup, Rdown, Gdown, Bdown} ;
void rgbFade( ) { // Code ist fehlerhaft!
static unsigned char fade= 0 ;
static unsigned char moveR= 0 , moveG= 0 , moveB= 0 ;
switch ( fadeIt[ fade] ) {
case Rup:
moveR++;
if ( moveR>= sizeof ( anpassung) - 1 ) fade++;
helligkeit[ 0 ] = pgm_read_byte( & anpassung[ moveR] ) ;
break ;
case Rdown:
moveR--;
if ( moveR<= 0 ) fade++;
helligkeit[ 0 ] = pgm_read_byte( & anpassung[ moveR] ) ;
break ;
case Gup:
moveG++;
if ( moveG>= sizeof ( anpassung) - 1 ) fade++;
helligkeit[ 1 ] = pgm_read_byte( & anpassung[ moveG] ) ;
break ;
case Gdown:
moveG--;
if ( moveG<= 0 ) fade++;
helligkeit[ 1 ] = pgm_read_byte( & anpassung[ moveG] ) ;
break ;
case Bup:
moveB++;
if ( moveB>= sizeof ( anpassung) - 1 ) fade++;
helligkeit[ 2 ] = pgm_read_byte( & anpassung[ moveB] ) ;
break ;
case Bdown:
moveB--;
if ( moveB<= 0 ) fade++;
helligkeit[ 2 ] = pgm_read_byte( & anpassung[ moveB] ) ;
break ;
}
if ( fade>= sizeof ( fadeIt) ) fade= 0 ;
}
int main( ) { // Hauptprogramm
unsigned char i;
PORTB= 0xff ; // alle LED aus
DDRB= 0xff ; // PB als Ausgang
TCCR0B = 1 ; // Phi
TCCR0A= 1 << WGM01; // CTC Mode mit OCR0A als TOP
TIMSK = 1 << OCIE0A; // Interrupt frei geben
OCR0A= 156 ; // bei 82 Interrupt ausloesen
sei( ) ; // globale Interruptfreigabe
while ( 1 ) { // Endlosschleife
keyCheck( ) ;
if ( keyEnter) {
i = auswerteTaste( ) ;
if ( helligkeit[ i] >= 255 ) helligkeit[ i] = 0 ;
else helligkeit[ i] ++;
}
else {
rgbFade( ) ;
//pulsierendWeis();
_delay_ms( 5 ) ;
}
}
return 0 ;
}