Forum: Mikrocontroller und Digitale Elektronik Soft-PWM macht nicht was es soll


von Marcel H. (multiholle)


Lesenswert?

Ich bekomme mein Software PWM für mehrere Kanäle nicht zum Laufen. Jetzt 
habe ich mich erstmal auf einen Kanal beschränkt, jedoch klappt das 
immer noch nicht.

Die LED habe ich auf den Wert 2 von 255 gesetzt. Sie leuchtet jedoch 
nicht schwach sondern blinkt sichtbar sehr schnell. Beim Code habe ich 
mich an dem Soft-PWM-Tutorial von hier orientiert.

Was mache ich falsch?


Hier mein Code:
1
#define F_PWM     100
2
#define CHANNELS  1
3
#define STEPS     256
4
#define PRESCALER 1
5
#define T_PWM     (F_CPU / PRESCALER * F_PWM * STEPS)
6
7
volatile uint8_t sync;
8
uint16_t timings_A[CHANNELS + 1];
9
uint16_t timings_B[CHANNELS + 1];
10
11
uint8_t steps = 1;
12
uint8_t buf_steps;
13
uint16_t* timings = timings_A;
14
uint16_t* buf_timings = timings_B;
15
16
ISR(TIMER1_COMPA_vect) {
17
  static uint8_t step;
18
19
  // switch led
20
  if (step == 0) {
21
    PORTC |= (1 << PC4);
22
    OCR1A = timings[0];
23
  } else {
24
    PORTC &= ~(1 << PC4);
25
    OCR1A += timings[step];
26
  }
27
  
28
  // set next step
29
  step++;
30
  if (step == steps) {
31
    step = 0; 
32
     
33
    // swap
34
    if (sync) {
35
      uint8_t tmp_steps = steps;
36
      steps = buf_steps;
37
      buf_steps = tmp_steps;
38
39
      uint16_t* tmp_timings = timings;
40
      timings = buf_timings;
41
      buf_timings = tmp_timings;
42
43
      // set swap finish
44
      sync = 0;
45
    }
46
  }
47
}
48
49
void set(uint8_t value) {
50
  // set pwm values
51
  buf_timings[0] = T_PWM * value;
52
  buf_timings[1] = T_PWM * (255 - value); 
53
54
  buf_steps = 2;
55
56
  // wait for sync
57
  sync = 1;
58
59
  // wait for swap finish
60
  while (sync == 1);
61
}
62
63
int main(void) {
64
  // set timer prescaler to F_CPU/8
65
    TCCR1B |= (1 << CS11);
66
  // enable output compare interrupt
67
    TIMSK1 |= (1 << OCIE1A);
68
  // enable global interrupts
69
  sei();
70
71
  // set led output
72
  DDRC |= (1 << PC4);
73
74
  // test
75
  set(2);
76
77
78
  while (1);
79
}

von Karl H. (kbuchegg)


Lesenswert?

Marcel Holle schrieb:

> Was mache ich falsch?

Warum hast du deinen Compiler angelogen?


> #define PRESCALER 1

> int main(void) {
>   // set timer prescaler to F_CPU/8
>     TCCR1B |= (1 << CS11);


Die Berechnung auf 100Hz (T_PWM) basiert auf einem Prescaler von 1, den 
Timer stellst du aber auf einen Prescaler von 8. D.h. die Berechnung der 
Compare Werte ergibt Werte die 8 mal zu groß sind. Damit kriegst du 
nicht 100Hz PWM-Wiederholfrequenz sondern nur 12.5Hz. Und das siehst du 
dann.

von Marcel H. (multiholle)


Lesenswert?

OK, das Flimmern ist jetzt weg. Allerdings leuchtet die LED konstant mit 
einer Helligkeit, egal welche Einstellung ich setze (2 oder 240 ist kein 
Unterschied).

Ich berechne die Zeiten im Array timings und übergebe sie dann im 
jeweiligen PWM-Schritt an den Timer. Was mache ich falsch?

von Karl H. (kbuchegg)


Lesenswert?

Marcel Holle schrieb:

> Ich berechne die Zeiten im Array timings und übergebe sie dann im
> jeweiligen PWM-Schritt an den Timer. Was mache ich falsch?

Mit welcher Taktfequenz betreibst du den Controller? Welchen Prescaler?
Hast du schon mal nachgerechnet, was bei T_PWM für Werte rauskommen?
Wenn die zu klein sind, dann kommt deine ISR nicht mehr hinterher, bzw. 
es bleibt kaum noch Rechenzeit für etwas anders als Compare Matches 
übrig.

Noch ein Detail am Rande:
Denk nochmal über die Reihenfolge der Initialisierungen im main() nach. 
Es ist wohl kaum sinnvoll zuerst durch eine Tür zu gehen und sie erst 
dann zu öffnen. Genauso ist es bei Initialisierungen (auch wenn das 
jetzt bei dir kein Problem darstellt)

von Falk B. (falk)


Lesenswert?

@Marcel Holle (multiholle)

>nicht schwach sondern blinkt sichtbar sehr schnell. Beim Code habe ich
>mich an dem Soft-PWM-Tutorial von hier orientiert.

Ohje. Und warum zerpflückst du einen super funktionierendes Programm und 
machst so einen Murks?

von Marcel H. (multiholle)


Lesenswert?

T_PWM hat den Wert 97, ist das zu gering?

Falk Brunner schrieb:
> Ohje. Und warum zerpflückst du einen super funktionierendes Programm und
> machst so einen Murks?
Ich kopiere nicht gerne einfach nur den Code. Ich möchte ihn verstehen, 
sonst bringt er mir nichts :/ Aber so richtig komme ich nicht klar.

von Karl H. (kbuchegg)


Lesenswert?

Marcel Holle schrieb:
> T_PWM hat den Wert 97, ist das zu gering?

Sollte reichen.
F_CPU ?
Prescaler ?

> Falk Brunner schrieb:
>> Ohje. Und warum zerpflückst du einen super funktionierendes Programm und
>> machst so einen Murks?
> Ich kopiere nicht gerne einfach nur den Code. Ich möchte ihn verstehen,
> sonst bringt er mir nichts :/ Aber so richtig komme ich nicht klar.

Wenn man Code verstehen will, denn man übernimmt, gibt es eine einfache 
Reihenfolge:

Zuerst wird der Code so wie er ist übernommen und getestet. Tut er das 
was der Autor behauptet?

Wenn nein, dann den Autor kontaktieren

Wenn ja, dann gehts weiter. Dann macht man erste kleine Veränderungen. 
Zwischendurch immer wieder kontrollieren: tut er noch?

Weitere Veränderungen. Dazwischen immer wieder: Tut er noch?

Und wenn man dann an einem Ende angelangt ist, dann stellt man sich die 
Frage: Jetzt nachdem ich alle Details verstehe - schreibe ich ihn neu 
oder nicht?

Wenn man viel Erfahrung hat, dann macht man manchmal auch dieses:
Man studiert den Code in allen Details und schreibt ihn neu. Allerdings 
muss man da meistens schon viel Erfahrung haben und auch darin geübt 
sein, Nebeneffekte im Code zu sehen.

von Falk B. (falk)


Lesenswert?

@ Karl heinz Buchegger (kbuchegg) (Moderator)

Genau so siehts aus!

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.