Atmega88: Fast-PWM-Ausgabe von Non-Inverting auf Inverting umstellen

Gast #6948960
Lesenswert?

Hallo,
ich will auf einem Atmega88 die Fast PWM Ausgabe für OCR0A und OCR0B vom 
Non-Inverting-Mode auf den Inverting Mode umstellen.
Non-Inverting funktioniert einwandfrei.
Zum Umstellen auf Inverting muss WGM02 in Register TCCR0B ja von 0 auf 1 
gesetzt werden.
Das alleine funktioniert aber nicht.
Weiß jemand, was hier noch umgestellt werden muss oder wo der Fehler 
liegen könnte?

Kann auch gerne die anderen Registereinstellungen und Werte posten, wenn 
das weiterhilft.
Gast #6948975
Lesenswert?

1
DDRD |= (1<<PD5) | (1<<PD6);    //OCR0x Pins auf Ausgang
2

3

4
TCNT0 = 255;// PWM-Max.-Wert 
5

6

7
TCCR0A |= (1<< WGM01)|(1<<WGM00);
8
TCCR0B |= (0<< WGM02); // 0 = non-inv. fast PWM; 1 = inv. fast PWM
9
TCCR0B |= (1<< CS00); // prescaler = 1   
10

11
  
12
OCR0A = 99; //Startwert OCR0A
13
OCR0B = 99; //Startwert OCR0B
14

15

16
TCCR0A |= (1<<COM0A1)|(0<<COM0A0); // Einschalten Ausgabe 0A
17
TCCR0A |= (1<<COM0B1)|(0<<COM0B0); // Einschalten Ausgabe 0B

So wie abgebildet funktioniert der Code im Programm im 
Non-Inverting-Fast-PWM-Modus.
Für eine Non-Inverting-Fast-PWM-Ausgabe habe ich Zeile 8 so geändert:
TCCR0B |= (1<< WGM02);

Diese Änderung alleine scheint aber nicht zu reichen, um in den 
Inverting-Fast-PWM-Modus zu kommen.
Gast #6949067
Lesenswert?

Habe es mittlerweile gesehen, COM0A0 und COM0B0 müssen neben WGM02 auch 
auf 1 gesetzt werden:
1
DDRD |= (1<<PD5) | (1<<PD6);    //OCR0x Pins auf Ausgang
2

3
TCNT0 = 254;// PWM-"Max."-Wert 
4

5
TCCR0A |= (1<< WGM01)|(1<<WGM00);
6

7
TCCR0B |= (1<< WGM02); // 0 = non-inv. fast PWM; 1 = inv. fast PWM
8

9
TCCR0B |= (1<< CS00); // prescaler = 1   
10

11
  
12

13
OCR0A = 255; //Startwert OCR0A = Pin auf Lo (kein Nadelpuls)
14

15
OCR0B = 255; //Startwert OCR0B = Pin auf Lo (kein Nadelpuls)
16

17
TCCR0A |= (1<<COM0A1)|(1<<COM0A0); // Einschalten Ausgabe 0A
18

19
TCCR0A |= (1<<COM0B1)|(1<<COM0B0); // Einschalten Ausgabe 0B

Es klappt aber trotzdem nicht so richtig.
Ich möchte den inverting Mode benutzen, um bei OCR0A = 255 bzw. OCR0B = 
255 jeweils auf eine Ausgabespannung von 0 kommen zu können (das geht ja 
im noninverting Modus nicht).
Aber mit den Einstellungen wie hier gezeigt kommt man trotzdem mit 
beiden nicht auf 0 runter.
Die Einstellungen aus Table 15-3 und Table 15-6 sollten aber stimmen.


Weiß jemand, woran das liegt? TCNT0 = 254 müsste doch stimmen.
#6949096
Lesenswert?

Lars L. schrieb:
> jeweils auf eine Ausgabespannung von 0 kommen zu können (das geht ja
> im noninverting Modus nicht)

Hallo, ich mach das so:  Wenn der Ausgang 0 sein soll, setze ich im 
Register TCCR1A COM1A1/COM1B1 und COM1A0/COM1B0 je nach Port auf 0. Ist 
der Ausgabewert nicht 0, setze ich den entsprechenden Wert wieder im 
TCCR1A. Bei der Initialisierung habe ich vorher die beiden Ports auf 
Ausgang und 0 gesetzt. Somit lassen sich Pulslängen von 0 bis 100% 
einstellen. Das funktioniert zumindest beim ATTiny4313 ganz gut.
Gruß Carsten
#6949101
Lesenswert?

Carsten-Peter C. schrieb:
> Hallo, ich mach das so:  Wenn der Ausgang 0 sein soll, setze ich im
> Register TCCR1A COM1A1/COM1B1 und COM1A0/COM1B0 je nach Port auf 0

ja weil es bei Inverting kein 0 gibt

Ich wunderte mich bei Nokia5110 LCD am ESP32 da war die 
Hintergrundbeleuchtung bei einer Displaysorte genau invers zum AVR
Es gab verschiedene Lieferungen und Designs so musste ich auch noch 
verschiedene Wege probieren
Am AVR fing es an Module die 5V tolerant waren!
1
// der Plan aus LED Fading Stufen von 0-100%
2
const uint8_t pwmtable_11C[] PROGMEM = {0, 2, 4, 7, 11, 19, 32, 54, 90, 152, 255};
3

4
//dann kamen die vom anderen Lieferanten für ESP32 3,3V und invers!
5
const uint8_t pwmtable_11C[] PROGMEM = {255, 152, 90, 54, 32, 19, 11, 7, 4, 2, 0};
6

7
// anderer Lieferant anderes Display
8
// hier führte die NULL zu volle Helligkeit deswegen die 1 am Ende
9
const uint8_t pwmtable_11C[] PROGMEM = {255, 253, 251, 248, 244, 236, 223, 201, 164, 103,   1};

nicht perfekt aber mir genügte es!
#6949200
Lesenswert?

Ich habe keinen Atmega88 und kann es nicht prüfen, aber mit dem 
ATtiny13A funktioniert die inverted PWM so dass wenn OCR0A = 255 dann 
bleibt die LED ausgeschaltet.
1
// ATtiny13A inverted PWM test
2

3
#define F_CPU 1200000UL
4
#include <avr/io.h>
5
#include <util/delay.h>
6

7
int main(void)
8
{
9
  DDRB |= (1<<DDB0);                        // set PB0 as output (OC0A)
10
  TCCR0B |= (1<<CS01);                      // set PWM frequency
11
  TCCR0A |= (1 << WGM01) | (1 << WGM00);    // set to Fast PWM Mode
12
  TCCR0A |= (1 << COM0A1) | (1 << COM0A0);  // set OC0A on compare match, clear OC0A at top
13

14
  while(1)
15
  {
16
    OCR0A = 253;
17
    _delay_ms(2000);
18
    OCR0A = 254;
19
    _delay_ms(2000);
20
    OCR0A = 255;            // LED off
21
    _delay_ms(2000);
22
  }
23
}
Gast #6949797
Lesenswert?

Lars L. schrieb:

> Aber mit den Einstellungen wie hier gezeigt kommt man trotzdem mit
> beiden nicht auf 0 runter.

Das ist normal für den FastPWM-Modus. Invertiert kommst du "oben" nicht 
ganz auf VCC, sondern nur auf 255/256 VCC, und im nichtinvertiert kommst 
du "unten" nicht ganz auf 0, sondern nur auf 1/256 VCC.

Das gilt natürlich für die 8Bit-Timer, bei 16Bit-Timern ist es halt 
analog 65535/65536 bzw. 1/65536.

Um wirklich den ganzen Bereich von 0 bis VCC überstreiben zu können, muß 
man für einen der Endwerte den Invertier-Modus wechseln oder man 
verwendet den PhaseCorrect-Modus, der aber wiederum andere Nachteile 
hat.
#6949821
Lesenswert?

c-hater schrieb:
> Das ist normal für den FastPWM-Modus. Invertiert kommst du "oben" nicht
> ganz auf VCC, sondern nur auf 255/256 VCC, und im nichtinvertiert kommst
> du "unten" nicht ganz auf 0, sondern nur auf 1/256 VCC.

wusste ich es doch, mal so mal so, je nach dem wie LED verschaltet sind, 
nach VCC oder nach GND
Das ist sogar bei Module unterschiedlich die gleich aussehen
#6949835
Lesenswert?

DS40002074A:
The extreme values for the OCR0A Register represents special cases when 
generating a PWM waveform output in the fast PWM mode.
If the OCR0A is set equal to BOTTOM, the output will be a narrow spike 
for each MAX+1 timer clock cycle.
Setting the OCR0A equal to MAX will result in a constantly high or low 
output (depending on the polarity of the output set by the COM0A1:0 
bits.)

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