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.
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: 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 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:
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 kΩ, R2 = 10 kΩ. 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. ComR1 + R2 = 43 kΩeV_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_inrecuperado 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.