Erhöhen Sie die PWM-Bitauflösung


9

Ich möchte die PWM-Bitauflösung des Arduino Uno erhöhen. In diesem Moment ist es 8-Bit, was ich für zu niedrig halte. Ist dies möglich, ohne die Fähigkeit von Interrupts und Verzögerungen zu verlieren?

Koen

BEARBEITEN Dieses Setup liefert ein 16-Bit-Ergebnis

void setupPWM16() {
    DDRB |= _BV(PB1) | _BV(PB2);        /* set pins as outputs */
    TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                   /* mode 14: fast PWM, TOP=ICR1 */
    TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS11);                    /* prescaler: clock / 8 */
    ICR1 = 0xffff;                      /* TOP counter value (freeing OCR1A*/
}
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> (16000000/8)/(65535+1)=30.5175Hz
*/

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
    switch (pin) {
        case  9: OCR1A = val; break;
        case 10: OCR1B = val; break;
    }
}

Antworten:


15

Der Arduino Uno basiert auf einem ATmega382P-Mikrocontroller. Dieser Chip verfügt über zwei 8-Bit-Timer, die jeweils zwei PWM-Kanäle ansteuern, und einen 16-Bit-Timer, der die letzten beiden Kanäle ansteuert.

Sie können die Auflösung der 8-Bit-Timer nicht erhöhen. Sie können den 16-Bit-Timer jedoch anstelle des von der Arduino-Kernbibliothek verwendeten 8-Bit-Modus in den 16-Bit-Modus versetzen. Dadurch erhalten Sie zwei 16-Bit-PWM-Kanäle mit einer reduzierten Frequenz von 244 Hz (maximal). Sie müssen den Timer wahrscheinlich selbst konfigurieren und profitieren nicht von der benutzerfreundlichen analogWrite()Funktion. Weitere Informationen finden Sie im Abschnitt zu Timer 1 im ATmega328P-Datenblatt .

Update : Hier ist eine Implementierung eines 16-Bit analogWrite(). Dies funktioniert nur an den Pins 9 und 10, da dies die einzigen Pins sind, die mit dem 16-Bit-Timer verbunden sind.

/* Configure digital pins 9 and 10 as 16-bit PWM outputs. */
void setupPWM16() {
    DDRB |= _BV(PB1) | _BV(PB2);        /* set pins as outputs */
    TCCR1A = _BV(COM1A1) | _BV(COM1B1)  /* non-inverting PWM */
        | _BV(WGM11);                   /* mode 14: fast PWM, TOP=ICR1 */
    TCCR1B = _BV(WGM13) | _BV(WGM12)
        | _BV(CS10);                    /* no prescaling */
    ICR1 = 0xffff;                      /* TOP counter value */
}

/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */
void analogWrite16(uint8_t pin, uint16_t val)
{
    switch (pin) {
        case  9: OCR1A = val; break;
        case 10: OCR1B = val; break;
    }
}

Möglicherweise stellen Sie fest, dass der obere Rand der Zählersequenz explizit konfiguriert ist. Sie können diesen Wert auf einen kleineren Wert ändern, um die PWM auf Kosten einer geringeren Auflösung zu beschleunigen.

Und hier ist eine Beispielskizze, die ihre Verwendung veranschaulicht:

void setup() {
    setupPWM16();
}

/* Test: send very slow sawtooth waves. */
void loop() {
    static uint16_t i;
    analogWrite16(9, i);
    analogWrite16(10, 0xffff - i);
    i++;
    delay(1);
}

Wow, vielen Dank, genau das brauche ich. Ich möchte, dass mein PWM-Ergebnis mit meiner Sensorauflösung übereinstimmt. Wenn ich Ihren Code in <siehe meine Bearbeitung ansehen> ändere, wäre das eine 13-Bit-Folge? Wenn ja, wie hoch wäre die Frequenz? Ich werde einen Gleichstrommotor damit fahren, also werden 244 Hz ein bisschen weniger sein, denke ich
KoenR

@KoenR: Nein, der Prescaler hat keinen Einfluss auf die Auflösung. Er dient dazu, die Zählung zu verlangsamen. Wenn Sie den Vorteiler auf 8 einstellen, erhalten Sie eine PWM-Frequenz von 30,5 Hz. Wenn Sie 13 - Bit - Auflösung, Satz ICR1zu 0x1fff, dann wird Ihre Frequenz 1953 Hz (F_CPU / (TOP + 1)) mit einem Vorteiler auf 1
Edgar Bonet

Vielen Dank für die Erklärung. Ich habe meine Frage so bearbeitet, dass sie diese Fehler abdeckt. So können andere Leute es direkt sehen. Danke!
KoenR

1
@ Edgar Bonet Das ist großartig, aber ich kann eine LED scheinbar nicht vollständig ausschalten. Ich benutze ICR1 = 0x03FFund bei 0 sehe ich einen winzigen Impuls auf dem Zielfernrohr, der ausreicht, um die LED zu beleuchten. Irgendwelche Ideen?
Davivid

1
@davivid: Ja, Sie können kein Tastverhältnis von Null haben. analogWrite16(pin, val)ergibt ein Tastverhältnis von (val + 1) / ICR1. Als Workaround analogWrite()tut Arduino's if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);. Aber dann können Sie keinen Arbeitszyklus von 1 / ICR1 bekommen ...
Edgar Bonet

3

Mit etwas Kalibrierung können Sie die Ausgänge von zwei PWM-Kanälen mit unterschiedlichen Gewichtungswiderständen summieren. Im Extremfall könnten Sie einen Ausgang verwenden, um 8 Bit Auflösung bereitzustellen, und den anderen auf 1/256 des Pegels skalieren und hinzufügen, sodass der 2. Kanal ein Bit Reichweite abdeckt und Sie (wieder fiktiv) 16 Bit Auflösung erhalten. Ohne immense Sorgfalt und Anpassung wäre alles, was Sie bekommen würden, ein Chaos.
Durch Teilen des 2. Kanals durch 16 oder 32 können Sie jedoch mehrere zusätzliche Bits PWM-Auflösung hinzufügen. Durch Hinzufügen von 2 gefilterten analogen gefilterten PWM-Kanälen fügen Sie ein zusätzliches Bit hinzu (da der Potentialbereich für unveränderte mV / Bit verdoppelt wird).
Normalerweise (wieder) erhalten Sie für jede zusätzliche Division durch 2 eine zusätzliche Auflösung, die jedoch nur für 4, 5 oder 6 zusätzliche Bits ausgeführt werden kann, wobei die Genauigkeitsanforderungen an Skalierungswiderstände steigen und die Kalibrierung und Fehleranfälligkeit schwieriger wird .

Kurzes Beispiel.
Wenn eine PWM verkleinert wird, um beispielsweise 0 bis 255 mV in einem Schritt von 1 mV zu ergeben, würde das Summieren von zwei PWMs mit gleicher Amplitude einen Bereich von 0 bis 510 mV in Schritten von 1 mV ergeben.
Wenn eine PWM um den Faktor 32 verkleinert wird, werden anstelle des Hinzufügens von 255 mV zum anfänglichen PWM-Bereich nur 8 mV zum oberen Ende hinzugefügt (0,256,32 = 8 mV, aber die Auflösung liegt bei 0,03125 (1/32) ) mV Schritte.

Während dies möglicherweise nur durch Widerstandssummierung und RC-Filterung erreicht werden könnte, würde die Verwendung eines Operationsverstärkersommers die Ergebnisse erheblich verbessern.

Auch die PWM-Welligkeit könnte mit einem einfachen RC-Filter gefiltert werden, aber die Verwendung eines Operationsverstärkers als Puffer (oder sogar nur eines einzelnen Transistors als Emitterfolger) würde Ihnen 3 oder 5 Pole Tiefpassfilterung und eine viel bessere Chance geben, zusätzliche PWM zu erzielen Auflösung. Ich habe die "Phasenkohärenz" der PWM-Ausgänge nicht untersucht, erwarte jedoch, dass sie sich im relativen Gleichschritt bewegen, sodass Sie nicht den Glättungsvorteil erhalten, zwei unkorrelierte Wellenformen hinzuzufügen.

Bei Bedarf können weitere Kommentare abgegeben werden. Fragen Sie bei Interesse.


Das ist klug! Die Mozzi-Soundsynthesebibliothek verwendet diesen Trick anscheinend für den sogenannten „HIFI“ -Modus.
Edgar Bonet

Das ist ein tolles Wir von der PWM. Aber würde dies nicht die Wellenform glätten? Ich frage dies, da Sie einen RC-Filter verwenden. Ich habe dies in meiner Frage nicht erwähnt, aber ich fahre einen Gleichstrommotor damit <schäme mich>. Vielen Dank für die Eingabe!
KoenR

@KoenR (fwiw: Ich sehe nichts, wofür ich mich schämen muss.) Ich weiß nicht, welchen Frequenzgang / welche Änderungsrate Sie in Ihrem ADC-Ausgang wünschen. Oder warum Sie N Bits wollen oder wie groß genug ist. Motoren werden normalerweise nicht sinnvollerweise mit mehr als 8 Bit gesteuert - abhängig von der Präzision einer Anwendung. Der Motor wirkt aufgrund der Induktivität als Teil eines Glättungsfilters. Sie müssen sagen, welche Art von Motor und wie angetrieben. Und ein Schaltplan ist ungefähr wesentlich. Wenn der Motor nicht winzig ist, haben Sie einen Fahrer. Eine PWM mit gebürstetem Motor muss eine Fangdiode haben, um den Motorstrom durchzulassen, wenn die PWM ausgeschaltet ist. Hinzufügen von zwei ...
Russell McMahon

... PWMs sind hier durchaus machbar, aber Schaltungsdetails müssen bekannt sein.
Russell McMahon

In acht nehmen! In einigen Fällen ist es nicht wünschenswert, PWM mit einem Tiefpass-RC zu glätten. Wenn Sie beispielsweise den Arduino-Ausgang in das Gate eines MOSFET einstecken, bleibt der MOSFET kalt, solange er von einer sauberen PWM angesteuert wird. Wenn Sie es jedoch glätten, leitet der MOSFET viel mehr Wärme ab. Manchmal ist das keine gute Sache.
Florin Andrei
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.