Forum: Mikrocontroller und Digitale Elektronik Atmega 168 Hardware-PWM


von Marcel H. (multiholle)


Lesenswert?

Ich habe nach einer Anleitung im Netz versucht Hardware-PWM auf meinem 
Atmega 168 zu implementieren. Im groben funktioniert es auch, es tritt 
nur folgendes Problem auf:

Bei "OCR0A = 0" ist die LED nicht aus, sondern leuchtet trotzdem sehr 
schwach. Was mache ich falsch?
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/pgmspace.h>
4
5
uint16_t pwmtable[32] PROGMEM = {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11, 13,
6
    16, 19, 23, 27, 32, 38, 45, 54, 64, 76, 91, 108, 128, 152, 181, 215, 255};
7
8
int main(void) {
9
  DDRD = 1 << PD6;
10
  
11
  OCR0A = 0;  
12
  
13
  TCCR0A = 1 << COM0A1 | 1 << WGM01 | 1 << WGM00;
14
  TCCR0B = 1 << CS02;
15
  
16
  while (1) {
17
    uint16_t i;
18
    for (i = 0; i < 32; i++) {
19
      OCR0A = pgm_read_word(pwmtable + i);
20
      _delay_ms(200);
21
    }
22
  }
23
}

von Karl H. (kbuchegg)


Lesenswert?

Marcel Holle schrieb:

> # Bei "OCR0A = 0" ist die LED nicht aus, sondern leuchtet trotzdem sehr
> schwach.

Yep.
Das ist normal.

Die Hardware PWM funktioniert so, dass bei einem Timerwert von 0 auf 
jeden Fall der Ausgang ein geschaltet wird. Danach kommt der Compare 
Match bei 0 und schaltet gleich wieder aus. Aber eine gewisse kurze Zeit 
ist eingeschaltet.

>
> # Wenn ich die pwmtable einmal vernünftig durchlaufen haben, fängt die
> LED ab dem 2. Durchlauf an wilkürlich zu blinken.
>
> Was mache ich falsch?

> uint16_t pwmtable[32] PROGMEM = {0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10,
> 11, 13,
>     16, 19, 23, 27, 32, 38, 45, 54, 64, 76, 91, 108, 128, 152, 181, 215,
> 255};
>

    for (i = 0; i < 256; i++) {
>       OCR0A = pgm_read_word(pwmtable + i);

Oha.
Dein Array ist 32 Einträge groß und nicht 256

von Marcel H. (multiholle)


Lesenswert?

> Dein Array ist 32 Einträge groß und nicht 256
Das habe ich selber auch gerade gemerkt. ^^

> Die Hardware PWM funktioniert so, dass bei einem Timerwert von 0 auf
> jeden Fall der Ausgang ein geschaltet wird. Danach kommt der Compare
> Match bei 0 und schaltet gleich wieder aus. Aber eine gewisse kurze Zeit
> ist eingeschaltet.
Das heißt, ich schreibe eine Funktion "set_pwm(unit16_t value)", welche 
bei "value == 0" den timer deaktiviert und ansonsten den Wert des 
Registers ändert? Oder geht es eleganter?

von Karl H. (kbuchegg)


Lesenswert?

Marcel Holle schrieb:
>> Dein Array ist 32 Einträge groß und nicht 256
> Das habe ich selber auch gerade gemerkt. ^^
>
>> Die Hardware PWM funktioniert so, dass bei einem Timerwert von 0 auf
>> jeden Fall der Ausgang ein geschaltet wird. Danach kommt der Compare
>> Match bei 0 und schaltet gleich wieder aus. Aber eine gewisse kurze Zeit
>> ist eingeschaltet.
> Das heißt, ich schreibe eine Funktion "set_pwm(unit16_t value)", welche
> bei "value == 0" den timer deaktiviert und ansonsten den Wert des
> Registers ändert? Oder geht es eleganter?

Es reicht, wenn du den Ausgansgpin vom Timer wegkoppelst (COM0A1 wieder 
löschen) und den Pin auf 0 setzt.
den Timer kannst du ja weiter laufen lassen.

(Und natürlich umgekehrt, wenn dann wieder ein PWM Wert ungleich 0 
kommt)

von Spess53 (Gast)


Lesenswert?

Hi

>Bei "OCR0A = 0" ist die LED nicht aus, sondern leuchtet trotzdem sehr
>schwach. Was mache ich falsch?

Eigentlich nichts. Aber die PWM erzeugt kurze Spikes. Also entweder bei 
OCR0A = 0 die PWM abschalten oder invertierte PWM benutzen.

MfG Spess

von Marcel H. (multiholle)


Lesenswert?

OK, das bekomme ich hin. Wenn 3 PWM-Kanäle brauche, kann ich maximal 
eine Auflösung von 8 Bit verwenden, da nur Timer 1 eine Auflösung von 10 
Bit verwendet. Oder gibt es noch eine andere Möglichkeit auf 10 Bit zu 
kommen?

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.