Aumenta la risoluzione dei bit PWM


9

Vorrei aumentare la risoluzione dei bit PWM di Arduino Uno. In questo momento è a 8 bit che considero troppo basso. È possibile senza perdere la capacità di interruzioni e ritardi?

Koen

EDIT Questa configurazione fornisce una risoluzione a 16 bit

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;
    }
}

Risposte:


15

Arduino Uno si basa su un microcontrollore ATmega382P. Questo chip ha due timer a 8 bit, che pilotano ciascuno due canali PWM e un timer a 16 bit, che guidano gli ultimi due canali.

Non è possibile aumentare la risoluzione dei timer a 8 bit. Tuttavia, è possibile impostare il timer a 16 bit in modalità 16 bit, invece della modalità a 8 bit utilizzata dalla libreria principale di Arduino. Questo ti darà due canali PWM a 16 bit, con una frequenza ridotta di 244 Hz (massimo). Probabilmente dovrai configurare tu stesso il timer e non trarrai beneficio dalla analogWrite()funzione facile da usare . Per i dettagli, consultare la sezione Timer 1 nella scheda tecnica ATmega328P .

Aggiornamento : ecco un'implementazione di un 16 bit analogWrite(). Funziona solo sui pin 9 e 10, in quanto questi sono gli unici pin collegati al timer a 16 bit.

/* 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;
    }
}

È possibile notare che la parte superiore della sequenza del contatore è configurata in modo esplicito. Puoi cambiarlo in un valore più piccolo per rendere più veloce il PWM, a costo di una risoluzione ridotta.

Ed ecco uno schizzo di esempio che ne illustra l'uso:

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, grazie mille, questo è esattamente ciò di cui ho bisogno. Voglio che la mia risoluzione PWM sia uguale alla mia risoluzione del sensore. Se cambio il tuo codice in <guarda la mia modifica> sarebbe una risoluzione di 13 bit? In tal caso, quale sarebbe la frequenza? Guiderò un motore DC con esso, quindi 244Hz sarà un po 'meno immagino
KoenR

@KoenR: No, il prescaler non ha alcun effetto sulla risoluzione, il suo scopo è rallentare il conteggio. Impostando il prescaler su 8 otterrai una frequenza PWM di 30,5 Hz. Se si desidera una risoluzione di 13 bit, impostare ICR1su 0x1fff, la frequenza sarà 1953 Hz (F_CPU / (TOP + 1)) con un prescaler a 1.
Edgar Bonet,

Grazie per la spiegazione. Ho modificato la mia domanda in modo da coprire questi errori. Quindi altre persone possono vederlo direttamente. Grazie!
KoenR,

1
@Edgar Bonet Questo è fantastico, tuttavia non riesco a spegnere completamente un LED. Sto usando ICR1 = 0x03FFe a 0 vedo un piccolo impulso sull'oscilloscopio abbastanza da illuminare il led. Qualche idea?
davivid

1
@davivid: Sì, non è possibile avere un ciclo di lavoro zero. analogWrite16(pin, val)fornisce un ciclo di funzionamento di (val + 1) / ICR1. Come soluzione alternativa, Arduino lo analogWrite()fa if (val == 0) digitalWrite(pin, LOW); else if (val == 255) digitalWrite(pin, HIGH);. Ma poi non puoi ottenere un ciclo di lavoro di 1 / ICR1 ...
Edgar Bonet

3

Con un po 'di calibrazione è possibile sommare le uscite di due canali PWM con resistori di ponderazione diversi. All'estremo si potrebbe teoricamente usare un'uscita per fornire 8 bit di risoluzione e ridimensionare l'altro a 1/556 ° livello e aggiungerli in modo che il 2 ° canale copra un bit di portata e (di nuovo nozionale) si ottengano 16 bit di risoluzione. Senza un'immensa cura e regolazione tutto ciò che otterresti sarebbe un disastro.
Tuttavia, dividendo il 2o canale per 16 o 32 è possibile aggiungere diversi bit extra di risoluzione PWM. Semplicemente aggiungendo 2 uscite PWM analogiche filtrate si aggiunge un bit in più (poiché la gamma potenziale viene raddoppiata per mV / bit invariati).
Dal punto di vista teorico (di nuovo) per ogni ulteriore divisione per 2 si ottiene un ulteriore bit di risoluzione, ma questo può essere eseguito solo per forse 4 o 5 o 6 bit aggiuntivi, con requisiti di precisione crescenti delle resistenze di ridimensionamento e calibrazione più difficile e propensione agli errori .

Breve esempio.
Se un PWM viene ridimensionato per dire 0 - 255 mV in step di 1 mV, la somma di due PWM con uguale ampiezza darebbe un intervallo di 0 - 510 mV in step di 1 mV.
Se un PWM viene ridimensionato di un fattore 32, invece di aggiungere 255 mV all'intervallo PWM iniziale, aggiungerebbe solo 8 mV all'estremità superiore (0.256.32 = 8 mV, ma la risoluzione sarebbe in 0.03125 (1/32 ) mV passi.

Anche se questo potrebbe essere ottenuto esclusivamente con la somma dei resistori e il filtro RC, l'uso di un'estate dell'amplificatore operazionale migliorerebbe notevolmente i risultati.

Anche l'ondulazione PWM potrebbe essere filtrata con un semplice filtro RC ma l'uso di un opamp come buffer (o anche solo un singolo transistor come follower di un emettitore) ti darebbe 3 o 5 poli di filtro passa basso e possibilità molto migliori di ottenere PWM extra risoluzione. Non ho verificato la "coerenza di fase" delle uscite PWM, ma mi aspetto che si muovano in modo relativo, in modo da non avere il vantaggio di aggiungere due forme d'onda non correlate.

Altri commenti possono essere fatti se necessario. Chiedi se interessati.


Questo è intelligente! Sembra che la libreria di sintesi sonora Mozzi utilizzi questo trucco per la sua cosiddetta modalità "HIFI".
Edgar Bonet,

Questo è un grande noi del PWM. Ma questo non appianerebbe la forma d'onda? Lo sto chiedendo poiché stai usando un filtro RC. Non ho menzionato questo nella mia domanda, ma sto guidando un motore DC con <<vergogna>. Grazie per l'input!
KoenR,

@KoenR (prima della guerra: non vedo nulla di cui vergognarmi.) Non so quale risposta in frequenza / frequenza di cambiamento desideri nell'output ADC. O perché vuoi N bit o quanto è grande. I motori di solito non saranno controllati utilmente da più di 8 bit - dipende dalla precisione di un'applicazione. Il motore agisce come parte di un filtro levigante a causa dell'induttanza. Devi dire che tipo di motore e quanto guidato. E uno schema circuitale è essenziale. A meno che il motore non sia piccolo, hai un driver. Un PWM alimentato da motore spazzolato deve avere un diodo di cattura per far passare la corrente del motore quando PWM è spento. Aggiunta di due ...
Russell McMahon,

... I PWM qui sono fattibili, ma è necessario conoscere i dettagli del circuito.
Russell McMahon,

Attenzione! In alcuni casi, non è auspicabile appianare PWM con un RC passa basso. Ad esempio, se si collega l'uscita Arduino al gate di un MOSFET, il MOSFET rimarrà freddo finché sarà guidato da PWM pulito. Ma se lo appianerai, il MOSFET inizierà a dissipare molto più calore. A volte non è una buona cosa.
Florin Andrei,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.