3.13. Geração de sinal analógico com PWM e um filtro RC

O ADC lê tensões num pino. O oposto – produzir uma tensão intermédia entre 0 V e Vcc num pino – é mais difícil, porque uma saída GPIO apenas sabe como conduzir os seus dois rails. A substituição padrão é comutar o pino entre os rails suficientemente rápido para que a tensão média seja o que nos interessa.

3.13.1. Modulação por largura de impulso

Um sinal modulado por largura de impulso (PWM) é uma onda quadrada a uma frequência fixa cujo tempo em alto – a fração de cada ciclo passada em Vcc em vez de massa – é definida em software. Essa fração é o ciclo de trabalho. A tensão média da forma de onda é o ciclo de trabalho multiplicado por Vcc:

V_avg = duty × Vcc

Um ciclo de trabalho de 25 % tem uma média de Vcc / 4; um ciclo de trabalho de 50 % de Vcc / 2; um ciclo de trabalho de 75 % de 3 × Vcc / 4.

Three square-wave traces stacked vertically, each at the same frequency. The top wave is high for 25 % of each period and low for 75 %. The middle wave is high and low for half the period each. The bottom wave is high for 75 % and low for 25 %.

PWM a 25 %, 50 % e 75 % de ciclo de trabalho. A tensão média acompanha o ciclo de trabalho.

A frequência é definida quando o PWM é configurado; o ciclo de trabalho é o que o software altera em tempo real. A classe machine.PWM envolve um canal de temporizador de hardware que gera a forma de onda sem intervenção do CPU – uma vez configurado, o sinal continua à frequência e ciclo de trabalho escolhidos até ser alterado.

3.13.2. A classe machine.PWM

Construa uma instância PWM com o pino e uma frequência e ciclo de trabalho iniciais:

from machine import PWM, Pin

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

Isto inicia uma onda quadrada a 20 kHz com 50 % de ciclo de trabalho em P7. Dois métodos alteram a saída em tempo real:

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

duty_u16() aceita um número inteiro sem sinal de 16 bits mapeando 0 para «sempre em baixo» e 65535 para «sempre em alto». freq() define a frequência portadora em hertz.

Nota

Todos os canais PWM no mesmo temporizador de hardware partilham a sua frequência. Chamar freq() num canal altera todos os outros canais ligados a esse temporizador. Use canais de temporizadores diferentes quando as saídas precisam de funcionar a frequências diferentes.

Chame deinit() para libertar o canal do temporizador quando a saída já não for necessária.

3.13.3. Suavização com um filtro passa-baixo RC

O PWM em bruto não é uma tensão suave; é uma onda quadrada cuja média é o que pretendemos. Para extrair essa média, passe o PWM por um filtro passa-baixo – a mesma combinação de resistor e condensador usada para eliminar a rejeição de contacto em Eliminação de ressalto.

A PWM pin connects through a series resistor R to an output node. A capacitor C from that node to ground completes the low-pass filter; the smoothed voltage appears at V_out.

PWM através de um filtro passa-baixo RC: o condensador suaviza a onda quadrada numa tensão DC proporcional ao ciclo de trabalho.

A frequência de corte do filtro – o limite entre as frequências que este deixa passar e as que bloqueia – é definida pelo mesmo produto RC que deu a constante de tempo para o circuito de eliminação de rejeição de contacto:

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

Para que o filtro extraia uma tensão DC limpa de uma entrada PWM, a frequência de corte deve ser muito inferior à própria frequência PWM. A componente DC (frequência 0) passa sem alterações; o harmónico fundamental do PWM (à frequência PWM) é atenuado por aproximadamente f_c / f_PWM. Um rácio de 1 / 200 reduz o ripple residual na saída para cerca de 0.5 % da excursão de entrada.

Um ponto de partida razoável para um ponto de ajuste de variação lenta:

  • Frequência PWM f_PWM = 20 kHz – bem acima do áudio, e fácil de gerar de forma limpa pelo temporizador.

  • Valores do filtro R = 1.6 , C = 1 µF – dando f_c = 1 / (2π × 1.6 × 1 µF) 100 Hz.

A supressão de 200× na portadora reduz a excursão total do PWM para aproximadamente Vcc / 200 de ripple residual em V_out – cerca de 16 mV a 3,3 V.

Duas notas práticas:

  • A impedância de saída do filtro é aproximadamente R. Qualquer carga a jusante que drene corrente transforma R e a carga num divisor que puxa V_out abaixo da média ideal, exatamente como o divisor na página Leitura analógica com o ADC. Alimente um pino ADC ou um buffer de alta impedância, não uma carga que absorva miliamperes.

  • O condensador demora cerca de 5 × R × C 8 ms a estabilizar quando o ciclo de trabalho muda; V_out atrasa o valor de ciclo de trabalho definido por esse tempo. Para um ponto de ajuste que precise de atualizar mais rapidamente, aumente a frequência de corte (R ou C menor) e aceite mais ripple.