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