Forum: Mikrocontroller und Digitale Elektronik ATTiny45 PhaseCorrect PWM auf konstante Frequenz


von Stan K. (krautsalat)


Lesenswert?

Hallo liebe Community,

ich versuche seit einiger Zeit mit Hilfe meines ATTinys die PWM-Einheit 
in Betrieb zu nehmen. Scheinbar übersehe ich eine Kleinigkeit und hoffe 
da einwenig auf eure Hilfe.

Mein Ziel ist es ein PWM-Signal mit der Frequenz von 48KHz zu erzeugen, 
dh eine Periode von ca. 21µs. Bis das aber klappt mache ich Versuche um 
mich von der korrekten Funktionalität des µC zu überzeugen, daher die 
sehr großen Werte:
1
void vConfPWM()
2
{
3
  TCCR0A = _BV(WGM00)|_BV(COM0A1); //Phase Correct PWM //Output on PB0
4
  TCCR0B = _BV(CS02)|_BV(CS00)|_BV(WGM02); //Maxinmum Prescaler: 1024 
5
  OCR0A = 255; //Counter counts to maximum
6
}

Mein Programm überwacht den PIN PB0 und gibt den Status über eine 
Soft-UART Schnittstelle an PB4 in Abhängigkeit vom Timer0.
1
int main (void)
2
{
3
    DDRB |= (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB4); //Output
4
    DDRB &= ~(1<<PB3);//PB3 als Input
5
    sei();
6
    vConfPWM();
7
    //die komplette main poste ich nach Bedarf. Will niemanden erschlagen...
8
}

Die Ausgabe macht deutlich, dass der PIN PB0 seinen Wert nicht 
verändert, obwohl er sollte. Dies ist mein Problem.
1
00255  <OCR0A & TCNT0> 00100 ->00108 ->00117 ->PINB 00017 
2
00255  <OCR0A & TCNT0> 00166 ->00157 ->00149 ->PINB 00017 
3
00255  <OCR0A & TCNT0> 00079 ->00087 ->00095 ->PINB 00017 
4
00255  <OCR0A & TCNT0> 00187 ->00179 ->00170 ->PINB 00017 
5
00255  <OCR0A & TCNT0> 00057 ->00066 ->00074 ->PINB 00017  
6
...

Man sieht an der Konsolenausgabe, dass obwohl der Counter hoch oder 
runterzählt, die LED an PB0 konstant leuchtend bleibt. Der andere 
gesetzte PIN ist hier PB4, denn dieser überträgt den Software-UART mit 
dem diese Daten auf meinen PC kommen ;-).

Zum Vergleich. Ich schalte das fast PWM an:
1
void vConfPWM()
2
{
3
  TCCR0A = _BV(WGM00)|_BV(WGM01)|_BV(COM0A1); //Fast PWM //Output PB0
4
  TCCR0B = _BV(CS02)|_BV(CS00); //Maxinmum Prescaler: 1024 
5
  OCR0A = 127; //Counter counts to half
6
}

Hier sieht man das Toggeln ganz deutlich...
1
00127  <OCR0A & TCNT0> 00118 ->00127 ->00135 ->PINB 00016 
2
00127  <OCR0A & TCNT0> 00013 ->00021 ->00029 ->PINB 00017 
3
00127  <OCR0A & TCNT0> 00163 ->00171 ->00180 ->PINB 00016 
4
00127  <OCR0A & TCNT0> 00057 ->00066 ->00074 ->PINB 00017 
5
00127  <OCR0A & TCNT0> 00208 ->00216 ->00224 ->PINB 00016

Was mache ich falsch? Habe ich evtl. ein altes Exemplar erwischt und 
diese im Datenblatt beschriebene Funktionalität ist noch nicht drin?

von Einer K. (Gast)


Lesenswert?

Stan K. schrieb:
> Hier sieht man das Toggeln ganz deutlich...
Du vielleicht....
Für mich ist das eine Horde Krähenfüße.

Stan K. schrieb:
> OCR0A = 255; //Counter counts to maximum
Der Kommentar ist falsch!
Und, mich wundert nicht, dass aus dem Pin nix raus kommt.

Stan K. schrieb:
> OCR0A = 127; //Counter counts to half
Auch hier ist der Kommentar falsch.
Aber immerhin kommt aus dem Pin eine 50%ige PWM

?
Oder habe ich was übersehen?

von Stan K. (krautsalat)


Lesenswert?

Wow, ich habe an diesem Beitrag nichts konstruktives und hilfreiches 
gefunden. Im Gegenzug viele Bemerkungen auf persönlicher Ebene die auch 
falsch sind, da durch keine Quelle gestützt. Ich wünsche mir einen 
respektvollen Umgang Ufuf.

von Peter D. (peda)


Lesenswert?

In Mode 5 ist TOP = OCR0A, d.h. als PWM kannst Du dann nur noch OC0B = 
PB1 benutzen.

von Eberhard H. (sepic) Benutzerseite


Lesenswert?

Stan K. schrieb:
> Mein Ziel ist es ein PWM-Signal mit der Frequenz von 48KHz zu erzeugen,
> dh eine Periode von ca. 21µs.

Zunächst würde ich die tatsächliche PWM am Pin per Scope anschauen und 
nicht per Software scannen, selbst wenn sie für Versuche erst einmal 
relativ langsam ist.

Dann musst du dir bewusst sein, dass 48 kHz im Phase-Correct-PWM-Mode 
nicht ganz einfach werden, denn die CPU müsste dann bei einem 
Prescale-Faktor von 1 und bei 8 Bit Auflösung mit 510 * 48 kHz = 24,48 
MHz takten. Das wird mit einem 8-Bit-AVR eher nichts  ...

Es geht jedoch ziemlich entspannt im Fast-PWM-Mode, indem man per OCR0A 
die Periode und per OCR0B das Tastverhältnis erzeugt, das sich dann zu 
(OCR0B+1)/(OCR0A+1) ergibt.

Der PWM-Ausgang ist dann OC0B.

Der einzige Wermutstropfen ist, dass man den PWM-Ausgang bei 0% 
Tastverhältnis (falls gewünscht) per Software abschalten muss.

Wie soll das Tastverhältnis denn eingestellt werden? Per Poti? Per 
serieller Schnittstelle? Oder per sonst etwas?

Wie groß soll die Auflösung und wie genau müssen die 48 kHz sein bzw. 
was wird damit angesteuert?

von S. Landolt (Gast)


Lesenswert?

> ... 24,48 MHz takten. Das wird mit einem 8-Bit-AVR eher nichts  ...

Es geht um einen ATtiny45, dieser kann mit PLL 64 MHz für Timer1.

von Stan K. (krautsalat)


Lesenswert?

Abschließend möchte ich hier eine Lösung meines Problems posten, so dass 
dieser Thread ordentlich geschlossen werden kann. Ich erhalte meine 
Frequenz von ca. 48kHz indem ich den Prescaler auf 8 Setze und den 
inneren Schwingkreis des ATTiny45 auf die Frequenz von 8MHz setze.
Zusätzlich wird das Register OCR0A dafür verwendet den Timer0 bis auf 22 
hochzählen zu lassen. Das ist in etwa die Periodendauer. Als Output 
verwende ich den PIN PB1. Im Modus Fast PWM ist die Benutzung des Pins 
PB0 nicht sinnvoll, da OCR0A als TOP-Wert verwendet wird. Dies hatte ich 
bis dahin nicht verstanden, da lag ich im Irrtum.
1
  TCCR0A = _BV(WGM00)|_BV(WGM01)|_BV(COM0B1); //Fast PWM //Output on PB0
2
  TCCR0B = _BV(CS00)|_BV(WGM02); //Prescaler: 8 //Fast PWM
3
  OCR0A = 22; //Counter counts to maximum
4
  OCR0B = OCR0A/2;

Wie funktioniert das jetzt? Ich versuche es als ASCII-Darstellung.
1
+---------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
2
|TCNT0    |  0  |  1  |  2  | ... |  10 |  11 | ... |  21 |  22 |  0  |  
3
+---------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
4
|OCR0A/TOP|     |     |     |     |     |     |     |     |  X  |     |
5
+---------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
6
|OCR0B    |     |     |     |     |     |  X  |     |     |     |     |
7
+---------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
8
|PB1/OC0B |  0  |  0  |  0  |  0  |  0  |  1  |  1  |  1  |  1  |     |
9
+---------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
X=Match (OCROA bewirkt beim Match, dass TCNT0 von 0 an zählt. OCR0B 
bewirkt, dass PB1 getoggelt wird.)

Zur UART-Ausgabe: Man kann natürlich mit einem Oszilloskop eine 
zuverlässigere Ausgabe erwirken, nur leider sieht man dies nicht in 
Relation zum Register TCNT0. Mir ist aber schon bewusst, dass das 
Register PINB etwas träge ist...

Meine Infrarotübertragung funktioniert jetzt, ich habe dafür erstmal den 
Soft-UART benutzt.

von Karl M. (Gast)


Lesenswert?

Stan K. schrieb:
> OCR0A = 22; //Counter counts to maximum
>   OCR0B = OCR0A/2;

Da hast Du dann geraten !

Im Datenblatt steht eine Formel:
MAX-Counter = F_CPU  Prescaler  Frequenzy

In das TOP-Register lädt man dann den Wert (MAX-Counter -1)
Wir rechnen:
MAX-Counter = 8*10^6  8  48*10^3 = Trunc(20,833 +0,5)

Somit ist MAX-Counter = 21
In das TOP-Register schreibt man dann (21-1)

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.