Forum: Mikrocontroller und Digitale Elektronik AVR ATtiny26 - 3Channel PWM


von Nicholas K. (keridos)


Lesenswert?

Guten Tag,

ich versuche seit einigen Stunden eine Steuerung für ein RGB Licht nach 
der Anleitung hier aufzubauen, allerdings mit einem ATtiny26: 
http://www.mikrocontroller.net/articles/Soft-PWM

Ich bekomme etwas PWM artiges hin: Ich benutze ein STK500 und habe an 
Port A 1-3 LEDs angeschlossen, die bei 0V ausgang am pin angehen. Sind 
also invertiert.
Allerdings sollte bei einem Wert von 255 die LED komplett aus sein, die 
Lampe wirkt allerdings so als ob sie bei 50% liegt. Wo liegt da mein 
Problem?
Kann mir bitte jemand hier helfen, ich steh da ein wenig auf dem 
Schlauch.

Vielen Dank schonmal im Vorraus,
Nico

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

: Bearbeitet durch User
von Easylife (Gast)


Lesenswert?

So nach dem Motto: ich rotze da mal 261 Zeilen unglaublich 
verkomplizierten und total intelligenten, jedoch nicht funktionierenden 
Code hin, und das Debuggen überlasse ich dann anderen?

3 Kanal PWM, 261 Zeilen Code?
Alter...

Und nebenbei: es wäre evtl. auch möglich gewesen, erstmal das Suchfeld 
zu benutzen:
http://www.mikrocontroller.net/articles/Soft-PWM
Beitrag "3-kanal-PWM mit ATmega8"

von Easylife (Gast)


Lesenswert?

Sorry, zu früh geranted, 1. Link ist ja wie dein Code...
OK, ich geh mal ausschlafen... ;-)

von Sam (Gast)


Lesenswert?

Geh mal davon aus, dass deine PWM nicht perfekt ist, sondern bei 255 den 
Ausgang einen Takt lang auf High setzt. Ich habe deinen Code nicht 
gelesen, ich geh aber mal davon aus, dass du Fast-PWM benutzt.

Mit dieser Annahme liest du dir dann mal diesen Artikel durch und 
erkennst dein Problem:
http://www.mikrocontroller.net/articles/LED-Fading

von Hui (Gast)


Lesenswert?

Sam schrieb:
> Geh mal davon aus, dass deine PWM nicht perfekt ist, sondern bei 255 den
> Ausgang einen Takt lang auf High setzt. Ich habe deinen Code nicht
> gelesen, ich geh aber mal davon aus, dass du Fast-PWM benutzt.

Oh, endlich ein geposteter Code und prompt wird er nicht beachtet und in 
die Glaskugel geschaut. Hättest ja weingstens nach dem Schaltplan fragen 
können. Ich dreh ab ...

von Peter D. (peda)


Lesenswert?

Hui schrieb:
> Oh, endlich ein geposteter Code und prompt wird er nicht beachtet

Antwort schreiben
Wichtige Regeln - erst lesen, dann posten!

    Groß- und Kleinschreibung verwenden
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

von Peter D. (peda)


Lesenswert?

Nimm den aktuellen ATtiny261, der hat 3 PWM-Ausgänge (OC1A, OC1B, OC1D).

von gvs (Gast)


Lesenswert?

Hast mal den Systemtakt geprüft bzw. verändert?

von Nicholas K. (keridos)


Lesenswert?

Der interner Oszillator ist auf 8MHz geschaltet. Der Sourcecode 
entspricht zu 99,9% dem SoftPWM Code aus dem Wiki, sollte also 
eigentlich problemlos funktionieren. Hab es auch mit 4MHZ Systemtakt 
probiert sowie verschiedenen PWM Takten.

Sam schrieb:
> Geh mal davon aus, dass deine PWM nicht perfekt ist, sondern bei
> 255 den
> Ausgang einen Takt lang auf High setzt. Ich habe deinen Code nicht
> gelesen, ich geh aber mal davon aus, dass du Fast-PWM benutzt.
>
> Mit dieser Annahme liest du dir dann mal diesen Artikel durch und
> erkennst dein Problem:
> http://www.mikrocontroller.net/articles/LED-Fading

Die LED leuchtet allerdings nicht schwach, sondern relativ hell.

: Bearbeitet durch User
von Easylife (Gast)


Lesenswert?

So, ausgeschlafen ;-)
Wie hast du denn die LEDs an den Ports angeschlossen?
Anode (mit Vorwiderstand!) an VCC, Kathode an I/O pin?
Vorwiderstand eventuell mal vergessen, und so den Ausgangstreiber 
gebraten?

von Nicholas K. (keridos)


Lesenswert?

Die sind auf dem STK500 so geschaltet, dass sie bei low active sind.
Ich teste das Board momentan auf dem Board. Später wird das ganze über 3 
Optokoppler an 3 BUZ71A gehangen, welche dann einen 5050 LED Streifen 
ansteuern werden.

/edit: Noch ein Zusatzgedanke: Wenn ich den Systemtakt oder die PWM Rate 
(100Hz Standard)ändere und alle defines anpasse hab ich das Gefühl, dass 
die PWM inkonsistente Ergebnisse liefert.

: Bearbeitet durch User
von Michael K. (Gast)


Lesenswert?

Das ist ja ein heilloses durcheinander das mir Kopfschmerzen verursacht.
Wirklich nur 3 * PWM mit 8bit Auflösung und 100Hz Wiederholrate ?

Ich verstehe schon mal nicht wieso Du Deine Zeitbasis permanent 
veränderst.
>>OCR1A += isr_ptr_time[pwm_cnt];
Was soll den für ein Zeitverhalten rauskommen wenn Du ständig an der Uhr 
drehst ?

Du must doch nur alle (1/(100hz * 256)) sek. (40us) eine Funktion 
aufrufen (per Timer irq) die einen 8bit wert fortlaufend hochzählt (mit 
Überlauf auf null) und drei Sollwerte damit vergleicht.
Ist der Sollwert größer wird angeschaltet, sonst ausgeschaltet.

Braucht das mehr 40us um bearbeitet zu werden gehts nicht und Du must 
Wiederholrate oder Auflösung verringern, bzw. die Taktfrequenz erhöhen 
damit der tiny das berechnen kann bevor der nächste irq kommt.

Um zu checken wie viel Zeitpuffer Du noch hast bevor das Teil an die 
Wand fährt setzt du in der while(1) einen pin der in der ISR rückgesetzt 
wird.
Geht der Pin nie oder unregelmäßig auf 1 hast Du ein timing Problem.

Alles was nicht zeitkritisch ist, z.B. Potis einlesen oder Fading etc. 
machst Du in der Main.

von Karl H. (kbuchegg)


Lesenswert?

Michael Knoelke schrieb:
> Das ist ja ein heilloses durcheinander das mir Kopfschmerzen verursacht.
> Wirklich nur 3 * PWM mit 8bit Auflösung und 100Hz Wiederholrate ?
>
> Ich verstehe schon mal nicht wieso Du Deine Zeitbasis permanent
> veränderst.
>>>OCR1A += isr_ptr_time[pwm_cnt];
> Was soll den für ein Zeitverhalten rauskommen wenn Du ständig an der Uhr
> drehst ?

Die Idee in dem Code ist es offenbar, die für die PWM notwenigen 
Portereignisse zeitlich zu ordnen und dann nur zu diesen Zeitpunkten die 
ISR aufrufen zu lassen. D.h. wird eine ISR Inkarnation abgearbeitet, 
dann wird errechnet, wann sich das nächste mal an den Portbits was tun 
muss und quasi 'der Wecker' auf diesen Zeitpunkt gestellt.

An und für sich eine nicht unclevere Idee, die massig Resourcen spart.

Aber der Code ist mir zu gross als das ich ihn im Kopf noch überblicken 
könnte. Daher lass ich die Fehlersuche.

Wenn der Tiny eh nichts anderes zu tun hat, als 3 PWM Kanäle zu 
servicieren, wäre mir das egal, ob der jetzt 30% seiner Zeit in der ISR 
rumlungert oder nur 0.5% und den Rest Däumchen dreht. Ich hätt genauso 
wie du eine klassische Software-PWM genommen.

: Bearbeitet durch User
von Michael K. (Gast)


Lesenswert?

Karl Heinz schrieb:
> An und für sich eine nicht unclevere Idee, die massig Resourcen spart.

Ok, das macht irgendwie Sinn.
Nun habe ich aber drei Ereignisse die fast zeitgleich sind.
Ereigniss 1 kommt zum berechneten Zeitpunkt, wenn ich denn die 
Ausführungszeit meines Codes korrekt berücksichtigt habe.
Dann rödelt die kleine MCU verzweifelt vor sich hin, aber Ereigniss 2 
ist schon sowas von abgelaufen um von 3 garnicht erst zu reden.
Trotzdem muß eine Zeit gesetzt werden die erst dann den IRQ triggert 
wenn ich die Routinen komplett abgearbeitet und sauber in die Main 
beendet habe.

Dafür gammelt die MCU die ganze restliche Zeit vor sich hin und bohrt in 
der Nase.

Muß ich mir das so ungefähr vorstellen ?

Mir scheint sowas geht nur wenn die CPU sehr schnell und die Ereignisse 
sehr langsam sind und somit der Jitter effektiv keine Rolle spielt.

von Bernd K. (prof7bit)


Lesenswert?

Karl Heinz schrieb:

> wann sich das nächste mal an den Portbits was tun
> muss und quasi 'der Wecker' auf diesen Zeitpunkt gestellt.
> [...]
> Wenn der Tiny eh nichts anderes zu tun hat, als 3 PWM Kanäle zu
> servicieren, wäre mir das egal, ob der jetzt 30% seiner Zeit in der ISR
> rumlungert

Es gibt auch noch nen Mittelweg, bei 8 Bit Auflösung braucht man 
eigentlich nur 8 Interrupts anstelle von 256, der Trick ist die 8 Zeiten 
sind unterschiedlich lang, und zwar entspricht ihre Länge genau dem 
Bitwert jedes der 8 Bits in dem Byte das die Helligkeit repräsentiert, 
Also zum Beispiel:

Bit 0 gesetzt -> 1 ms lang high
Bit 1 gesetzt -> 2 ms
Bit 2 gesetzt -> 4 ms
...
Bit 7 gesetzt -> 128 ms

damit kann man dann die Gesamtzeit in 1 ms Schritten einstellen und 
braucht dennoch nur 8 Interrupts. Man muss nichts umständlich sortieren 
und man kann relativ unkompliziert viele verschiedene Pins ansteuern. 
Nachteil: Es kommt kein simples Rechteck mehr raus sondern eine schnelle 
Folge unterschiedlich langer Pulse, aber meist spielt das überhaupt 
keine Rolle, wichtig ist nur das Verhältnis zwischen ein- und aus-Zeit.

von Karl H. (kbuchegg)


Lesenswert?

Michael Knoelke schrieb:

> Nun habe ich aber drei Ereignisse die fast zeitgleich sind.

Sind sie zeitgleich dann legt der Code sie zusammen.
Sind sie nicht zeitgleich, dann darf die Zeitdifferenz natürlich nicht 
größer als die ISR Duchlaufzeit sein. Bei entsprechendem Timer-Prscaler 
sollte das kein Problem sein.

> Dafür gammelt die MCU die ganze restliche Zeit vor sich hin und bohrt in
> der Nase.
>
> Muß ich mir das so ungefähr vorstellen ?

So in etwa würde ich das sehen :-)
OK. Man könnte sie in den Sleep schicken. Allerdings dürfte das bisschen 
Strom bei (wieviele warens noch mal) x RGB-LED auch schon wurscht sein.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:
> Michael Knoelke schrieb:
>
>> Nun habe ich aber drei Ereignisse die fast zeitgleich sind.
>
> Sind sie zeitgleich dann legt der Code sie zusammen.
> Sind sie nicht zeitgleich, dann darf die Zeitdifferenz natürlich nicht
> größer als die ISR Duchlaufzeit sein. Bei entsprechendem Timer-Prscaler
> sollte das kein Problem sein.

Na ich glaub da hab ich den Mund etwas zu voll genommen.
Aus dem Original
1
#define F_CPU         8000000L           // Systemtakt in Hz
2
#define F_PWM         100L               // PWM-Frequenz in Hz
3
#define PWM_PRESCALER 8                  // Vorteiler für den Timer
4
#define PWM_STEPS     256                // PWM-Schritte pro Zyklus(1..256)
5
#define PWM_PORT      PORTB              // Port für PWM
6
#define PWM_DDR       DDRB               // Datenrichtungsregister für PWM
7
#define PWM_CHANNELS  8                  // Anzahl der PWM-Kanäle
8
 
9
// ab hier nichts ändern, wird alles berechnet
10
 
11
#define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt

setze ich die Werte ein, kriege ich 39 raus. D.h. meinem Verständnis 
nach ist das die Mindestzahl an Systemtakten, die zwischen 2 Ereignissen 
möglich ist.

Könnte mit der ISR im Extremfall eng werden.

von Nicholas K. (keridos)


Lesenswert?

Ich versuche mal aus dem wiki artikel die etwas einfachere Steuerung und 
ich glaube sie funktioniert auch recht gut. Problem ist ich brauch zum 
testen eine negierte PWM, kann mir wer einen Tipp geben, wie ich eine 
uint schnell bitweise negieren kann?

von Karl H. (kbuchegg)


Lesenswert?

Nicholas K. schrieb:
> Ich versuche mal aus dem wiki artikel die etwas einfachere Steuerung und
> ich glaube sie funktioniert auch recht gut. Problem ist ich brauch zum
> testen eine negierte PWM, kann mir wer einen Tipp geben, wie ich eine
> uint schnell bitweise negieren kann?
1
  PORTx = ~ Wert;

: Bearbeitet durch User
von Michael K. (Gast)


Lesenswert?

Bernd K. schrieb:
> Es gibt auch noch nen Mittelweg

Ich muss also entscheiden in welcher der 8 irqs die leds an oder 
ausgeschaltet werden.
Nicht so einfach wie meine Software PWM nicht so von hinten durch die 
Brust ins Auge wie der 'Wecker'.

Ich persönlich halte mehr von PDM (Pulse Dichte Modulation) weil viele 
PWM Ausgänge kein Thema sind und durch das Pulsmuster eine geringe 
Wiederholfrequenz weniger auffällt.
Mit einem 24Mhz 8051 sind 4 x 10bit bei 100Hz ohne Schweissausbrüche 
möglich und es bleibt genug Zeit für die RS485 und diverse 
Schutzfunktionen und Dimkurven.

Bei PWM schalten immer alle LEDs zeitgleich ein, ziehen einen wahnsinns 
Peak Strom und gehen dann alle wieder aus.
Bei PDM verteilt sich das besser.

von Karl H. (kbuchegg)


Lesenswert?

Michael Knoelke schrieb:
> Bernd K. schrieb:
>> Es gibt auch noch nen Mittelweg
>
> Ich muss also entscheiden in welcher der 8 irqs die leds an oder
> ausgeschaltet werden.

Das ist nicht so schwer.
Wie heisst das Verfahren noch mal?

Ach ja. Bit Angle Modulation.

http://www.batsocks.co.uk/readme/art_bcm_3.htm

von Nicholas K. (keridos)


Lesenswert?

Karl Heinz schrieb:
> Nicholas K. schrieb:
>> Ich versuche mal aus dem wiki artikel die etwas einfachere Steuerung und
>> ich glaube sie funktioniert auch recht gut. Problem ist ich brauch zum
>> testen eine negierte PWM, kann mir wer einen Tipp geben, wie ich eine
>> uint schnell bitweise negieren kann?
>   PORTx = ~ Wert;

Vielen Dank, es klappt super.
Noch eine finale Frage: Bei dem ATtiny26 hat timer0 keinen CTC modus. 
Wie heißt das Register, das ich auf 0 setzen muss in der ISR von Timer0?

von Karl H. (kbuchegg)


Lesenswert?

Nicholas K. schrieb:
> Karl Heinz schrieb:
>> Nicholas K. schrieb:
>>> Ich versuche mal aus dem wiki artikel die etwas einfachere Steuerung und
>>> ich glaube sie funktioniert auch recht gut. Problem ist ich brauch zum
>>> testen eine negierte PWM, kann mir wer einen Tipp geben, wie ich eine
>>> uint schnell bitweise negieren kann?
>>   PORTx = ~ Wert;
>
> Vielen Dank, es klappt super.
> Noch eine finale Frage: Bei dem ATtiny26 hat timer0 keinen CTC modus.
> Wie heißt das Register, das ich auf 0 setzen muss in der ISR von Timer0?

TCNT0

Aber wieso auf 0?
Wenn du keinen CTC Modus hast, dann musst du den Timer vorladen. Also zb 
mit 100, damit 156 Timer Takte später der nächste Overflow kommt. DIe 
Overflow ISR wird dann effektiv alle 156 Timer Takte angesprungen.

: Bearbeitet durch User
von Nicholas K. (keridos)


Lesenswert?

Karl Heinz schrieb:
> TCNT0
>
> Aber wieso auf 0?
> Wenn du keinen CTC Modus hast, dann musst du den Timer vorladen. Also zb
> mit 100, damit 156 Timer Takte später der nächste Overflow kommt. DIe
> Overflow ISR wird dann effektiv alle 156 Timer Takte angesprungen.

Hab es mit eurer Hilfe erfolgreich hinbekommen, vielen Danke nochmal an 
alle Helfer.

Viele Grüße
Nico

: Bearbeitet durch User
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.