Hallo,
ich möchte gerne per Software-PWM LED-Fading durchführen. Als Basis
dient ein Attiny861A, an welchem eine LED zwischen PA5 und PA6 hängt.
Als Basis habe ich zunächst die erste Variante der Software-PWM aus dem
Artikel Soft-PWM verwendet. Die Software-PWM an sich funktioniert
soweit auch. Nun wollte ich einen ersten Ansatz zum Fading der LED
ausprobieren, indem ich alle x Millisekunden das Tastverhältnis ändere.
Leider scheint hier irgendwas zu haken, wenn ich z.B. einstelle, dass
die Helligkeit sich alle 50ms erhöhen soll, so bleibt die LED etliche
Sekunden auf jede Helligkeitsstufe stehen. Erst wenn ich "sleep(1)"
setze geht es etwas schneller, ein vollständiger Durchlauf benötigt aber
immer noch ~20 Sekunden.
Kann mir jemand sagen, wo mein Fehler ist? Ich vermute, dass irgendwo
die ISR dazwischen funkt, aber ich habe noch nicht so viel Erfahrung und
nachdem ich nun zwei Stunden alles mögliche probiert habe weiß ich
wirklich nicht mehr weiter.
Hier noch der Code, den ich verwende:
1 | #define F_CPU 8000000UL
|
2 | #include <avr/io.h>
|
3 | #include <avr/interrupt.h>
|
4 | #include <util/delay.h>
|
5 |
|
6 | #define F_PWM 100
|
7 | #define PWM_STEPS 255
|
8 | #define T_PWM (F_CPU / (F_PWM * PWM_STEPS))
|
9 |
|
10 | #if (T_PWM < (152 + 5))
|
11 | #error T_PWM zu klein!
|
12 | #endif
|
13 |
|
14 | #if PWM_STEPS > 255
|
15 | #error PWM_STEP zu gross!
|
16 | #endif
|
17 |
|
18 | volatile uint8_t dutyCycle = 16;
|
19 |
|
20 | void sleep(uint16_t ms) {
|
21 | for(; ms > 0; ms--) {
|
22 | _delay_ms(1);
|
23 | }
|
24 | }
|
25 |
|
26 | ISR(TIMER1_COMPA_vect) {
|
27 | static uint8_t pwmCnt = 0;
|
28 |
|
29 | OCR1A += (uint16_t)T_PWM;
|
30 |
|
31 | if(dutyCycle > pwmCnt) {
|
32 | // LED an
|
33 | PORTA &= ~(1<<PA6);
|
34 | } else {
|
35 | // LED aus
|
36 | PORTA |= (1<<PA6);
|
37 | }
|
38 |
|
39 | if(pwmCnt == (uint8_t)(PWM_STEPS-1)) {
|
40 | pwmCnt = 0;
|
41 | } else {
|
42 | pwmCnt++;
|
43 | }
|
44 | }
|
45 |
|
46 | int main(void)
|
47 | {
|
48 | int i;
|
49 |
|
50 | // PA5 & PA6 als Ausgang, HIGH
|
51 | DDRA = (1<<DDA6)|(1<<DDA5);
|
52 | PORTA = (1<<PA6)|(1<<PA5);
|
53 |
|
54 | // Timer1 Takt = CPU Takt
|
55 | TCCR1B = 1;
|
56 | // Timer1 Output Compare Interrupt aktivieren
|
57 | TIMSK |= (1<<OCIE1A);
|
58 | // Interrupts aktivieren
|
59 | sei();
|
60 |
|
61 | while(1) {
|
62 | // Tastverhältnis ändern
|
63 | for(i = 0; i <= 255; i++) {
|
64 | dutyCycle = i;
|
65 | // warte bis zur nächsten Stufe - HIER HAKT ES SCHEINBAR
|
66 | sleep(1);
|
67 | }
|
68 | }
|
69 | }
|
Gruß
Daniel