Forum: Mikrocontroller und Digitale Elektronik 2 PWMs AVR Atmega16 (OCR1A,OCR1B)


von Raphael T. (leaf131)


Lesenswert?

Hallo,

Ich habe ein Problem. Ich brauche 2 PWMs um ein Magnetventil 
anzusteuern. So sieht meine Inizialisierung aus:

DDRD=1<<PD4|1<<PD5;  // PWM Pins auf Ausgang

TIMSK=1<<OCIE1A|1<<OCIE1B;

TCCR1A=1<<WGM11|1<<WGM10|1<<COM1A1|1<<COM1B1;
TCCR1B=1<<WGM13|1<<WGM12|1<<CS10;

// Pins: OC1A 0 wenn TCNT1 = OCR1A, OC1B 0 wenn TCNT1 = OCR1B, Fast PWM, 
Clock kein Vorteiler

volatile unsigned char pwmA=75;
volatile unsigned char pwmB=75;

main{
      while(1)
      {
          XXX

          OCR1A=pwmA;
    OCR1B=pwmB;
      }
    }

xxx steht für den restlichen Code der für das Problem aber nicht so 
wichtig ist, da dort nur die Werte von pwmA und B verändert werden.

Ich habe es schon 10 mal überprüft und finde den Fehler nicht, hier im 
Forum konnte ich auch nichts konkretes finden. Der µC den ich verwende 
ist der Atmega16. Ich hoffe Ihr könnt mir helfen. (:

von Stefan E. (sternst)


Lesenswert?

Warum schaltest du die beiden Interrupts ein?
Warum wählst du einen Modus, bei dem OCR1A als TOP genutzt wird?

von Raphael T. (leaf131)


Lesenswert?

Wie meinst du als TOP benutzt?
Sollte ich das TIMSK weglassen?

Ich habe im code noch was vergessen:

SIGNAL(SIG_OUTPUT_COMPARE1A)
{}
SIGNAL(SIG_OUTPUT_COMPARE1B)
{}

von spess53 (Gast)


Lesenswert?

Hi

>Wie meinst du als TOP benutzt?

Du hast PWM-Mode 15 eingestellt. Damit läuft der Timer bis er OCR1A 
(Top) erreicht und fängt bei Null wieder an. OC1A ist damit nicht für 
PWM nutzbar. Entweder du nimmst einen PWM-Mode mit festem Top oder Mode 
14 mit ICR1 als Top. Das Register muss natürlich initialisiert werden.

MfG Spess

von Raphael T. (leaf131)


Lesenswert?

habe den fehler gefunden, hier nun der fertige programmcode als lösung:

#include <avr/io.h>

#define XTAL    16000000L

int main(void)
{
    // OC1A (PD5) und OC1B (PD4) auf Ausgang setzen
    DDRD |= 1<<(PD5) | 1<<(PD4);
    // Clock kein Vorteiler, 8 bit fast pwm
    // Pins: OC1A/OC1B = 0 wenn TCNT1=OCR1A/B
    TCCR1A =  1<<(WGM10) | 1<<(COM1A1) | 1<<(COM1B1);
    TCCR1B = 1<<(CS10) | 1<<(WGM12);

  volatile unsigned int pwmA=75;
  volatile unsigned int pwmB=75;
  volatile unsigned int input=0;

    for (;;)
    {
  OCR1AL=pwmA;
  OCR1BL=pwmB;
    }
}

von spess53 (Gast)


Lesenswert?

Hi

>habe den fehler gefunden, hier nun der fertige programmcode als lösung:

Nicht ganz.

>    for (;;)
>    {
>  OCR1AL=pwmA;
>  OCR1BL=pwmB;
>    }

Es ist nicht sinnvoll, die OC-Register ständig mit Werten zu 
bombardieren. Die weder eh beim Erreichen von Top aktualisiert.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Raphael Tschernitz schrieb:
> habe den fehler gefunden, hier nun der fertige programmcode als lösung:

Wenn du wüsstest, wie oft diese Fragestellung hier auftaucht.
Und dabei ist das so einfach, wenn man erst mal verstanden hat wie PWM 
funktioniert und wie das Zusammenspiel der einzelnen Timer-Register in 
den einzelnen Timer-Modi ist. Im Datenblatt hat Atmel bei der Auflistung 
der Timer-Modi sogar die wesentlichen Register dazugeschrieben und 
trotzdem taucht genau diese Frage in schöner Regelmässigkeit immer 
wieder auf.


PS:  1<<(CS10)
interessante kreative Klammernsetzung

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.