Forum: Mikrocontroller und Digitale Elektronik PWM beim Atmega8


von Thomas L. (tom)


Lesenswert?

Hallo mitsammen. Ich hoffe ich nerve nicht mit meiner Fragerei, aber ich
habe Probleme damit, die 3 PWM Kanäle des Atmega8 zu nutzen.

Was ich bisher habe:
Um die PWM zu nutzen, sind die Bits WGM10, WGM11, WGM12, WGM13
zuständig. Und hier schon die erste Frage:
* Die Bits 10,11 sind im TCCR1A, die Bits 12,13 im TCCR2A. Ich würde
gerne den 8bit - Modus nutzen (0...255), also muss:
WGM10 -> 0
WGM11 -> 1
WGM12 -> 0
WGM13 -> 0
Nur nun meine Frage: Wohin muss ich denn dann den Wert schreiben, mit
welchem verglichen wird - OCR1A?, OCR1B? Das wär dann wohl der erste
PWM Kanal.

Für den 2ten PWM Kanal ist wohl TCCR2 zuständig.
D.h.
WGM20 -> 1
WGM21 -> 0  -> Ebenfalls wieder eine 8bit PWM
Und wieder die Frage - Wohin muss ich den wert schreiben und an welchem
Pin erhalte ich das Ausgangssignal? OCR2?

Und die dritte Frage: WO ist der 3te Kanal? Ein WGM3x finde ich nicht
.. ebensowenig wie ein WGM0x

Ich danke euch für eure Hilfe :)

von Rahul (Gast)


Lesenswert?

Du hast doch gerade 3 PWM-Kanäle aufgezählt:
OCR1A
OCR1B
und
OCR2

Und vermutlich kommen die Vergleichswerte auch in die OC-Register
(output compare register...).

Bei OCR1A und OCR1B wird für beide Timer1 als Zeitbasis genommen.
Für OCR2 ist die Basis Timer2.

von Thomas L. (tom)


Lesenswert?

Oh mein Gott.
Irgendwie muss ich blind gewesen sein :) Mich hat das TCCR1x komplett
irritiert. Heißt das, dass OCR1A und OCR1B immer im gleichen Modus
laufen (Sprich: 8Bit, ..) auch wenn ich nur das TCCR1A/B
dementsprechend nur einmal setze?
Das heisst OC1A, OC1B und OC2 sind meine Ausgänge?

Bin noch recht neu bei der ganzen Sache - Danke mal für deinen Input :)

von bla (Gast)


Lesenswert?

du musst auch noch die COM1Ax und COM1Bx Register setzen - sonst kommt
nix.

Für Phase correct PWM (8,9 oder 10 Bit) würde ich folgendes nehmen:

WGM13: 1 z.B. 8 Bit Phase correct PWM
WGM12: 0
WGM11: 0
WGM10: 0

COM1A1: 1 Ausgabe an OC1A und OC1B
COM1A0: 0 hochzählen:zurücksetzen
COM1B1: 1 runterzählen: setzen
COM1B0: 0

Wenn du dann in OCR1AL "255" reinschreibst bekommst du am Pin
OC1A 5V, bei "0" 0V - an OC1B kannst du OCR1BL ausgeben.

von bla (Gast)


Lesenswert?

die WGM-Werte die du oben beschrieben hast sind nach meinem Datenblatt
für 9-Bit PWM

von Thomas L. (tom)


Lesenswert?

so .. die WGM habe ich geändert. Im Datenblatt des atmega8 muss WGM10 =
1 sein, der Rest = 0 für eine 8bit PWM.

Ich habe jetzt:
---snip---
#include <avr/io.h>
#include <stdint.h>

int main(void)
{
  // Set 8 bit Phase correct PWM Mode for channel 1 + 2(A/B)
  TCCR1A |=  (1 << WGM10);  // 8bit Phase correct CH1
  TCCR1A &= ~(1 << WGM11);  // 8bit Phase correct CH1
  TCCR1B &= ~(1 << WGM12);  // 8bit Phase correct CH2
  TCCR1B &= ~(1 << WGM13);  // 8bit Phase correct CH2

  // Clock select channel 1+2
  TCCR1B |=  (1 << CS10);
  TCCR1B &= ~(1 << CS11);

  // Connect output Pin channel 1
  TCCR1A &= ~(1 << COM1A0);
  TCCR1A |=  (1 << COM1A1);

  // Connect output Pin channel 2
  TCCR1A &= ~(1 << COM1B0);
  TCCR1A |=  (1 << COM1B1);


  // Set 8 bit phase correct PWM Mode for channel 3
  TCCR2 |=  (1 << WGM20);
  TCCR2 &= ~(1 << WGM21);

  // Clock select channel 3
  TCCR2 |= (1 << CS20);
  TCCR2 &= ~(1 << CS21);

  // Connect output Pin channel 3
  TCCR2 &= ~(1 << COM20);
  TCCR2 |= (1 << COM21);


  // Now the values can be put into OCR1A, OCR1B, OCR2
  OCR1AL = 0;
  OCR1BL = 255;
  OCR2 = 126;



  while(1);
}
---snip---

Aber noch immer nix am Pin :(

von The E. (the_engineer)


Lesenswert?

*abo

von Kersten D. (unbenannt-editor)


Lesenswert?

Hi!
Setze mal die entsprechenden Ports als Ausgang....dadrüber bin ich eben
auch gerade gestolpert....

Habe aber auch ein Problem mit atmega8 und PWM: Laut PDF soll er 16 Bit
PWM mit Timer1 können, also 2 PWM-Kanäle (OCR1A und OCR1B) mit je 16 Bit
PWM. Ich bekomme nur 10 Bit PWM hin.

Gruß
Kersten

von Kersten D. (unbenannt-editor)


Lesenswert?

So, bei mir klappts jetzt:

//Pins als Ausgang gesetzt
TCCR1A |= _BV(COM1A1) | _BV(COM1B1); // Eigenschaften der Portpins

TCCR1A |= _BV(WGM11); // 16 Bit Fast PWM, TOP ist ICR1:
TCCR1B |= _BV(WGM12);
TCCR1B |= _BV(WGM13);

ICR1H = 0xFF; //Top = 0xFFFF;
ICR1L = 0xFF; //Normalerweise über ein TEMP-Register schreiben, aber da
der Timer noch nicht läuft sollte das nicht nötig sein

TCCR1B |= _BV(CS10); // kein Prescaler und Timer starten

OCR1A = 0xFFFF; //5V
OCR1B = 0x7FFF; //die Hälfte


@Tom: Was hat es sich denn mit OCR1AL und OCR1AH auf sich? Erscheint
logisch aber steht nirgendwo im Datenblatt. Ich verwende einfach nur
OCR1A/B und es klappt.

Kersten

von Sebastian (Gast)


Lesenswert?

Im Datenblatt steht auf Seite 79, dass man bei den 16 bit Registern erst 
die das high byte beschrieben werden muss, bevor das low byte 
geschrieben wird. Gilt allerdings auch nur bei assembler. Wenn ihr C 
programmiert, macht das der Compiler selbstständig. Deswegen geht das 
auch wenn man direkt OCR1A/B beschreibt.

von Johannes M. (johnny-m)


Lesenswert?

@Sebastian:
Was soll das denn bitteschön wieder? Wenn die das nach zwei Jahren nicht 
rausgefunden haben, nützt es jetzt auch nichts mehr!

von neu-avr (Gast)


Lesenswert?

@Johannes M. (johnny-m)
es gibt immer wieder Menschen denen hilft es trotzdem weiter, egal wie 
alt der Beitrag ist.

@Sebastian: Danke !

Gruß,

von Julian T. (Firma: Stuttgart) (livingevil)


Lesenswert?

Kersten D. schrieb:
> So, bei mir klappts jetzt:
>
> //Pins als Ausgang gesetzt
> TCCR1A |= _BV(COM1A1) | _BV(COM1B1); // Eigenschaften der Portpins
>
> TCCR1A |= _BV(WGM11); // 16 Bit Fast PWM, TOP ist ICR1:
> TCCR1B |= _BV(WGM12);
> TCCR1B |= _BV(WGM13);
>
> ICR1H = 0xFF; //Top = 0xFFFF;
> ICR1L = 0xFF; //Normalerweise über ein TEMP-Register schreiben, aber da
> der Timer noch nicht läuft sollte das nicht nötig sein
>
> TCCR1B |= _BV(CS10); // kein Prescaler und Timer starten
>
> OCR1A = 0xFFFF; //5V
> OCR1B = 0x7FFF; //die Hälfte


Hi,

ich hab nur mittel viel Ahnung: Wenn ich den Code in eine int main(void)
{ } einfüge, müsste doch am Port OC1A bzw. -B eine LED Leuchten, ohne 
dass ich etwas dem Code hinzufügen muss (etwa eine while Schleife) oder 
fehlt da noch etwas?

Danke und sorry, dass ich hier die Totenruhe störe ;)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Julian T. schrieb:
> oder
> fehlt da noch etwas?

Bin jetzt nicht über den ganzen Code gegangen, aber du musst natürlich 
noch die Portpins für OC1A und OC1B auf Ausgang setzen. Das wären beim 
Mega8 PB1 und PB2.

von Chris F. (chfreund) Benutzerseite


Lesenswert?

Habe mir gerade auch den PWM via Timer/Counter im Datenblatt angesehen 
und den Code minimal angepasst, so dass er direkt lauffähig ist. 
Vielleicht hilft es ja jemandem.
An Pin 15/16 sollte je eine LED mit Vorwiderstand, schon geht es los:
1
// Dieses Makro verwende ich nicht mehr, hilft vielleicht den Rest des Threads zu verstehen
2
//#define _BV(a) ((1 << a))
3
// Mein AtMega8 läuft mit 4MHz
4
#define F_CPU 4000000UL
5
// Wartezeit in der Schleife auf 5us
6
#define INTERVALL 5UL
7
// Minimalwert 1000h
8
#define MINVALPWM 0x1000
9
// IO-Makros 
10
#include <avr/io.h>
11
// hier gibt es die tollen delay-Funktionen
12
#include <util/delay.h>
13
14
int main(void)
15
{
16
  DDRB |= (1<<DDB1);  //Pin 15 ist ein Ausgang
17
  DDRB |= (1<<DDB2);  //Pin 16 ist ein Ausgang
18
  /* Im folgenden wird die Pulsweitenmodulation für Timer/Counter1 eingestellt
19
  wir wollen eine schnelle Pulsweitenmodulation, Maximalwert (Top) in ICR1*/
20
  TCCR1A |= (1<<(COM1A1)) | (1<<(COM1B1)); // OC1A und OC1B beim Raufzählen an (bezieht sich auf den internen PWM)
21
  TCCR1A |= (1<<(WGM11)); // Timer/Counter1 Control Register A - Waveform Generator Modus 11 
22
  TCCR1B |= (1<<(WGM12));  // Timer/Counter1 Control Register B - Waveform Generator Modus 12
23
  TCCR1B |= (1<<(WGM13)); // Timer/Counter1 Control Register B - Waveform Generator Modus 13
24
  ICR1 = 0xFFFF;      //ICR1, alle Bits setzen
25
  TCCR1B |= (1<<(CS10)); // kein Prescaler (clkio wird 1:1 vom IC-Takt übernommen), Timer starten
26
  
27
  uint_fast16_t n = MINVALPWM;  // 16-Bit-Variable für die Dimmschleife
28
    while (1) 
29
    {
30
  OCR1A = 0xFFFF;      //5V an Pin 15
31
    for (;n<0xffff;n++)  //von MINVALPWM bis 2^16 raufzählen
32
      {
33
        OCR1B = n;  // Intensität setzen
34
        _delay_us(INTERVALL);  //5us Pause
35
      }
36
  OCR1A = 0;      //0V an Pin 15
37
    for (;n>MINVALPWM;n--)    //von 2^16 bis MINVALPWM runterzählen
38
      {
39
        OCR1B = n;  // Intensität setzen
40
        _delay_us(INTERVALL);  //5us Pause
41
      }
42
    }
43
}

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.