3.12. Lendo sinais analógicos com o ADC

Até agora a câmera tem lido sinais digitais – um pino é 0 ou 1, uma chave está aberta ou fechada. A maioria dos sinais que saem de sensores do mundo real é analógica: uma tensão contínua que varia suavemente dentro de alguma faixa. Um fotorresistor percorre todas as tensões entre os trilhos conforme o brilho ambiente muda. A saída de um sensor de temperatura varia alguns milivolts à medida que uma sala esquenta. A saída de um microfone sobe e desce com o som ao seu redor.

Um conversor analógico-digital (ADC) é a ponte. Ele amostra a tensão em um pino e retorna um inteiro que o Python pode ler como qualquer outro valor.

3.12.1. Quantização

Um valor digital não pode representar exatamente uma tensão contínua. A função do ADC é quantizar – ajustar cada amostra para o 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 por toda a sua faixa de entrada.

Uma curva analógica suave plotada em função do tempo, sobreposta com uma aproximação digital em degraus. Linhas horizontais tracejadas marcam os níveis de quantização; a curva em degraus ajusta-se a qualquer nível que esteja mais próximo do sinal analógico em cada ponto de amostragem.

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

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

3.12.2. A classe machine.ADC

machine.ADC encapsula um canal de entrada analógica. Construa-o com o pino que você quer ler e então chame read_u16():

from machine import ADC

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

read_u16() sempre retorna um inteiro de 16 bits sem sinal entre 0 e 65535. A resolução nativa do ADC varia conforme a placa (12 bits no STM32, específica da porta em outros casos); o resultado é alinhado à esquerda em 16 bits, de modo que o detalhe de hardware não vaza para o Python – um valor de 65535 é o fundo de escala independentemente do chip.

A tensão de referência – a entrada que corresponde ao fundo de escala – depende da placa. Consulte a Placas OpenMV para obter o valor da sua câmera. Qualquer coisa acima da referência é lida como fundo de escala (e pode danificar o pino se exceder a tensão de entrada máxima absoluta).

3.12.2.1. Convertendo contagens em tensão

O mapeamento de contagens para tensão é linear, com as contagens de fundo de escala mapeando exatamente para 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 trilho de tensão e o terra formam um divisor de tensão. O nó entre eles fica em uma tensão definida pela razão dos dois resistores:

Um divisor de tensão. Vin no topo conecta-se através de R1 a um nó derivado como V_out, que então se conecta através de R2 ao terra.

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 trilho; R2 muito menor que R1 coloca a derivação perto do terra; R2 muito maior a coloca perto do trilho.

A fórmula assume que nada mais drena corrente apreciável de V_out. Um pino de ADC é de alta impedância (megaohms, nanoamperes) e satisfaz isso facilmente, então um divisor alimentando um ADC se comporta como a fórmula prevê.

3.12.4. Potenciômetros

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

Um potenciômetro conectado entre 3,3 V e o terra. O cursor é derivado para um pino de ADC.

Um potenciômetro conectado como uma fonte de tensão manual para o ADC: 3,3 V em uma extremidade, terra na outra, cursor para o pino.

Um potenciômetro é o dispositivo de entrada canônico para experimentar o ADC. Conecte uma extremidade a 3.3 V, a outra ao terra, e o cursor a um pino com capacidade de ADC; girar o botão faz o cursor percorrer todas as tensões entre os trilhos.

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. Lendo tensões mais altas com um divisor

Uma tensão acima de Vref vai fixar o ADC no fundo de escala e pode danificar a entrada se exceder a especificação máxima absoluta. Para ler uma fonte mais alta – uma bateria, a saída de um sensor que ultrapassa Vref – reduza-a com um divisor de tensão fixo antes que ela chegue ao pino:

Um divisor de tensão reduzindo um V_in alto para um pino de ADC. R1 vai de V_in até uma junção, que é derivada horizontalmente para o pino de ADC; R2 continua da junção até o terra.

Reduzindo uma fonte de alta tensão para caber no ADC: R1 e R2 formam um divisor de tensão fixo cuja derivação alimenta o pino de ADC.

Escolha R1 e R2 de modo que a tensão dividida permaneça dentro da faixa do ADC na maior tensão de entrada que você espera:

V_adc = V_in × R2 / (R1 + R2)

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

Para recuperar o V_in original a partir de uma leitura do 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 observações práticas:

  • O divisor drena V_in / (R1 + R2) continuamente. Com R1 + R2 = 43 e V_in = 12 V, isso é cerca de 280 µA – geralmente desprezível, 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 do resistor (tipicamente ±1 % ou ±5 %) afeta diretamente a precisão da medição. Dois resistores de ±5 % podem dar ao V_in recuperado um erro de pior caso de aproximadamente ±10 %.

  • A impedância de fonte do divisor combina-se com qualquer capacitância parasita para filtrar a entrada por passa-baixas. Para sinais que mudam rapidamente isso importa; para uma verificação de tensão de bateria, não.