3.13. Generare segnali analogici con PWM e un filtro RC

L’ADC legge le tensioni su un pin. L’operazione opposta, ovvero produrre su un pin una tensione intermedia tra 0 V e Vcc, è più difficile, perché un’uscita GPIO sa pilotare solo le sue due alimentazioni. Il sostituto standard consiste nel commutare il pin tra le alimentazioni abbastanza velocemente da rendere la tensione media il valore di interesse.

3.13.1. Modulazione di larghezza di impulso

Un segnale modulato in larghezza di impulso (PWM) è un’onda quadra a frequenza fissa il cui tempo di livello alto, cioè la frazione di ogni ciclo trascorsa a Vcc anziché a massa, viene impostato via software. Quella frazione è il duty cycle. La tensione media della forma d’onda è il duty cycle moltiplicato per Vcc:

V_avg = duty × Vcc

Un duty cycle del 25 % dà in media Vcc / 4; un duty cycle del 50 % dà Vcc / 2; un duty cycle del 75 % dà 3 × Vcc / 4.

Tre tracce di onda quadra impilate verticalmente, ciascuna alla stessa frequenza. L'onda in alto è alta per il 25 % di ogni periodo e bassa per il 75 %. L'onda centrale è alta e bassa per metà periodo ciascuna. L'onda in basso è alta per il 75 % e bassa per il 25 %.

PWM con duty cycle del 25 %, 50 % e 75 %. La tensione media segue il duty cycle.

La frequenza viene impostata al momento della configurazione del PWM; il duty cycle è ciò che il software modifica al volo. La classe machine.PWM incapsula un canale di un timer hardware che genera la forma d’onda senza l’intervento della CPU: una volta configurato, il segnale prosegue alla frequenza e al duty cycle scelti finché non vengono modificati.

3.13.2. La classe machine.PWM

Costruisci un’istanza di PWM con il pin e una frequenza e un duty cycle iniziali:

from machine import PWM, Pin

pwm = PWM(Pin("P7"), freq=20_000, duty_u16=32768)

Questo avvia un’onda quadra a 20 kHz con duty cycle del 50 % su P7. Due metodi modificano l’uscita al volo:

pwm.duty_u16(16384)   # change to 25 % (16384 / 65535)
pwm.freq(5_000)       # change to 5 kHz

duty_u16() accetta un intero a 16 bit senza segno che associa 0 a «sempre basso» e 65535 a «sempre alto». freq() imposta la frequenza portante in hertz.

Nota

Tutti i canali PWM sullo stesso timer hardware condividono la frequenza. Chiamare freq() su un canale modifica ogni altro canale collegato a quel timer. Usa canali di timer diversi quando le uscite devono funzionare a frequenze diverse.

Chiama deinit() per rilasciare il canale del timer quando l’uscita non serve più.

3.13.3. Mediazione con un filtro passa-basso RC

Il PWM grezzo non è una tensione regolare; è un’onda quadra la cui media è ciò che ci interessa. Per estrarre quella media, fai passare il PWM attraverso un filtro passa-basso, la stessa combinazione di resistore e condensatore usata per l’antirimbalzo degli interruttori in Debouncing.

Un pin PWM si collega attraverso un resistore in serie R a un nodo di uscita. Un condensatore C da quel nodo a massa completa il filtro passa-basso; la tensione filtrata appare in V_out.

PWM attraverso un filtro passa-basso RC: il condensatore media l’onda quadra in una tensione continua proporzionale al duty cycle.

La frequenza di taglio del filtro, ovvero il confine tra le frequenze che lascia passare e quelle che blocca, è determinata dallo stesso prodotto RC che dava la costante di tempo per il circuito antirimbalzo:

f_c = 1 / (2π × R × C)

Affinché il filtro estragga una tensione continua pulita da un ingresso PWM, la frequenza di taglio deve essere molto più bassa della frequenza PWM stessa. La componente continua (frequenza 0) passa inalterata; la prima armonica del PWM (alla frequenza PWM) viene attenuata di circa f_c / f_PWM. Un rapporto di 1 / 200 riduce l’ondulazione residua all’uscita a circa lo 0.5 % dell’escursione di ingresso.

Un punto di partenza ragionevole per un valore di consegna a variazione lenta:

  • Frequenza PWM f_PWM = 20 kHz, ben al di sopra della banda audio e facile da generare in modo pulito per il timer.

  • Valori del filtro R = 1.6 , C = 1 µF, che danno f_c = 1 / (2π × 1.6 × 1 µF) 100 Hz.

La soppressione di 200× alla portante riduce l’escursione completa del PWM a circa Vcc / 200 di ondulazione residua in V_out, ovvero circa 16 mV a 3,3 V.

Due note pratiche:

  • L’impedenza di uscita del filtro è all’incirca R. Qualsiasi carico a valle che assorbe corrente trasforma R e il carico in un partitore che tira V_out al di sotto della media ideale, esattamente come il partitore nella pagina Leggere segnali analogici con l’ADC. Alimenta un pin ADC o un buffer ad alta impedenza, non un carico che assorbe milliampere.

  • Il condensatore impiega circa 5 × R × C 8 ms ad assestarsi quando il duty cycle cambia; V_out insegue l’impostazione del duty con quel ritardo. Per un valore di consegna che deve aggiornarsi più velocemente, aumenta la frequenza di taglio (R o C più piccoli) e accetta più ondulazione.