Das folgende Codebeispiel soll als Ergänzung dienen. Oft wird gewünscht, eine LED zu dimmen. Dies ist elektronisch korrekt nur möglich, in dem die LED mit kurzen Signalimpulsen angesteuert wird: per PWM.
Der Code läßt drei LEDs an PORTD unterschiedlich schnell unterschiedlich hell und dunkel werden.
Code:
/*
* Läßt drei LEDs per Software PWM hell und dunkel werden.
*
* XII/2013 Florian Schäffer
*
* ATmega168
* 8 MHz Quarz
* avrdude -p atmega168 -P com3 -c stk500v2 -B1.5 -E -U lfuse:w:0xf7:m -U hfuse:w:0xde:m
*
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#define LED0_DDR DDRD // Datenrichtungsregister
#define LED0_PORT PORTD // Datenport
#define LED0_BIT 0 // welches Bit am Port
#define LED0_min 80 // Minimale Helligkeit (0..255)
#define LED0_max 200 // Maximale Helligkeit (0..255)
#define LED0_step 30 // Schrittweite/Geschwindigkeit (1..254), je größer die Zahl, desto schneller der helligkeitswechsel
#define LED1_DDR DDRD
#define LED1_PORT PORTD
#define LED1_BIT 1
#define LED1_min 0
#define LED1_max 255
#define LED1_step 5
#define LED2_DDR DDRD
#define LED2_PORT PORTD
#define LED2_BIT 2
#define LED2_min 15
#define LED2_max 255
#define LED2_step 15
int main (void);
volatile uint8_t cnt = 0;
volatile int16_t led0_cnt = 0;
volatile uint8_t led0_dir = 0;
volatile int16_t led1_cnt = 0;
volatile uint8_t led1_dir = 0;
volatile int16_t led2_cnt = 0;
volatile uint8_t led2_dir = 0;
uint8_t timermin = 220; // Timer 0 läuft von timermin bis 255, Wert beeinflußt das Flackern/die "Bildwiederholfrequenz". 200 = leichtes Flimmern. 220 = kein Flimmern
// Timer 0 Überlauf
ISR (TIMER0_OVF_vect)
{
cnt++;
// LED 0
if (cnt >= led0_cnt)
LED0_PORT &= ~(1 << LED0_BIT); // aus
else
LED0_PORT |= (1 << LED0_BIT); // ein
// LED 1
if (cnt >= led1_cnt)
LED1_PORT &= ~(1 << LED1_BIT); // aus
else
LED1_PORT |= (1 << LED1_BIT); // ein
// LED 2
if (cnt >= led2_cnt)
LED2_PORT &= ~(1 << LED2_BIT); // aus
else
LED2_PORT |= (1 << LED2_BIT); // ein
TCNT0 = timermin;
}
// Timer 1 Überlauf
ISR (TIMER1_OVF_vect)
{
// LED 0
if (led0_dir == 0) // Laufrichtung
led0_cnt += LED0_step; // Dunkel -> Hell
else
led0_cnt -= LED0_step; // Hell -> Dunkel
if (led0_cnt <= LED0_min) // Laufrichtung ändern
led0_dir = 0; // Dunkel -> Hell
if (led0_cnt >= LED0_max)
led0_dir = 1; // Hell -> Dunkel
// LED 1
if (led1_dir == 0)
led1_cnt += LED1_step;
else
led1_cnt -= LED1_step;
if (led1_cnt <= LED1_min)
led1_dir = 0;
if (led1_cnt >= LED1_max)
led1_dir = 1;
// LED 2
if (led2_dir == 0)
led2_cnt += LED2_step;
else
led2_cnt -= LED2_step;
if (led2_cnt <= LED2_min)
led2_dir = 0;
if (led2_cnt >= LED2_max)
led2_dir = 1;
}
// Main
int main()
{
LED0_DDR |= (1 << LED0_BIT);
LED0_PORT &= ~(1 << LED0_BIT); // aus
LED1_DDR |= (1 << LED1_BIT);
LED1_PORT &= ~(1 << LED1_BIT); // aus
LED2_DDR |= (1 << LED2_BIT);
LED2_PORT &= ~(1 << LED2_BIT); // aus
// PWD Timer
TCNT0 = timermin;
TIMSK0 |= (1 << TOIE0); // Überlauf IRQ
TCCR0B |= (1 << CS00); // keine Prescaler
// Timer für hell dunkel
TIMSK1 |= (1 << TOIE0); // Überlauf IRQ
TCCR1B |= (1 << CS00); // keine Prescaler
sei(); // IRQs ein
while (1) ; // NOP endlos
return 0; // niemals
}