3.12. Leitura analógica com o ADC

Até agora, a câmara tem lido sinais digitais – um pino está em 0 ou 1, um interruptor está aberto ou fechado. A maioria dos sinais provenientes de sensores do mundo real são analógicos: uma tensão contínua que varia suavemente ao longo de um intervalo. Um fotorresistor percorre todas as tensões entre os dois rails à medida que a luminosidade ambiente se altera. A saída de um sensor de temperatura deriva alguns milivolts quando uma sala aquece. A saída de um microfone sobe e desce com o som ao seu redor.

Um conversor analógico-digital (ADC) é a ponte. Amostra a tensão num pino e devolve um número inteiro que o Python pode ler como qualquer outro valor.

3.12.1. Quantização

Um valor digital não pode representar uma tensão contínua com exatidão. A função do ADC é quantizar – encaixar cada amostra no nível mais próximo de um conjunto fixo de níveis. Um ADC de N bits tem 2^N níveis; um conversor de 12 bits tem 4096 deles distribuídos pelo intervalo de entrada.

A smooth analog curve plotted against time, overlaid with a stepped digital approximation. Dashed horizontal lines mark the quantization levels; the stepped curve snaps to whichever level is nearest the analog signal at each sample point.

Quantização: cada amostra do sinal analógico (linha contínua) é arredondada para um de um conjunto finito de níveis digitais (linha a tracejado em degraus).

A tensão entre dois níveis adjacentes é o tamanho do passo do ADC; qualquer coisa menor que isso desaparece no arredondamento. Um ADC de 12 bits com um intervalo de 3,3 V tem um tamanho de passo de aproximadamente 3.3 / 4096 0.8 mV – suficientemente fino para que a maioria dos sinais pareça efetivamente contínua em software.

3.12.2. A classe machine.ADC

machine.ADC envolve um canal de entrada analógica. Construa-o com o pino que pretende ler e, em seguida, chame read_u16():

from machine import ADC

adc = ADC("P6")
value = adc.read_u16()
print(value)

read_u16() devolve sempre um número inteiro sem sinal de 16 bits entre 0 e 65535. A resolução nativa do ADC varia consoante a placa (12 bits no STM32, específico da porta noutros casos); o resultado é alinhado à esquerda em 16 bits para que o detalhe de hardware não transvase para o Python – um valor de 65535 corresponde à escala máxima independentemente do chip.

A tensão de referência – a entrada que corresponde à escala máxima – depende da placa. Consulte o Placas OpenMV para o valor na sua câmara. Qualquer valor acima da referência lê como escala máxima (e pode danificar o pino se exceder a tensão máxima de entrada absoluta).

3.12.2.1. Converter contagens em tensão

O mapeamento de contagens para tensão é linear, com as contagens de escala máxima a corresponder exatamente a Vref:

voltage = counts × Vref / 65535

Em código:

VREF = 3.3  # cam-dependent; see the quickref
counts = adc.read_u16()
voltage = counts * VREF / 65535
print(voltage, "V")

3.12.3. Divisores de tensão

Dois resistores em série entre um rail de tensão e massa formam um divisor de tensão. O nó entre eles fica a uma tensão definida pelo rácio dos dois resistores:

A voltage divider. Vin at the top connects through R1 to a node tapped off as V_out, which then connects through R2 to ground.

Um divisor de tensão: R1 e R2 em série reduzem Vin para V_out.

V_out = Vin × R2 / (R1 + R2)

Resistores iguais dão metade da tensão do rail; R2 muito menor que R1 coloca o ponto de derivação próximo da massa; R2 muito maior coloca-o próximo do rail.

A fórmula pressupõe que mais nada drena corrente apreciável de V_out. Um pino ADC tem alta impedância (megaohms, nanoamperes) e satisfaz facilmente essa condição, pelo que um divisor a alimentar um ADC comporta-se conforme a fórmula prevê.

3.12.4. Potenciómetros

Um potenciómetro é um componente físico único que é exatamente um divisor de tensão, com um cursor deslizante que move o ponto de derivação entre as duas extremidades. Rodar o botão altera R1 e R2 em conjunto, mantendo a sua soma (a resistência total do pot) constante.

A potentiometer wired between 3.3 V and ground. The wiper is tapped off to an ADC pin.

Um potenciómetro ligado como fonte de tensão manual para o ADC: 3,3 V numa extremidade, massa na outra, cursor para o pino.

Um potenciómetro é o dispositivo de entrada canónico para experimentar o ADC. Ligue uma extremidade a 3.3 V, a outra à massa e o cursor a um pino com capacidade ADC; rodar o botão faz o cursor percorrer todas as tensões entre os rails.

import time
from machine import ADC

pot = ADC("P6")
VREF = 3.3

while True:
    counts = pot.read_u16()
    voltage = counts * VREF / 65535
    print(voltage, "V")
    time.sleep_ms(100)

3.12.5. Ler tensões mais altas com um divisor

Uma tensão acima de Vref fará o ADC atingir a escala máxima e pode danificar a entrada se exceder o valor máximo absoluto. Para ler uma fonte mais alta – uma bateria, uma saída de sensor que excede Vref – reduza-a com um divisor de tensão fixo antes de chegar ao pino:

A voltage divider scaling a high V_in down to an ADC pin. R1 runs from V_in down to a junction, which is tapped off horizontally to the ADC pin; R2 continues from the junction down to ground.

Redução de uma fonte de alta tensão para o ADC: R1 e R2 formam um divisor de tensão fixo cujo ponto de derivação alimenta o pino ADC.

Escolha R1 e R2 de modo a que a tensão dividida se mantenha dentro do intervalo do ADC à tensão de entrada mais alta que espera:

V_adc = V_in × R2 / (R1 + R2)

Para um V_in = 12 V máximo e uma referência de 3,3 V, o rácio R2 / (R1 + R2) deve ser no máximo 3.3 / 12 0.275. Uma escolha comum com alguma margem de segurança é R1 = 33 , R2 = 10 . O rácio é 10 / 43 0.233, pelo que V_adc atinge o máximo de cerca de 12 × 0.233 2.79 V – seguramente abaixo de Vref.

Para recuperar o V_in original a partir de uma leitura ADC, inverta a fórmula do divisor:

V_in = V_adc × (R1 + R2) / R2

Em código:

from machine import ADC

R1 = 33_000
R2 = 10_000
VREF = 3.3

adc = ADC("P6")

counts = adc.read_u16()
v_adc = counts * VREF / 65535
v_in = v_adc * (R1 + R2) / R2
print(v_in, "V")

Algumas notas práticas:

  • O divisor consome V_in / (R1 + R2) continuamente. Com R1 + R2 = 43 e V_in = 12 V, isso corresponde a cerca de 280 µA – geralmente insignificante, mas se a fonte for alimentada por bateria considere resistores maiores (100 kΩ a 1 MΩ) para reduzir o consumo em repouso.

  • A tolerância dos resistores (tipicamente ±1 % ou ±5 %) reflete-se diretamente na precisão da medição. Dois resistores de ±5 % podem dar ao V_in recuperado um erro máximo de cerca de ±10 %.

  • A impedância de saída do divisor combina-se com qualquer capacitância parasita para filtrar a entrada passa-baixo. Para sinais de variação rápida isso é relevante; para uma verificação de tensão de bateria não é.