Forum: Mikrocontroller und Digitale Elektronik Attiny24 - Software - PWM


von Flo (Gast)


Lesenswert?

Guten Abend,

wollte den Code für die Software Pwm auf Mikrocontroller.net für einen 
Attiny24 portieren. Leider bisher ohne Erfolg. Sieht jemand wo der Haken 
ist?

http://www.mikrocontroller.net/articles/Soft-PWM

1
/*
2
    Eine 8-kanalige PWM mit intelligentem Lösungsansatz
3
 
4
    Attiny24 
5
 
6
*/
7
 
8
// Defines an den Controller und die Anwendung anpassen
9
 
10
#define F_CPU         8000000UL           // Systemtakt in Hz
11
#define F_PWM         100                 // PWM-Frequenz in Hz
12
#define PWM_PRESCALER 8                  // Vorteiler für den Timer
13
#define PWM_STEPS     256                // PWM-Schritte pro Zyklus(1..256)
14
#define PWM_PORT      PORTA              // Port für PWM
15
#define PWM_DDR       DDRA               // Datenrichtungsregister für PWM
16
#define PWM_CHANNELS  8                  // Anzahl der PWM-Kanäle
17
 
18
// ab hier nichts ändern, wird alles berechnet
19
 
20
#define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
21
//#define T_PWM 1   //TEST
22
 
23
#if ((T_PWM*PWM_PRESCALER)<(111+5))
24
    #error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
25
#endif
26
 
27
#if ((T_PWM*PWM_STEPS)>65535)
28
    #error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.   
29
#endif
30
// includes
31
 
32
#include <stdint.h>
33
#include <string.h>
34
#include <avr/io.h>
35
#include <avr/interrupt.h>
36
 
37
// globale Variablen
38
 
39
uint16_t pwm_timing[PWM_CHANNELS+1];          // Zeitdifferenzen der PWM Werte
40
uint16_t pwm_timing_tmp[PWM_CHANNELS+1];      
41
 
42
uint8_t  pwm_mask[PWM_CHANNELS+1];            // Bitmaske für PWM Bits, welche gelöscht werden sollen
43
uint8_t  pwm_mask_tmp[PWM_CHANNELS+1];        // ändern uint16_t oder uint32_t für mehr Kanäle
44
 
45
uint8_t  pwm_setting[PWM_CHANNELS];           // Einstellungen für die einzelnen PWM-Kanäle
46
uint8_t  pwm_setting_tmp[PWM_CHANNELS+1];     // Einstellungen der PWM Werte, sortiert
47
                                              // ändern auf uint16_t für mehr als 8 Bit Auflösung  
48
 
49
volatile uint8_t pwm_cnt_max=1;               // Zählergrenze, Initialisierung mit 1 ist wichtig!
50
volatile uint8_t pwm_sync;                    // Update jetzt möglich
51
 
52
// Pointer für wechselseitigen Datenzugriff
53
 
54
uint16_t *isr_ptr_time  = pwm_timing;
55
uint16_t *main_ptr_time = pwm_timing_tmp;
56
 
57
uint8_t *isr_ptr_mask  = pwm_mask;              // Bitmasken fuer PWM-Kanäle
58
uint8_t *main_ptr_mask = pwm_mask_tmp;          // ändern uint16_t oder uint32_t für mehr Kanäle
59
 
60
// Zeiger austauschen
61
// das muss in einem Unterprogramm erfolgen,
62
// um eine Zwischenspeicherung durch den Compiler zu verhindern
63
 
64
void tausche_zeiger(void) {
65
    uint16_t *tmp_ptr16;
66
    uint8_t *tmp_ptr8;                          // ändern uint16_t oder uint32_t für mehr Kanäle
67
 
68
    tmp_ptr16 = isr_ptr_time;
69
    isr_ptr_time = main_ptr_time;
70
    main_ptr_time = tmp_ptr16;
71
    tmp_ptr8 = isr_ptr_mask;
72
    isr_ptr_mask = main_ptr_mask;
73
    main_ptr_mask = tmp_ptr8;
74
}
75
 
76
// PWM Update, berechnet aus den PWM Einstellungen
77
// die neuen Werte für die Interruptroutine
78
 
79
void pwm_update(void) {
80
    
81
    uint8_t i, j, k;
82
    uint8_t m1, m2, tmp_mask;                   // ändern uint16_t oder uint32_t für mehr Kanäle    
83
    uint8_t min, tmp_set;                       // ändern auf uint16_t für mehr als 8 Bit Auflösung
84
 
85
    // PWM Maske für Start berechnen
86
    // gleichzeitig die Bitmasken generieren und PWM Werte kopieren
87
 
88
    m1 = 1;
89
    m2 = 0;
90
    for(i=1; i<=(PWM_CHANNELS); i++) {
91
        main_ptr_mask[i]=~m1;                       // Maske zum Löschen der PWM Ausgänge
92
        pwm_setting_tmp[i] = pwm_setting[i-1];
93
        if (pwm_setting_tmp[i]!=0) m2 |= m1;        // Maske zum setzen der IOs am PWM Start
94
        m1 <<= 1;
95
    }
96
    main_ptr_mask[0]=m2;                            // PWM Start Daten 
97
 
98
    // PWM settings sortieren; Einfügesortieren
99
 
100
    for(i=1; i<=PWM_CHANNELS; i++) {
101
        min=PWM_STEPS-1;
102
        k=i;
103
        for(j=i; j<=PWM_CHANNELS; j++) {
104
            if (pwm_setting_tmp[j]<min) {
105
                k=j;                                // Index und PWM-setting merken
106
                min = pwm_setting_tmp[j];
107
            }
108
        }
109
        if (k!=i) {
110
            // ermitteltes Minimum mit aktueller Sortiertstelle tauschen
111
            tmp_set = pwm_setting_tmp[k];
112
            pwm_setting_tmp[k] = pwm_setting_tmp[i];
113
            pwm_setting_tmp[i] = tmp_set;
114
            tmp_mask = main_ptr_mask[k];
115
            main_ptr_mask[k] = main_ptr_mask[i];
116
            main_ptr_mask[i] = tmp_mask;
117
        }
118
    }
119
 
120
    // Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
121
 
122
    k=PWM_CHANNELS;             // PWM_CHANNELS Datensätze
123
    i=1;                        // Startindex
124
 
125
    while(k>i) {
126
        while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0))  && (k>i) ) {
127
 
128
            // aufeinanderfolgende Werte sind gleich und können vereinigt werden
129
            // oder PWM Wert ist Null
130
            if (pwm_setting_tmp[i]!=0)
131
                main_ptr_mask[i+1] &= main_ptr_mask[i];        // Masken vereinigen
132
 
133
            // Datensatz entfernen,
134
            // Nachfolger alle eine Stufe hochschieben
135
            for(j=i; j<k; j++) {
136
                pwm_setting_tmp[j] = pwm_setting_tmp[j+1];
137
                main_ptr_mask[j] = main_ptr_mask[j+1];
138
            }
139
            k--;
140
        }
141
        i++;
142
    }
143
    
144
    // letzten Datensatz extra behandeln
145
    // Vergleich mit dem Nachfolger nicht möglich, nur löschen
146
    // gilt nur im Sonderfall, wenn alle Kanäle 0 sind
147
    if (pwm_setting_tmp[i]==0) k--;
148
 
149
    // Zeitdifferenzen berechnen
150
    
151
    if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind
152
        main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2;
153
        main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2;
154
        k=1;
155
    }
156
    else {
157
        i=k;
158
        main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]);
159
        tmp_set=pwm_setting_tmp[i];
160
        i--;
161
        for (; i>0; i--) {
162
            main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]);
163
            tmp_set=pwm_setting_tmp[i];
164
        }
165
        main_ptr_time[0]=(uint16_t)T_PWM*tmp_set;
166
    }
167
 
168
    // auf Sync warten
169
 
170
    pwm_sync=0;             // Sync wird im Interrupt gesetzt
171
    while(pwm_sync==0);
172
 
173
    // Zeiger tauschen
174
    cli();
175
    tausche_zeiger();
176
    pwm_cnt_max = k;
177
    sei();
178
}
179
 
180
// Timer 1 Output COMPARE A Interrupt
181
 
182
ISR(TIMER1_COMPA_vect) {
183
    static uint8_t pwm_cnt;                     // ändern auf uint16_t für mehr als 8 Bit Auflösung
184
    uint8_t tmp;                                // ändern uint16_t oder uint32_t für mehr Kanäle
185
 
186
    OCR1A += isr_ptr_time[pwm_cnt];
187
    tmp    = isr_ptr_mask[pwm_cnt];
188
    
189
    if (pwm_cnt == 0) {
190
        PWM_PORT = tmp;                         // Ports setzen zu Begin der PWM
191
                                                // zusätzliche PWM-Ports hier setzen
192
        pwm_cnt++;
193
    }
194
    else {
195
        PWM_PORT &= tmp;                        // Ports löschen
196
                                                // zusätzliche PWM-Ports hier setzen
197
        if (pwm_cnt == pwm_cnt_max) {
198
            pwm_sync = 1;                       // Update jetzt möglich
199
            pwm_cnt  = 0;
200
        }
201
        else pwm_cnt++;
202
    }
203
}
204
 
205
int main(void) {
206
 
207
    // PWM Port einstellen
208
    
209
    PWM_DDR = 0xFF;         // Port als Ausgang
210
    // zusätzliche PWM-Ports hier setzen
211
    DDRB = (1<<DDB0);
212
    PORTB = (1<<PB0);
213
    // Timer 1 OCRA1, als variablen Timer nutzen
214
 
215
    TCCR1B = 2;             // Timer läuft mit Prescaler 8
216
    TIMSK1 |= (1<<OCIE1A);   // Interrupt freischalten
217
 
218
    sei();                  // Interrupts global einschalten
219
  
220
  pwm_setting[1] = 100;
221
  pwm_setting[2] = 100;
222
  pwm_setting[3] = 100;
223
  pwm_setting[4] = 100;
224
        pwm_setting[5] = 100;
225
  pwm_setting[6] = 100;
226
  pwm_setting[7] = 100;
227
  pwm_setting[8] = 100;
228
  
229
  pwm_update();
230
  
231
    while(1){
232
    
233
    
234
  }    
235
  
236
  
237
    return 0;
238
}

Vielen Dank!

Gruß Florian

von Krapao (Gast)


Lesenswert?

Wo hast du denn was geändert?

Tipp: Benutze z.B. den Präprozessor
1
#if defined (__AVR_ATmega32__)    
2
  TIMSK |= (1<<OCIE1A); // Interrupt freischalten
3
#elif defined (__AVR_ATtiny24__)
4
  TIMSK1 |= (1<<OCIE1A); // Interrupt freischalten
5
#else
6
#error "Timer1 nicht konfiguriert"
7
#endif

von Flo (Gast)


Lesenswert?

1
TIMSK1 |= (1<<OCIE1A);   // Interrupt freischalten

und
1
pwm_setting[1] = 100;
2
pwm_setting[2] = 100;
3
pwm_setting[3] = 100;
4
pwm_setting[4] = 100;
5
pwm_setting[5] = 100;
6
pwm_setting[6] = 100;
7
pwm_setting[7] = 100;
8
pwm_setting[8] = 100;
9
pwm_update();

Viel mehr sollten die Änderungen nicht sein.
Die Idee mit den Präprozessoren ist eine sehr Gute....Danke!

von Krapao (Gast)


Lesenswert?

> #define PWM_CHANNELS  8             // Anzahl der PWM-Kanäle
> uint8_t  pwm_setting[PWM_CHANNELS]; // Einstellungen ... PWM-Kanäle
> pwm_setting[8] = 100;

Bufferoverflow!

Prüf dein Programm mal mit pwm_setting[Index] und Index von 0 bis 
PWM_CHANNELS-1

von Flo (Gast)


Lesenswert?

Ja das dürfte schon mal ein Fehler sein. Sollte von 0 losgehen.... und 
der Interruptvektor gehört eher so:
1
ISR(TIM1_COMPA_vect)

Werde ich morgen mal probieren.

Danke soweit mal.

Gruß Flo

von Krapao (Gast)


Lesenswert?

> Device: attiny24
>
> Program:     910 bytes (44.4% Full)
> (.text + .data + .bootloader)
>
> Data:         83 bytes (64.8% Full)
> (.data + .bss + .noinit)

Die 83 Bytes von 128 Bytes RAM benutzt. Der Sache ist IMHO schon nach zu 
gehen, weil nicht richtig viel Platz für den Stack bleibt. Vielleicht 
statt 8 PWMs erstmal mit einer versuchen....

> Device: attiny24
>
> Program:     518 bytes (25.3% Full)
> (.text + .data + .bootloader)
>
> Data:         27 bytes (21.1% Full)
> (.data + .bss + .noinit)

von Flo (Gast)


Lesenswert?

Guten Abend,

mit dem folgenden Code funktioniert es nun. Ausschlaggebend war wohl der 
falsche Vektor für die ISR....
1
/*
2
    Eine 8-kanalige PWM mit intelligentem Lösungsansatz
3
 
4
    Attiny24 
5
 
6
*/
7
 
8
// Defines an den Controller und die Anwendung anpassen
9
 
10
#define F_CPU         8000000UL           // Systemtakt in Hz
11
#define F_PWM         100L                 // PWM-Frequenz in Hz
12
#define PWM_PRESCALER 8                  // Vorteiler für den Timer
13
#define PWM_STEPS     256                // PWM-Schritte pro Zyklus(1..256)
14
#define PWM_PORT      PORTA              // Port für PWM
15
#define PWM_DDR       DDRA               // Datenrichtungsregister für PWM
16
#define PWM_CHANNELS  8                  // Anzahl der PWM-Kanäle
17
 
18
// ab hier nichts ändern, wird alles berechnet
19
 
20
#define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
21
//#define T_PWM 1   //TEST
22
 
23
#if ((T_PWM*PWM_PRESCALER)<(111+5))
24
    #error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
25
#endif
26
 
27
#if ((T_PWM*PWM_STEPS)>65535)
28
    #error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.   
29
#endif
30
// includes
31
 
32
#include <stdint.h>
33
#include <string.h>
34
#include <avr/io.h>
35
#include <avr/interrupt.h>
36
 
37
// globale Variablen
38
 
39
uint16_t pwm_timing[PWM_CHANNELS+1];          // Zeitdifferenzen der PWM Werte
40
uint16_t pwm_timing_tmp[PWM_CHANNELS+1];      
41
 
42
uint8_t  pwm_mask[PWM_CHANNELS+1];            // Bitmaske für PWM Bits, welche gelöscht werden sollen
43
uint8_t  pwm_mask_tmp[PWM_CHANNELS+1];        // ändern uint16_t oder uint32_t für mehr Kanäle
44
 
45
uint8_t  pwm_setting[PWM_CHANNELS];           // Einstellungen für die einzelnen PWM-Kanäle
46
uint8_t  pwm_setting_tmp[PWM_CHANNELS+1];     // Einstellungen der PWM Werte, sortiert
47
                                              // ändern auf uint16_t für mehr als 8 Bit Auflösung  
48
 
49
volatile uint8_t pwm_cnt_max=1;               // Zählergrenze, Initialisierung mit 1 ist wichtig!
50
volatile uint8_t pwm_sync;                    // Update jetzt möglich
51
 
52
// Pointer für wechselseitigen Datenzugriff
53
 
54
uint16_t *isr_ptr_time  = pwm_timing;
55
uint16_t *main_ptr_time = pwm_timing_tmp;
56
 
57
uint8_t *isr_ptr_mask  = pwm_mask;              // Bitmasken fuer PWM-Kanäle
58
uint8_t *main_ptr_mask = pwm_mask_tmp;          // ändern uint16_t oder uint32_t für mehr Kanäle
59
 
60
// Zeiger austauschen
61
// das muss in einem Unterprogramm erfolgen,
62
// um eine Zwischenspeicherung durch den Compiler zu verhindern
63
 
64
void tausche_zeiger(void) {
65
    uint16_t *tmp_ptr16;
66
    uint8_t *tmp_ptr8;                          // ändern uint16_t oder uint32_t für mehr Kanäle
67
 
68
    tmp_ptr16 = isr_ptr_time;
69
    isr_ptr_time = main_ptr_time;
70
    main_ptr_time = tmp_ptr16;
71
    tmp_ptr8 = isr_ptr_mask;
72
    isr_ptr_mask = main_ptr_mask;
73
    main_ptr_mask = tmp_ptr8;
74
}
75
 
76
// PWM Update, berechnet aus den PWM Einstellungen
77
// die neuen Werte für die Interruptroutine
78
 
79
void pwm_update(void) {
80
    
81
    uint8_t i, j, k;
82
    uint8_t m1, m2, tmp_mask;                   // ändern uint16_t oder uint32_t für mehr Kanäle    
83
    uint8_t min, tmp_set;                       // ändern auf uint16_t für mehr als 8 Bit Auflösung
84
 
85
    // PWM Maske für Start berechnen
86
    // gleichzeitig die Bitmasken generieren und PWM Werte kopieren
87
 
88
    m1 = 1;
89
    m2 = 0;
90
    for(i=1; i<=(PWM_CHANNELS); i++) {
91
        main_ptr_mask[i]=~m1;                       // Maske zum Löschen der PWM Ausgänge
92
        pwm_setting_tmp[i] = pwm_setting[i-1];
93
        if (pwm_setting_tmp[i]!=0) m2 |= m1;        // Maske zum setzen der IOs am PWM Start
94
        m1 <<= 1;
95
    }
96
    main_ptr_mask[0]=m2;                            // PWM Start Daten 
97
 
98
    // PWM settings sortieren; Einfügesortieren
99
 
100
    for(i=1; i<=PWM_CHANNELS; i++) {
101
        min=PWM_STEPS-1;
102
        k=i;
103
        for(j=i; j<=PWM_CHANNELS; j++) {
104
            if (pwm_setting_tmp[j]<min) {
105
                k=j;                                // Index und PWM-setting merken
106
                min = pwm_setting_tmp[j];
107
            }
108
        }
109
        if (k!=i) {
110
            // ermitteltes Minimum mit aktueller Sortiertstelle tauschen
111
            tmp_set = pwm_setting_tmp[k];
112
            pwm_setting_tmp[k] = pwm_setting_tmp[i];
113
            pwm_setting_tmp[i] = tmp_set;
114
            tmp_mask = main_ptr_mask[k];
115
            main_ptr_mask[k] = main_ptr_mask[i];
116
            main_ptr_mask[i] = tmp_mask;
117
        }
118
    }
119
 
120
    // Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
121
 
122
    k=PWM_CHANNELS;             // PWM_CHANNELS Datensätze
123
    i=1;                        // Startindex
124
 
125
    while(k>i) {
126
        while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0))  && (k>i) ) {
127
 
128
            // aufeinanderfolgende Werte sind gleich und können vereinigt werden
129
            // oder PWM Wert ist Null
130
            if (pwm_setting_tmp[i]!=0)
131
                main_ptr_mask[i+1] &= main_ptr_mask[i];        // Masken vereinigen
132
 
133
            // Datensatz entfernen,
134
            // Nachfolger alle eine Stufe hochschieben
135
            for(j=i; j<k; j++) {
136
                pwm_setting_tmp[j] = pwm_setting_tmp[j+1];
137
                main_ptr_mask[j] = main_ptr_mask[j+1];
138
            }
139
            k--;
140
        }
141
        i++;
142
    }
143
    
144
    // letzten Datensatz extra behandeln
145
    // Vergleich mit dem Nachfolger nicht möglich, nur löschen
146
    // gilt nur im Sonderfall, wenn alle Kanäle 0 sind
147
    if (pwm_setting_tmp[i]==0) k--;
148
 
149
    // Zeitdifferenzen berechnen
150
    
151
    if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind
152
        main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2;
153
        main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2;
154
        k=1;
155
    }
156
    else {
157
        i=k;
158
        main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]);
159
        tmp_set=pwm_setting_tmp[i];
160
        i--;
161
        for (; i>0; i--) {
162
            main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]);
163
            tmp_set=pwm_setting_tmp[i];
164
        }
165
        main_ptr_time[0]=(uint16_t)T_PWM*tmp_set;
166
    }
167
 
168
    // auf Sync warten
169
 
170
    pwm_sync=0;             // Sync wird im Interrupt gesetzt
171
    while(pwm_sync==0);
172
 
173
    // Zeiger tauschen
174
    cli();
175
    tausche_zeiger();
176
    pwm_cnt_max = k;
177
    sei();
178
}
179
 
180
// Timer 1 Output COMPARE A Interrupt
181
 
182
ISR(TIM1_COMPA_vect) {
183
    static uint8_t pwm_cnt;                     // ändern auf uint16_t für mehr als 8 Bit Auflösung
184
    uint8_t tmp;                                // ändern uint16_t oder uint32_t für mehr Kanäle
185
 
186
    OCR1A += isr_ptr_time[pwm_cnt];
187
    tmp    = isr_ptr_mask[pwm_cnt];
188
  PORTB ^= ( 1 << PB0 );
189
    
190
    if (pwm_cnt == 0) {
191
        PWM_PORT = tmp;                         // Ports setzen zu Begin der PWM
192
                                                // zusätzliche PWM-Ports hier setzen
193
        pwm_cnt++;
194
    }
195
    else {
196
        PWM_PORT &= tmp;                        // Ports löschen
197
                                                // zusätzliche PWM-Ports hier setzen
198
        if (pwm_cnt == pwm_cnt_max) {
199
            pwm_sync = 1;                       // Update jetzt möglich
200
            pwm_cnt  = 0;
201
        }
202
        else pwm_cnt++;
203
    }
204
}
205
 
206
int main(void) {
207
 
208
    // PWM Port einstellen
209
    
210
    PWM_DDR = 0xFF;         // Port als Ausgang
211
    // zusätzliche PWM-Ports hier setzen
212
    DDRB = (1<<DDB0);
213
  PORTB = (1<<PB0);
214
    // Timer 1 OCRA1, als variablen Timer nutzen
215
 
216
    TCCR1B = 2;             // Timer läuft mit Prescaler 8
217
    TIMSK1 |= (1<<OCIE1A);   // Interrupt freischalten
218
 
219
    sei();                  // Interrupts global einschalten
220
  
221
  pwm_setting[0] = 100;
222
  pwm_setting[1] = 100;
223
  pwm_setting[2] = 100;
224
  pwm_setting[3] = 100;
225
    pwm_setting[4] = 100;
226
  pwm_setting[5] = 100;
227
  pwm_setting[6] = 100;
228
  pwm_setting[7] = 100;
229
  
230
  pwm_update();
231
  
232
    while(1){
233
    
234
    
235
  }    
236
  
237
  
238
    return 0;
239
}

Damit hat das ganze schon mal einen Teilerfolg. Für mehr Möglichkeiten 
fehlt es, dann aber schon fast an SRAM..... :)

Da sollte aber ein Attiny44 evtl. Abhilfe schaffen...

Gruß Flo

von Karl H. (kbuchegg)


Lesenswert?

Flo schrieb:

> Damit hat das ganze schon mal einen Teilerfolg. Für mehr Möglichkeiten
> fehlt es, dann aber schon fast an SRAM..... :)
>
> Da sollte aber ein Attiny44 evtl. Abhilfe schaffen...

Nichts gegen diese Form der PWM, die ist schon super.
Sie geht aber auch (für diesen Fall) schon sehr verschwenderisch mit dem 
Speicher um.

Eine 8 Bit PWM bei 8Mhz und ca 100Hz kriegst du auch mit einer 
klassischen IST-PWM bei 9 Byte Speicherverbrauch noch gut hin. Braucht 
ein wenig mehr Rechenzeit, ist aber kein Problem.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.