Tutorial · Iniciante · 30 min
Leitura de tensões analógicas: referências do ADC e divisores
analogRead retorna uma razão, não uma tensão. Escolha uma referência estável, dimensione um divisor e faça um monitor de bateria confiável.
Introdução
analogRead() é a função mais amigável de um Arduino e uma das mais traiçoeiramente enganosas. Ela devolve um número entre 0 e 1023, todo mundo trata esse número como uma tensão e, na maior parte do tempo, nada dá errado.
Em um robô, dá errado, porque um robô tem motores, e os motores alteram justamente a tensão de referência usada nessa medição.
analogRead retorna uma razão
O ADC não mede volts. Ele compara sua entrada com uma referência e informa a razão:
reading = 1023 × V_in / V_ref
Em um Arduino Uno, V_ref é definido como AVCC por padrão — o trilho de 5 V da placa. Portanto, analogRead() está realmente respondendo “que fração do trilho de 5 V isso representa?”, e converter a leitura para volts multiplicando-a por 5/1023 só é correto enquanto o trilho for exatamente 5 V.
Você já sabe que essa tensão não é, sempre que os motores estão funcionando.
A referência é o defeito
Conecte a tensão de uma bateria, por meio de um divisor, a A0 e observe o número enquanto os motores iniciam.
Um desligamento por bateria fraca baseado no primeiro projeto cumpre o papel oposto: quanto mais o robô trabalha, mais sadia a bateria parece. E a falha é silenciosa, porque cada leitura individual é uma razão perfeitamente válida.
A solução é uma referência que não se move. O ATmega328P tem uma referência bandgap de 1,1 V interna:
analogReference(INTERNAL); // 1.1 V on an Uno; INTERNAL1V1 on a Mega
analogRead(A0); // discard — the reference needs a moment to settle
Sempre descarte a primeira leitura depois de trocar a referência. A referência interna e o capacitor de entrada precisam de tempo para estabilizar, e a primeira amostra é feita antes que isso aconteça.
Dimensionando o divisor
A referência agora é 1,1 V e a bateria chega a 8,4 V, então o divisor precisa levar o valor máximo da faixa a um nível ligeiramente inferior ao da referência:
V_adc = V_pack × R2 / (R1 + R2)
Com R1 = 68 kΩ e R2 = 10 kΩ, a razão é 0,128, portanto uma bateria totalmente carregada de 8,4 V apresenta 1,077 V — logo abaixo da referência, usando quase toda a escala. Há três números que vale verificar em qualquer divisor que você projetar:
| Verificação | Este divisor | Por quê |
|---|---|---|
| Topo da faixa em relação à referência | 1,077 V contra 1,1 V | Se a tensão ultrapassar a referência, a leitura satura |
| Corrente de repouso | 108 µA | Drena 2,6 mAh por dia — irrelevante frente a 2000 mAh |
| Impedância de saída (R1∥R2) | 8,7 kΩ | Mantenha abaixo de cerca de 10 kΩ; veja abaixo |
Compare isso com a versão ingênua — um divisor de 20 kΩ/10 kΩ lido contra o trilho de 5 V. Ela coloca uma bateria totalmente carregada em 2,80 V, que correspondem a 573 contagens de 1023 possíveis, e usa 164 contagens em toda a faixa de 6,0–8,4 V da bateria, contra 286 do melhor projeto. Quase o dobro da resolução, com os mesmos dois resistores e uma linha de código.
Resolução não é precisão
Dez bits contra uma referência de 5 V são 4,88 mV por nível; contra a referência de 1,1 V, são 1,07 mV. Nenhum desses números representa sua precisão.
O que realmente limita você:
- Tolerância da referência. A bandgap é nominalmente 1,1 V e varia alguns pontos percentuais entre chips. Esse é um erro de escala fixo, portanto meça-a uma vez por placa: aplique uma tensão conhecida, leia as contagens e calcule a referência real. Armazene essa constante. Esta é uma etapa de calibração, não um refinamento opcional.
- Ruído. A alimentação de um robô é ruidosa, e a média é a resposta simples. Fazer a média de N amostras reduz o ruído aleatório em √N — com 16 amostras, o ruído cai a um quarto, o equivalente a um bit extra de resolução utilizável. Isso não resolve um erro de escala.
- Impedância da fonte. O ADC carrega um pequeno capacitor de amostragem e retenção por meio da fonte de sinal à qual está conectado. Uma fonte de sinal com alta impedância não consegue carregá-lo no tempo permitido, e o resíduo do canal lido anteriormente continua presente.
Este último item produz uma falha característica que vale nomear.
Canais que refletem o valor dos vizinhos
Leia A0 e A1 alternadamente com fontes de sinal de alta impedância e cada leitura será puxada na direção da anterior. Varie um potenciômetro em A0 e veja A1 se mover junto. Nada está ligado errado.
Há duas correções, e você pode usar as duas:
int readSettled(uint8_t pin) {
analogRead(pin); // charge the sample-and-hold on this channel
return analogRead(pin); // then take the one you keep
}
Ler duas vezes e descartar a primeira dá ao capacitor uma segunda janela de amostragem para se carregar até a nova tensão. A outra correção é reduzir a impedância da fonte — e é por isso que o divisor acima usa 68 kΩ/10 kΩ, em vez dos 100 kΩ/100 kΩ que parecem mais simétricos e dão uma impedância de saída de 50 kΩ.
Onde isso aparece em um robô
- Monitoramento da bateria, como acima — e é o que torna um desligamento por tensão baixa suficientemente confiável para proteger um conjunto de células de íon-lítio.
- Sensores de linha analógicos. Uma matriz de sensores de reflexão por infravermelho fornece um valor contínuo por sensor, o que permite que um seguidor de linha calcule uma posição contínua, em vez de um indicador esquerda/direita. Esses sensores são lidos contra o mesmo trilho que sofre queda de tensão quando os motores funcionam, e essa é uma razão pela qual a calibração de um seguidor de linha muda conforme a bateria esvazia.
- Medição de corrente, por meio de um resistor de derivação (shunt) ou de um sensor Hall cuja saída é uma tensão.
- Potenciômetros como botões de ajuste, que é a maneira mais amigável de ajustar um ganho de PID sem reprogramar o firmware.
- Não use um sensor de 5 V com uma placa de 3,3 V. Um ESP32 ou Raspberry Pi precisa do divisor para proteção, não apenas para faixa.
Quando algo dá errado
| Sintoma | Causa provável |
|---|---|
| A leitura da bateria sobe quando os motores iniciam | Referenciada ao trilho que caiu; use INTERNAL |
| Leitura presa em 1023 | Entrada acima da referência — razão do divisor grande demais |
| Um canal repete o valor do canal anterior | Impedância da fonte alta demais; leia duas vezes e descarte |
| As leituras saltam dezenas de contagens | Ruído da fonte; faça a média e verifique os trilhos de alimentação |
| Tensão consistentemente alguns pontos percentuais fora | Referência interna não calibrada — meça-a uma vez |
A primeira leitura depois de analogReference() está errada |
Esperado; descarte-a |
| A calibração do sensor de linha sofre deriva conforme a bateria esvazia | Leituras referenciadas ao trilho em queda |
| Apenas 15% da faixa é usado | Divisor dimensionado para 5 V, mas lido contra 1,1 V |
A regra que evita a maior parte disso: decida qual é sua referência antes de decidir qualquer outra coisa. Cada número que o ADC fornece é relativo a ela, portanto uma referência que se move faz de cada leitura uma medição que depende simultaneamente da entrada e da referência.
Explore o grafo
Faz parte destas montagens
Projetos e caminhos de aprendizagem que incluem este tutorial.
Leitura complementar