3.13. Gerando sinais analógicos com PWM e um filtro RC

O ADC lê tensões em um pino. O oposto – produzir uma tensão intermediária entre 0 V e Vcc em um pino – é mais difícil, porque uma saída GPIO só sabe acionar seus dois trilhos. O substituto padrão é chavear o pino entre os trilhos rápido o suficiente para que a tensão média seja o que importa.

3.13.1. Modulação por largura de pulso

Um sinal modulado por largura de pulso (PWM) é uma onda quadrada de frequência fixa cujo tempo em nível alto – a fração de cada ciclo gasta em Vcc em vez do terra – é definido por software. Essa fração é o ciclo de trabalho (duty cycle). 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 % resulta em uma média de Vcc / 4; um ciclo de trabalho de 50 % em Vcc / 2; um ciclo de trabalho de 75 % em 3 × Vcc / 4.

Três traços de onda quadrada empilhados verticalmente, cada um na mesma frequência. A onda superior fica em nível alto por 25 % de cada período e em nível baixo por 75 %. A onda do meio fica em nível alto e em nível baixo durante metade do período cada. A onda inferior fica em nível alto por 75 % e em nível baixo por 25 %.

PWM com ciclo de trabalho de 25 %, 50 % e 75 %. 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 encapsula um canal de timer de hardware que gera a forma de onda sem ajuda da CPU – uma vez configurado, o sinal continua na frequência e no ciclo de trabalho escolhidos até ser alterado.

3.13.2. A classe machine.PWM

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

from machine import PWM, Pin

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

Isso inicia uma onda quadrada de 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() recebe um inteiro de 16 bits sem sinal que mapeia 0 para “sempre baixo” e 65535 para “sempre alto”. freq() define a frequência da portadora em hertz.

Nota

Cada canal de PWM no mesmo timer de hardware compartilha sua frequência. Chamar freq() em um canal altera todos os outros canais ligados àquele timer. Use canais de timers diferentes quando as saídas precisarem operar em frequências diferentes.

Chame deinit() para liberar o canal do timer quando a saída não for mais necessária.

3.13.3. Calculando a média com um filtro passa-baixas RC

O PWM bruto não é uma tensão suave; é uma onda quadrada cuja média é o que queremos. Para extrair essa média, passe o PWM por um filtro passa-baixas – a mesma combinação de resistor e capacitor usada para o debounce de chaves em Debouncing.

Um pino de PWM conecta-se através de um resistor em série R a um nó de saída. Um capacitor C desse nó ao terra completa o filtro passa-baixas; a tensão suavizada aparece em V_out.

PWM através de um filtro passa-baixas RC: o capacitor calcula a média da onda quadrada, transformando-a em uma tensão DC proporcional ao ciclo de trabalho.

A frequência de corte do filtro – a fronteira entre as frequências que ele deixa passar e as que ele bloqueia – é definida pelo mesmo produto RC que deu a constante de tempo do circuito de debounce:

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 menor que a própria frequência do PWM. A componente DC (frequência 0) passa inalterada; o harmônico fundamental do PWM (na frequência do PWM) é atenuado por aproximadamente f_c / f_PWM. Uma razão de 1 / 200 reduz o ripple residual na saída para cerca de 0.5 % da variação da entrada.

Um ponto de partida razoável para um setpoint que muda lentamente:

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

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

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

Duas observações práticas:

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

  • O capacitor leva cerca de 5 × R × C 8 ms para estabilizar quando o ciclo de trabalho muda; V_out fica atrasado em relação ao ajuste do ciclo de trabalho por esse tempo. Para um setpoint que precise atualizar mais rápido, aumente a frequência de corte (R ou C menores) e aceite mais ripple.