PWM beim Atmega8

OP #311507
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 :)
Gast #311508
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.
OP #311509
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 :)
Gast #311510
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.
OP #311512
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 :(
#311515
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
Gast #790144
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.
(Firma: Stuttgart) #4274752
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 ;)
Persönliche Seite #4522793
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
}

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