Atmega 168 Hardware-PWM

OP #1965684
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
}
#1965686
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
OP #1965690
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?
#1965691
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)
Gast #1965692
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren