Stellen Sie die PWM-Frequenz auf 25 kHz ein

11

Ich kann derzeit vier PWM-Pins mit dem folgenden Code auf ungefähr 31 kHz einstellen:

void setup()
{
    TCCR1B = TCCR1B & B11111000 | B00000001; // Set PWM frequency for D9 & D10:
    pinMode(pwmPin9, OUTPUT); // Sets the pin as output
    pinMode(pwmPin10, OUTPUT); // Sets the pin as output


    TCCR2B = TCCR2B & B11111000 | B00000001; // Set PWM for D3 & D11
    pinMode(pwmPin3, OUTPUT); // Sets the pin as output
    pinMode(pwmPin11, OUTPUT); // Sets the pin as output
}

Ich habe dieses Setup irgendwo gefunden, weiß aber nicht, wie ich diese vier PWM-Pins stattdessen auf etwa 25 kHz einstellen kann. Wie ist das möglich?

user16307
quelle
3
Verstehst du, wie die AVR-Timer funktionieren?
Ignacio Vazquez-Abrams
3
Siehe meine Seite über Timer .
Nick Gammon
1
@ IgnacioVazquez-Abrams Ich bin nicht vertraut und ich muss diese vier Pins am Anfang auf ungefähr 25 kHz setzen. Ich habe es eilig, ein Projekt abzuschließen und würde mich über jede Hilfe freuen. Der Code, den ich habe, ist auf 31 kHz eingestellt. Kann ich es auf 25 kHz ändern? Gleichstrommotoren erfordern, dass Freq.
user16307
1
@ NickGammon Danke, aber ich habe im Moment wirklich nicht genug Zeit, um diese zu studieren. Könnten Sie mir den Codeteil zum Einrichten von 25 kHz zur Verfügung stellen?
Ich bin
2
Ich muss ihre genaue Drehzahl einstellen, damit sich ihre Arbeitszyklen geringfügig unterscheiden. Wie wäre es, wenn 2 Pins nur auf 25 kHz eingestellt werden könnten?
user16307

Antworten:

10

Ich poste diese zweite Antwort, da mir klar wurde, dass es möglich ist, 4 PWM-Kanäle bei 25 kHz mit 161 Schritten auf einem einzelnen Arduino Uno zu haben. Dies beinhaltet das Ändern der Haupttaktfrequenz auf 8 MHz , was einige Nebenwirkungen hat, da das gesamte Programm halb so schnell läuft. Es beinhaltet auch die drei Zeitgeber neu zu konfigurieren, das heißt , die Zeitfunktionen Arduino verlieren ( millis(), micros(), delay()und delayMicroseconds()). Wenn diese Kompromisse akzeptabel sind, gehen Sie wie folgt vor:

void setup()
{
    // Set the main system clock to 8 MHz.
    noInterrupts();
    CLKPR = _BV(CLKPCE);  // enable change of the clock prescaler
    CLKPR = _BV(CLKPS0);  // divide frequency by 2
    interrupts();

    // Configure Timer 0 for phase correct PWM @ 25 kHz.
    TCCR0A = 0;           // undo the configuration done by...
    TCCR0B = 0;           // ...the Arduino core library
    TCNT0  = 0;           // reset timer
    TCCR0A = _BV(COM0B1)  // non-inverted PWM on ch. B
        | _BV(WGM00);  // mode 5: ph. correct PWM, TOP = OCR0A
    TCCR0B = _BV(WGM02)   // ditto
        | _BV(CS00);   // prescaler = 1
    OCR0A  = 160;         // TOP = 160

    // Same for Timer 1.
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
        | _BV(COM1B1)  // same on ch. B
        | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
        | _BV(CS10);   // prescaler = 1
    ICR1   = 160;

    // Same for Timer 2.
    TCCR2A = 0;
    TCCR2B = 0;
    TCNT2  = 0;
    TCCR2A = _BV(COM2B1)  // non-inverted PWM on ch. B
        | _BV(WGM20);  // mode 5: ph. correct PWM, TOP = OCR2A
    TCCR2B = _BV(WGM22)   // ditto
        | _BV(CS20);   // prescaler = 1
    OCR2A  = 160;
}

void loop()
{
    analogWrite( 3,   1);  // duty cycle = 1/160
    analogWrite( 5,  53);  // ~ 1/3
    analogWrite( 9, 107);  // ~ 2/3
    analogWrite(10, 159);  // 159/160
}

Im Gegensatz zur anderen Antwort ist hierfür keine modifizierte Version erforderlich analogWrite(): Die Standardversion funktioniert einwandfrei. Es ist nur darauf zu achten, dass:

  1. Der geschriebene Wert sollte zwischen 0 (dh immer LOW) und 160 (immer HIGH) einschließlich liegen.
  2. Es sind nur die Pins 3, 5, 9 und 10 verfügbar. Der Versuch, analogWrite() die Pins 6 oder 11 zu erreichen, liefert nicht nur keinen PWM-Ausgang, sondern ändert auch die Frequenz an Pin 5 bzw. 3.
Edgar Bonet
quelle
Es ist schon sehr lange her und jetzt bin ich mit Arduino Due, das einen anderen Prozessor verwendet, bei der gleichen Sache festgefahren. Ich würde mich freuen, wenn Sie hier eine Eingabe haben arduino.stackexchange.com/questions/67053/…
user16307
10

Sie können Timer 1 so konfigurieren, dass er im phasenkorrekten PWM-Modus mit 25 kHz läuft, und die beiden Ausgänge an den Pins 9 und 10 wie folgt verwenden:

// PWM output @ 25 kHz, only on pins 9 and 10.
// Output value should be between 0 and 320, inclusive.
void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
            break;
    }
}

void setup()
{
    // Configure Timer 1 for PWM @ 25 kHz.
    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 320;         // TOP = 320

    // Set the PWM pins as output.
    pinMode( 9, OUTPUT);
    pinMode(10, OUTPUT);
}

void loop()
{
    // Just an example:
    analogWrite25k( 9, 110);
    analogWrite25k(10, 210);
    for (;;) ;  // infinite loop
}

Wenn Sie einen Wert von 0 mit schreiben analogWrite25k(), ist der Pin immer LOW, während 320 immer HIGH bedeutet. Der Regular analogWrite() sollte fast funktionieren, aber er interpretiert 255 genauso wie 320 (dh immer HIGH).

Dieser Code setzt ein Arduino Uno oder ein ähnliches Board (ATmega168 oder 328 @ 16 MHz) voraus. Die hier verwendete Methode erfordert einen 16-Bit-Timer und verwendet daher Timer 1, da dies der einzige auf dem Uno verfügbare ist. Deshalb stehen nur zwei Ausgänge zur Verfügung. Das Verfahren könnte mit einem 16-Bit-Timer an andere AVR-basierte Karten angepasst werden. Wie Gerben bemerkte, sollte dieser Timer ein entsprechendes ICRx-Register haben. Auf dem Arduino Mega gibt es 4 solcher Timer mit jeweils 3 Ausgängen.

Edgar Bonet
quelle
1
Es kann nützlich sein zu erklären, dass diese Methode nur für timer1 funktioniert, da die anderen Timer kein ICRxRegister haben. Sie können höchstens einen PWM-Pin pro Timer für die Timer 0 und 2 haben.
Gerben
1
@Gerben: Haben nicht alle 16-Bit-Timer dieses Register? Zumindest auf der Mega tun sie das.
Edgar Bonet
1
Ja, aber nur timer1 ist 16-Bit auf dem ATMega328. Der Rest ist 8-Bit. Und das OP möchte 4 PWM-Ausgang, und Ihre Lösung bietet nur 2. Oder irre ich mich?
Gerben
1
@ Gerben: Nein, du hast recht. Ich sage nur, dass das Erfordernis von ICRx redundant zu sein scheint, wenn der Timer 16-Bit sein muss. Zumindest für Uno und Mega, nicht sicher über andere AVR-basierte Arduinos. Das OP versteht, dass dies nur 2 PWM-Kanäle bietet: siehe meinen Kommentar zu seiner Frage und seiner Antwort.
Edgar Bonet
2
@techniche: 1. Funktioniert für mich. Vielleicht haben Sie vergessen zu setzen COM4C1in TCCR4A? 2. Wenn dies nicht das Problem ist, lesen Sie Wie stelle ich eine gute Frage? Aktualisieren Sie dann Ihre Frage, indem Sie Ihren vollständigen Quellcode einfügen und klar angeben, was Sie von dem Programm erwarten und was es stattdessen tut („Ich sehe keinen Erfolg“ wird nicht als gültige Problemstellung angesehen).
Edgar Bonet