Beliebige PWM Frequenz erzeugen

Doc_Arduino:
wichtige Ergänzung. Alle Register des eigens verwendeten Timer vorher nullen/reseten.

Das Problem sollte man kennen. Aber in diesem Fall kann man wie oben einfach eine Zuweisung machen, da man beide Status Control Register sowieso ändern muss.
Interrupts (TIMSK1) z.B. muss man nicht extra abschalten da diese sowieso deaktiviert sind.

Das Problem hat man eher wenn man irgendwas macht wo man TCCR1A eigentlich nicht braucht und dann nicht bemerkt dass es nicht auf 0 steht

Dass der Pin vielleicht irgendwas komisches beim Umschalten der Modi macht kann man auch verhindern wenn man als letzten Schritt TCCR1A |= _BV(COM1A1) macht. Erst damit schaltet der Timer den Pin hin und her. So wie es oben steht wird erst der Pin aktiviert und sofort danach der Modus umgeschaltet.
Also besser vielleicht so:

void setup()
{
   pinMode(9, OUTPUT);     //Pin auf Ausgang
   ICR1 = 11110;           //TOP = CPU Freq / Prescaler / gewünschte Frequenz - 1
   TCCR1A = _BV(WGM11);  // Mode 14
   TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS11);   //Mode 14, Prescaler = 8
   TCNT1 = 0;
   TCCR1A |= _BV(COM1A1)   //Kanal A nicht-invertierend
}

Erst ab der letzten Zeile sieht man dann was am Ausgang

Die Arduino Software fasst für PWM nur die zwei Status Control Register und die Compare Match Register an. Bei Timer0 kommt noch etwas mehr dazu für millis(). Siehe wiring.c und wiring_analog.c

Eine Frage drängt sich mir noch auf: Zu was brauchst Du ein PWM Signal? Genügt Dir nicht ein Rechtecksignal mit fixem Tastverhältnis? wie zB tone() das liefert?

Grüße Uwe

Ich möchtendamit eine Zumesseinheit ansteuern. Die Zumesseinheit ist Teil einer Regelung. Sprich: Das Tastverhältnis wird nicht konstant bleiben.

Hagi-Hagi:
Ich möchtendamit eine Zumesseinheit ansteuern. Die Zumesseinheit ist Teil einer Regelung. Sprich: Das Tastverhältnis wird nicht konstant bleiben.

Dann wäre Deine Idee von oben (das händisch zu erledigen) doch eigentlich ideal. Die Frequenz ist niedrig genug, um das zu Fuß zu machen. Und wenn Du das Spielen mit endlichem Automat und Klassen drauf hast (oder es lernen möchtest), ist das ein idealer Einstieg, finde ich.

Gruß

Gregor

Hier noch ein anderes Beispiel, das du hier nachlesen kannst:
http://www.gammon.com.au/timers

Mit Timer 2 wird ein PWM-Signal generiert. Das Tastverhältnis (duty cycle) lässt sich im Beispiel mit einem Poti an A0 einstellen.

/* Modulating 180 Hz signal with Timer 2 on D3

   The code below uses Timer 2 to generate
   a 180 Hz pulse using fast PWM mode (mode 15).

   PWM: 180 Hz on Pin D3
  
   It then modulates the duty cycle from 0% to 100% based
   on a figure read from a potentiometer connected to A0.
*/

// Example of modulating a 180 Hz frequency duty cycle
// by reading a potentiometer
// Author: Nick Gammon

const byte POTENTIOMETER = A0;
const byte OUTPUT_PIN    = 3;  // Timer 2 "B" output: OC2B

// Clock frequency divided by prescaler and desired frequency
const long timer2_Setting = F_CPU / 1024L / 180L;


void setup() {
  pinMode (OUTPUT_PIN, OUTPUT);

  // set up Timer 2 - gives us 180 Hz on D3
  TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1);            // fast PWM, clear OC2A on compare
  TCCR2B = bit (WGM22) | bit (CS20) | bit (CS21) | bit (CS22);  // fast PWM, prescaler of 1024
  OCR2A = timer2_Setting;
}


void loop() {
  // OCR2B = ((timer2_Setting + 1) / 2) - 1;  // 50% duty cycle

  // alter Timer 2 duty cycle in accordance with pot reading
  OCR2B = (((long) (analogRead (POTENTIOMETER) + 1) * timer2_Setting) / 1024L) - 1;


  // do other stuff here
}

// http://www.gammon.com.au/forum/?id=11504&reply=7#reply7

Mit Timer 1 ginge das natürlich auch in ähnlicher Weise.

Hallo,
ich habe mir diese Posts (und viele weitere dieses Thema betreffend) mehrmals durchgelesen. Die weiter oben erwähnte Library (Arduino PWM Frequency Library v_05.zip) habe ich auch in meiner IDE installiert. Allerdings verweigert der Compiler seinen Dienst, sobald #include im Sketch verwendet wird: “Exit Status1 Fehler beim compilieren für das Board Arduino/ Genuino Uno”. Meine Vermutung: mit der PWM.h stimmt etwas nicht. denn auch aus der Beispielbibliothek funktioniert der Sketch “PWM_lib_example” mit gleicher Fehlermeldung ebenfalls nicht.
Eine wählbare PWM wäre mir wichtig. Was kann ich tun?

Hi

Eigener Thread - gerne auf Diesen verwiesen - mit kompletter Fehlermeldung und komplettem Sketch.
Dafür vll. auch die Warnungen in den Einstellungen der IDE aktivieren.
Schuss ins Blaue: gibt’s einfach nicht, <PWM.h> müsste Es wenigstens sein.

MfG

PS: Mit Holger85 geht’s Hier weiter.

gregorss:
180 Hz ist eine ziemlich niedrige Frequenz. Ca. 5 ms Laufzeit je loop()-Durchgang sind eher gemächlich.

Gruß

Gregor

Diese Zahlen haben aber erstmal nicht viel miteinander zu tun. Bei 180 Hz PWM muss ja nicht erst nach den 5,5ms etwas passieren, sondern irgendwann innerhalb einer Periode muss auf LOW geschaltet werden. Möchte man z. B. bei 10bit Auflösung das kleinste mögliche Tastverhältnis nutzen, dann muss bereits nach 5 Mikrosekunden wieder ausgeschaltet werden. Dementsprechend muss auch die Loop so schnell sein.

Mahimus:
Diese Zahlen haben aber erstmal nicht viel miteinander zu tun. Bei 180 Hz PWM muss ja nicht erst nach den 5,5ms etwas passieren, sondern irgendwann innerhalb einer Periode muss auf LOW geschaltet werden. Möchte man z. B. bei 10bit Auflösung das kleinste mögliche Tastverhältnis nutzen, dann muss bereits nach 5 Mikrosekunden wieder ausgeschaltet werden. Dementsprechend muss auch die Loop so schnell sein.

Ich kann Deinem Gedankengang nicht so recht folgen.

180 Hz entspricht einer Periodenlänge von etwa 5 ms - das ist wohl unstrittig. Und eine loop()-Laufzeit von 5 ms ist locker erreichbar, auch wenn man eher schlampig programmiert.

Was möchtest Du mir konkret sagen?

Gruß

Gregor

Was möchtest Du mir konkret sagen?

Ihm möchte dich darauf hinweisen, dass deine heiß geliebten 5ms noch in Stücke gehakt werden wollen.
Bei einer 8Bit PWM in 255 Stücke.
Bei einer 10Bit PWM in 1023 Stücke.
Und das bitte möglichst exakt.

combie:
Ihm möchte dich darauf hinweisen, dass deine heiß geliebten 5ms noch in Stücke gehakt werden wollen.
Bei einer 8Bit PWM in 255 Stücke.
Bei einer 10Bit PWM in 1023 Stücke.
Und das bitte möglichst exakt.

Genau, was Combie sagt! Zu Beginn deiner 5ms dauernden Periode schaltest du High und je nach Auflösung musst du dann alle x Mikrosekunden checken, ob die vergangene Zeit schon ausreicht um das gewünschte Tastverhältnis zu erreichen, denn dann muss ausgeschaltet werden. Nach 5ms wird dann schon wieder für die nächste Periode eingeschaltet.

Mahimus:
Genau, was Combie sagt! Zu Beginn deiner 5ms dauernden Periode schaltest du High und je nach Auflösung musst du dann alle x Mikrosekunden checken, ob die vergangene Zeit schon ausreicht um das gewünschte Tastverhältnis zu erreichen, denn dann muss ausgeschaltet werden. Nach 5ms wird dann schon wieder für die nächste Periode eingeschaltet.

Bei 180 Hz PWM mit 8 Bit Auflösung beträgt die Dauer eines 1-zu-255-Pulses gut 20 Mikrosekunden.

Ein loop()-Durchlauf sollte also nicht länger als gut 20 µs sein. Um das zu erreichen muss man kein Magier sein.

Gruß

Gregor

gregorss:
Ein loop()-Durchlauf sollte also nicht länger als gut 20 µs sein.

Jetzt sind wir uns einig.

Warum sollte man die Grenzen der Software ausloten, wenn man nachher für höhere Ansprüche sowieso die eingebaute Hardware nutzen muß?

Einen loop in 20uS? Sportlich, sportlich. Dann darf er aber sonst nix machen. Das im loop ohne irq zu machen, geht nicht mal testweise richtig.

gregorss:
Ein loop()-Durchlauf sollte also nicht länger als gut 20 µs sein. Um das zu erreichen muss man kein Magier sein.

Das wage ich auch mal zu bezweifeln. Oder soll der Sketch sonst nichts wesentliches machen? Und wie hoch sind die Anforderungen an die Exaktheit der PWM-Impulse? Da spuckt ab und zu ja schon der millis-IRQ rein.

Meine Rede. Ich glaube, da hat sich jemand um Faktor 1000 vertan.

Ups, tatsächlich. 20 µs sind arg kurz. Da fehlt 'ne (i.W.: eine) Null.

Aber 5000 loop()-Durchläufe pro Sekunde sind nun wirklich kein Hexenwerk. Mein aktuelles Gebastel, das immerhin eine 7x7-LED-Matrix ansteuert und div. Muster mit 32 Helligkeitsstufen produziert, kommt immerhin auf knapp 2000.

Gruß

Gregor

PS: Mein simpler 35 Bit-Zähler zählt mit knapp 19 kHz

gregorss:
Aber 5000 loop()-Durchläufe pro Sekunde sind nun wirklich kein Hexenwerk.

Na ja, hängt davon ab, was der Arduino machen soll. Und die hier geforderte PWM (180Hz bei 255 Schritten Auflösung ) bekommst Du dann definitiv nicht mehr hin.

MicroBahner:
Na ja, hängt davon ab, was der Arduino machen soll. Und die hier geforderte PWM (180Hz bei 255 Schritten Auflösung ) bekommst Du dann definitiv nicht mehr hin.

Das stimmt. Wobei ich nicht sehe, wo der OP die 8 Bit Auflösung fordert.

Gruß

Gregor