Forum: Mikrocontroller und Digitale Elektronik Arduino - PWM an zwei Ausgängen


von Mike C. (bigmike0488)


Lesenswert?

ich versuche nun seit zwei Tagen, jetzt hoffe ich hier Unterstützung zu 
bekommen:
ich benötige an zwei Ausgängen des Arduinos ein ~130Hz PWM-Signal, ich 
verwende in meinem Code D9 und D10. D10 gibt das Signal aus, wie 
gewünscht. D9 gibt nur ein HIGH aus, ohne PWM. hat jemand eine Idee was 
im Code fehlt oder falsch ist?

hier der Code:
1
int interruptNumber = 0;
2
int tasterPin = 2;
3
bool on = 1;
4
5
void setup() {
6
  Serial.begin(9600);
7
  DDRB = 0b00000110;
8
  TCCR1A = 0;
9
  TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1) | _BV(COM1B1);     //Clear OC1A/OC1B on compare match, set OC1A/OC1B at BOTTOM, WGM10, WGM11(Fast-PWM)
10
  TCCR1B = 0;
11
  TCCR1B = _BV(CS12) | _BV(WGM12) | _BV(WGM13);   //CS12 - Prescaler 256; WMG12 & WGM13 für Fast-PWM
12
  OCR1A = 490;    //für benötigte Frequenz von 130Hz
13
  OCR1B = 100;   //duty-cycle
14
  pinMode(tasterPin, INPUT_PULLUP);
15
  attachInterrupt(interruptNumber, interruptfunction, FALLING);   //sollte PWM-Signal zwischen D9 und D10 hin und herschalten
16
}
17
18
void loop() {
19
 OCR1A = map(analogRead(A0), 0, 1023, 0, 490);   //Steuerung von duty-cycle
20
}
21
22
void interruptfunction() {
23
  if (on == 1) {
24
    TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1) | _BV(COM1B1);
25
    on = 0;
26
  }
27
  else {
28
    TCCR1A = _BV(~WGM10) | _BV(~WGM11) | _BV(~COM1A1) | _BV(~COM1B1);
29
    on = 1;
30
  }
31
}

: Bearbeitet durch User
von Timo N. (tnn85)


Lesenswert?

Mike C. schrieb:
> TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1) | _BV(COM1B1);
> //Clear OC1A/OC1B on compare match, set OC1A/OC1B at BOTTOM, WGM10,
> WGM11(Fast-PWM)

Das ist aber //Set OC1A/OC1B on compare match, clear OC1A/OC1B at
BOTTOM (inverting mode)

Mike C. schrieb:
> OCR1A = 490;    //für benötigte Frequenz von 130Hz

Wenn du OCR1A im Mode 15 ( Fast PWM, TOP = OCR1A, Update of OCR1x at 
BOTTOM) einsetz, dann definiert OCR1A deine Frequenz. Richtig.

Mike C. schrieb:
> OCR1A = map(analogRead(A0), 0, 1023, 0, 490);   //Steuerung von
> duty-cycle

Dann kannst du aber vergessen den DutyCycle damit festlegen zu wollen.
Du änderst hier die PWM-Frequenz, nicht den DutyCylce.

Außerdem änderst du praktisch die ganze Zeit die PWM Frequenz (in der 
Loop) und deshalb bleibt OC1A = D9 immer high, weil immer ein Compare 
Match für OCR1A auftritt.

Wenn du Fast PWM nutzen willst und auf D9 und D10 unterschiedliche DC 
ausgeben willst, musst du WGM Mode 14 mit dem ICR1 als Register für die 
Definition der Frequenz verwenden.

von foobar (Gast)


Lesenswert?

> TCCR1A = _BV(~WGM10) | _BV(~WGM11) | _BV(~COM1A1) | _BV(~COM1B1);

Ich bezweifel, dass diese Zeile das tut, was du beabsichtigst - 
_BV(~xxx) ergibt keinen Sinn ...

von PittyJ (Gast)


Lesenswert?

Ich dachte, beim Arduino kann man analogWrite() benutzen, und die 
Bibliothek erledigt den Rest für einen.

https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/

Mit einer LED hat das bei mir auch geklappt.

Warum braucht man also diese Bitschubserei?

von A. Z. (donvido)


Lesenswert?

Mike C. schrieb:
> ich benötige an zwei Ausgängen des Arduinos ein ~130Hz PWM-Signal

PittyJ schrieb:
> Warum braucht man also diese Bitschubserei?

Weil analogWrite keine 130Hz macht.

von Chris K. (Gast)


Lesenswert?

Im richtigen Modus setzt und löscht der Atmel für dich ganz alleine den 
Port Ausgang bei der verwendung von PWM. Dein Code ist also schonmal 
viel komplizierter, als er sein müsste. Ich empfehle mal folgende 2 
Links zu lesen und dabei das augenmerk auf FastPWM zu legen.

https://www.mikrocontroller.net/articles/AVR_PWM
https://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM

von Mike C. (bigmike0488)


Lesenswert?

Timo N. schrieb:
> Wenn du Fast PWM nutzen willst und auf D9 und D10 unterschiedliche DC
> ausgeben willst, musst du WGM Mode 14 mit dem ICR1 als Register für die
> Definition der Frequenz verwenden.

Danke dir Timo, so funktioniert es natürlich, so ist es auch total 
logisch.

int interruptNumber = 0;
int tasterPin = 2;
bool on = 1;

void setup() {
  Serial.begin(9600);
  DDRB = 0b00000110;
  TCCR1A = 0;
  TCCR1A = _BV(WGM11) | _BV(COM1A1) | _BV(COM1B1);
  TCCR1B = 0;
  TCCR1B = _BV(CS12) | _BV(WGM12) | _BV(WGM13);
  ICR1 = 490;
  pinMode(tasterPin, INPUT_PULLUP);
  attachInterrupt(interruptNumber, interruptfunction, FALLING); 
//sollte PWM-Signal zwischen D9 und D10 hin und herschalten
}

void loop() {
  OCR1A = map(analogRead(A0), 0, 1023, 0, 490);   //Steuerung von 
duty-cycle
  OCR1B = OCR1A;
}

void interruptfunction() {
  if (on == 1) {
    TCCR1A = _BV(WGM11) | _BV(COM1A1) | _BV(COM1B1);
    on = 0;
  }
  else {
    TCCR1A = 0;
    on = 1;
  }
  Serial.println(TCCR1A, BIN);
}

von Michael M. (michael89)


Lesenswert?


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.