Fundamentos · 22 min de leitura

O que é ADC? Conversão analógico-digital com Arduino

O que é um ADC e como ele funciona? Sinais analógicos e digitais, resolução de 10 e 12 bits, analogReference, fórmula da tensão, ADC2 do ESP32 e redução de ruído.

Um ADC (conversor analógico-digital) é o circuito que transforma uma tensão que varia continuamente em um pino em um número com o qual o microcontrolador pode trabalhar. Toda vez que você chama analogRead() no Arduino, esse conversor faz o trabalho nos bastidores: o ADC de 10 bits do Arduino Uno transforma uma tensão entre 0 e 5 V em um número de 0 a 1023, enquanto os ADCs de 12 bits do ESP32 e do Raspberry Pi Pico transformam aproximadamente 0–3,3 V em um número de 0 a 4095. O ADC é a chave para ler qualquer coisa com saída analógica: potenciômetros, LDRs, sensores de umidade do solo, joysticks e sensores de temperatura.

Neste guia você vai aprender a diferença entre sinais analógicos e digitais, como um ADC transforma uma tensão em um número passo a passo e como a resolução e a tensão de referência afetam suas medições. Com números reais, vamos ver a fórmula que converte uma leitura em volts, como mudar a faixa de medição com analogReference, a taxa de amostragem e formas práticas de reduzir o ruído. Também vamos falar do ADC do ESP32, que não é linear nas extremidades, do conflito do ADC2 com o Wi-Fi e do ajuste de atenuação (attenuation), do uso do ADC do Raspberry Pi Pico com MicroPython e, por fim, fazer uma breve introdução ao DAC, que faz o trabalho inverso.

Leitura de um potenciômetro com o ADC
O potenciômetro é o jeito mais fácil de testar um ADC: a tensão no terminal do meio varia entre 0 V e a tensão de alimentação conforme você gira o botão.

Qual é a diferença entre sinal analógico e digital?

Um sinal analógico é uma grandeza que pode assumir infinitos valores dentro de uma faixa e varia continuamente ao longo do tempo. Quando a tensão no terminal do meio de um potenciômetro vai de 0 V a 5 V, ela passa por todos os valores intermediários, como 1,2 V, 1,21 V e 1,215 V; a onda sonora de um microfone, a tensão de um termistor que varia com a temperatura e a tensão de uma pilha que cai lentamente também são analógicas. Já um sinal digital só conhece níveis específicos. No mundo da lógica do Arduino, eles são dois: LOW (0) e HIGH (1). No Uno, uma entrada digital considera LOW qualquer coisa abaixo de cerca de 1,5 V e HIGH qualquer coisa acima de 3,0 V; a região entre os dois é indefinida. É por isso que digitalRead() não consegue distinguir 3,7 V de 4,2 V em uma bateria e chama os dois de HIGH. A força do sinal digital é a imunidade ao ruído: 4,6 V e 5,0 V significam o mesmo HIGH. Para medir, armazenar ou fazer cálculos com um valor analógico, primeiro você precisa transformá-lo em um número, ou seja, em um valor digital, e a peça que faz isso é o ADC.

O que é um ADC e como ele funciona?

O trabalho de um ADC pode ser resumido em dois passos. O primeiro é a amostragem: no momento da medição, o conversor copia a tensão de entrada para um pequeno capacitor (o circuito de amostragem e retenção, sample-and-hold) e a mantém estável até a conversão terminar; no ATmega328P esse capacitor tem cerca de 14 pF. O segundo é a quantização: a tensão retida é arredondada para o degrau mais próximo de uma escala que divide a tensão de referência em degraus iguais, e o número do degrau é devolvido como resultado. Os ADCs do Arduino Uno, do ESP32 e do Pico são todos do tipo aproximações sucessivas (SAR, Successive Approximation Register). Um ADC SAR funciona como um jogo de adivinhar números: primeiro testa metade da referência, coloca o bit mais significativo em 1 se a entrada for maior e o deixa em 0 se for menor, depois testa metade da faixa restante e repete isso para cada bit. É assim que um ADC de 10 bits encontra o degrau certo entre 1024 possibilidades com apenas 10 comparações. Para simplificar, a tabela abaixo mostra como um ADC de 4 bits com referência de 5 V mede uma entrada de 3,2 V:

PassoBit testadoTensão de comparaçãoA entrada (3,2 V) é maior?Bits do resultado
1Bit 3 (vale 8)8 / 16 × 5 = 2,500 VSim → 11000
2Bit 2 (vale 4)12 / 16 × 5 = 3,750 VNão → 01000
3Bit 1 (vale 2)10 / 16 × 5 = 3,125 VSim → 11010
4Bit 0 (vale 1)11 / 16 × 5 = 3,4375 VNão → 01010
ResultadoTodos os bits concluídos1010 = 10 → 10 × 5 / 16 = 3,125 VErro de 0,075 V (um degrau vale 0,3125 V)1010

A diferença de 0,075 V no resultado é o erro de quantização, e nenhum ADC escapa dele: se a tensão real estiver entre dois degraus, o ADC só pode informar um deles. O erro fica abaixo de um degrau (LSB), então quanto menor o degrau, mais fina a medição. Como o capacitor de amostragem e retenção precisa carregar a cada medição, a resistência da fonte que alimenta o ADC também importa: o datasheet do ATmega328P recomenda uma impedância de saída de cerca de 10 kΩ ou menos, e um divisor de tensão com resistência maior não consegue carregar o capacitor a tempo, fazendo as leituras desviarem. Além do tipo SAR encontrado nos microcontroladores, existem outros tipos de ADC. Os ADCs sigma-delta são lentos, mas muito precisos: o HX711, usado em projetos de balança, oferece 24 bits, e o módulo ADS1115, ligado por I2C, oferece 16 bits. Os ADCs flash usam um comparador separado para cada degrau; são extremamente rápidos e aparecem em osciloscópios.

Resolução do ADC: o que significam 10 bits e 12 bits?

A resolução diz em quantos degraus o ADC divide sua faixa de medição. Um ADC de N bits produz 2^N degraus: 10 bits significam 1024 degraus (0–1023), 12 bits, 4096 degraus (0–4095) e 16 bits, 65.536 degraus. A tensão de um único degrau se chama LSB (bit menos significativo) e é calculada com LSB = Vref / 2^N. No Arduino Uno isso dá 5 V / 1024 = 4,88 mV, e no ESP32 e no Pico, 3,3 V / 4096 = 0,81 mV. Ou seja, o Uno não enxerga variações menores que 4,88 mV; com um LM35, que fornece 10 mV/°C, isso equivale a um passo de cerca de 0,5 °C. Mas resolução e exatidão não são a mesma coisa. O ruído do ADC, a não linearidade e o erro da referência tornam inúteis alguns dos bits que existem no papel. A medida disso é o número efetivo de bits (ENOB): o ADC do RP2040, no Raspberry Pi Pico, devolve um resultado de 12 bits, mas segundo o datasheet o número efetivo de bits é 8,7. Vamos comparar os ADCs das três placas lado a lado:

CaracterísticaArduino Uno R3ESP32 (WROOM-32)Raspberry Pi Pico
Resolução do ADC10 bits (0–1023)12 bits (0–4095)12 bits (escalonado para 0–65535 no MicroPython)
Entradas analógicas6 (A0–A5; A0–A7 no Nano)18 canais: 8 no ADC1, 10 no ADC23 pinos (GP26–GP28) + VSYS/3 (GP29) + sensor de temperatura
Faixa de medição padrão0–5 VCerca de 0–3,1 V (atenuação de 11 dB)0–3,3 V (ADC_VREF)
Um degrau (LSB)4,88 mVCerca de 0,8 mV0,81 mV
Opções de referênciaDEFAULT (5 V), INTERNAL (1,1 V), EXTERNAL (AREF)Atenuação: 0, 2,5, 6 e 11 dBReferência externa no pino ADC_VREF
Taxa de amostragemCerca de 10.000 leituras/s20 kHz – 2 MHz no modo contínuo (DMA)500.000 leituras/s no hardware
Observação sobre exatidãoErro absoluto de ±2 LSBNão linear nas extremidades, precisa de calibraçãoENOB de 8,7 bits, offset de cerca de 30 mV
Saída analógica (DAC)Nenhuma (usa-se PWM)2 canais, 8 bits (GPIO 25 e 26)Nenhuma (usa-se PWM)

Fórmula para converter a leitura do ADC em tensão

O número que o ADC devolve não significa nada sozinho; para transformá-lo em tensão, você usa a tensão de referência e o número de degraus: Tensão = valor do ADC × Vref / 2^N. No Arduino Uno isso fica V = valor × 5,0 / 1024; então, se analogRead() devolveu 512, a tensão no pino é 512 × 5 / 1024 = 2,50 V. No sentido inverso, você descobre a que número uma tensão corresponde com valor = V × 1024 / Vref: 3,3 V é lido como cerca de 675 no Uno. Em muitos exemplos você vai ver uma divisão por 1023 em vez de 1024. O datasheet do ATmega328P dá a fórmula ADC = Vin × 1024 / Vref; o maior valor, 1023, representa um degrau abaixo de Vref. Dividir por 1023 faz o valor máximo mostrar exatamente 5,00 V, mas desloca todos os valores em cerca de 0,1%. Essa diferença é menor que o próprio erro de ±2 LSB do ADC, então as duas formas funcionam; o importante é ser consistente dentro do projeto. A grande fonte de erro, na verdade, é o próprio Vref: o pino 5V de um Uno alimentado por USB costuma ficar entre 4,7 e 5,1 V, e escrever 5,0 na fórmula causa até 5% de erro. Por isso, para medições precisas, meça o pino 5V com um multímetro e coloque o valor real no seu código. A única entrada analógica do ESP8266 (A0) também é de 10 bits; o chip em si mede 0–1 V, e o divisor embutido em placas como a NodeMCU e a Wemos D1 Mini amplia essa faixa para cerca de 0–3,2 V.

Placa e configuraçãoFaixa de leituraConversão para voltsExemplo
Arduino Uno / Nano (DEFAULT, 5 V)0–1023V = valor × 5,0 / 1024768 → 3,75 V
Uno, analogReference(INTERNAL)0–1023V = valor × 1,1 / 1024512 → 0,55 V
ESP32 (11 dB)0–4095Calibrado: analogReadMilliVolts() / 1000; aproximado: valor × 3,3 / 40951650 mV → 1,65 V
Raspberry Pi Pico (read_u16)0–65535V = valor × 3,3 / 6553532768 → 1,65 V
ESP8266 NodeMCU / Wemos D1 Mini (A0)0–1023V = valor × 3,2 / 1024512 → 1,60 V

Ligação do potenciômetro: Arduino, ESP32 e Pico

Terminal do potenciômetroArduino UnoESP32Raspberry Pi Pico
Terminal externo 15V3V33V3(OUT) (pino 36)
Terminal do meio (sinal)A0GPIO 34 (ADC1_CH6)GP26 / ADC0 (pino 31)
Terminal externo 2GNDGNDAGND (pino 33) ou GND
Capacitor antirruído opcional100 nF entre A0 e GND100 nF entre GPIO 34 e GND100 nF entre GP26 e AGND
As entradas analógicas do ESP32 e do Raspberry Pi Pico aceitam no máximo 3,3 V; ligar o terminal externo do potenciômetro em 5 V, ou conectar diretamente um sensor com saída de 5 V, pode danificar o pino de forma permanente. No Uno também, nunca aplique em uma entrada mais que a tensão de alimentação (5 V) nem menos que 0 V; reduza tensões maiores com um divisor de tensão. Um pino analógico sem nada ligado, flutuando, lê valores aleatórios; isso não é defeito, o pino simplesmente está “no ar”.

Passo a passo: sua primeira leitura de ADC com Arduino

  1. Monte o circuito: Ligue os terminais externos de um potenciômetro de 10 kΩ em 5V e GND, e o terminal do meio em A0.
  2. Meça o pino 5V: Meça a tensão entre 5V e GND com um multímetro e coloque o valor na constante VREF do código (ex.: 4.93).
  3. Carregue o código: Abra o sketch abaixo no Arduino IDE, selecione a placa e a porta e carregue-o.
  4. Abra o Monitor Serial: Ajuste para 9600 baud e observe o valor do ADC variar entre 0 e 1023 conforme você gira o botão (detalhes no guia do Monitor Serial).
  5. Confira: Meça entre A0 e GND com o multímetro e compare com a tensão na tela; a diferença deve ficar em torno de 10–20 mV.
C++ (Arduino IDE)
1// Potansiyometreyi ADC ile okuma / Reading a potentiometer with the ADC
2// Kenar bacaklar 5V ve GND'ye, orta bacak A0'a / Outer legs to 5V and GND, wiper to A0
3const int POT_PIN = A0;
4const float VREF = 5.0;      // 5V pininde ölçtüğün gerilim / voltage you measured on the 5V pin
5
6void setup() {
7  Serial.begin(9600);
8}
9
10void loop() {
11  int raw = analogRead(POT_PIN);             // 0-1023 arası sayı / number between 0-1023
12  float volts = raw * VREF / 1024.0;         // sayıyı volta çevir / convert the number to volts
13  int percent = map(raw, 0, 1023, 0, 100);   // yüzdeye ölçekle / scale to percent
14
15  Serial.print(F("ADC: "));
16  Serial.print(raw);
17  Serial.print(F("  Gerilim / Voltage: "));
18  Serial.print(volts, 3);
19  Serial.print(F(" V  Yuzde / Percent: "));
20  Serial.println(percent);
21  delay(200);
22}

analogRead() faz uma medição em cerca de 100 µs e devolve um inteiro entre 0 e 1023. O código primeiro converte esse número em volts com a fórmula e depois em porcentagem com map(). Como map() usa aritmética de inteiros, ela descarta a parte fracionária; se precisar de um resultado decimal, faça a conta você mesmo com float. Essa é uma medição raciométrica (ratiometric): como o potenciômetro e o ADC são alimentados pelos mesmos 5 V, a posição do botão, e portanto o valor do ADC, não muda mesmo que a alimentação caia para 4,9 V; só a tensão calculada muda. O mesmo vale para sensores lidos por meio de um divisor, como LDRs e NTCs. Por outro lado, quando você mede a tensão de uma bateria ou um sensor com saída fixa em mV, como o LM35, o valor real de Vref vai direto para o resultado.

Tensão de referência e analogReference

A tensão de referência (Vref) é o topo da escala do ADC: se a tensão de entrada for igual ou maior que Vref, o resultado trava no valor máximo (1023). Diminuir Vref estreita a faixa de medição, mas torna cada degrau menor, então você mede sinais pequenos com mais detalhe. No Arduino Uno, você escolhe a referência com a função analogReference(). Com a opção INTERNAL, Vref passa a ser 1,1 V e um degrau cai para 1,07 mV; você consegue ler um LM35 (10 mV/°C) em passos de cerca de 0,1 °C, mas em troca nada acima de 1,1 V, ou seja, 110 °C, pode ser medido. A própria referência interna de 1,1 V pode variar entre 1,0 e 1,2 V de um chip para outro, então projetos precisos exigem uma calibração única com multímetro. As primeiras leituras depois de trocar a referência podem sair erradas, como a própria documentação do Arduino observa, por isso descartar algumas leituras depois da troca é um bom hábito. A configuração de referência também afeta todos os pinos analógicos da placa ao mesmo tempo. As opções variam de placa para placa:

OpçãoReferênciaPlacasQuando usar
DEFAULT5 V (3,3 V em placas de 3,3 V)Uno, Nano, Mega, LeonardoSensores raciométricos em relação à alimentação, como potenciômetros, LDRs e joysticks
INTERNAL1,1 V (ATmega328P); 2,56 V no LeonardoUno, Nano, Leonardo (não existe no Mega)Sensores de baixa tensão, como o LM35
INTERNAL1V1 / INTERNAL2V561,1 V / 2,56 VSó no MegaSinais pequenos no Mega
EXTERNALA tensão no pino AREF (0–5 V)Uno, Nano, MegaUsar sua própria referência de precisão (ex.: 2,5 V ou 4,096 V)
AR_INTERNALCerca de 1,43 V (referência interna do chip)Uno R4 Minima e WiFiSinais pequenos no Uno R4
Se você ligou uma referência externa no pino AREF, precisa chamar analogReference(EXTERNAL) antes de chamar analogRead(). Caso contrário, a referência gerada dentro do chip entra em curto com a tensão do pino AREF e o microcontrolador pode ser danificado. Se quiser alternar entre referências, ligue a tensão externa ao AREF por meio de um resistor de 5 kΩ; como ele forma um divisor com a resistência interna do pino, de cerca de 32 kΩ, leve em conta que a tensão no AREF vai cair um pouco (cerca de 2,2 V para 2,5 V). Nunca aplique no AREF menos que 0 V nem mais que 5 V.

Taxa de amostragem: quantas leituras um ADC faz por segundo?

A taxa de amostragem é quantas medições o ADC consegue fazer em um segundo. No Arduino Uno, o clock do ADC é ajustado em 125 kHz dividindo 16 MHz por 128, e uma conversão leva 13 ciclos de clock; é por isso que analogRead() leva cerca de 100 µs e você consegue fazer no máximo umas 10.000 leituras por segundo. Isso é mais que suficiente para grandezas que mudam devagar, como temperatura, luz ou tensão de bateria; muitas vezes até 10 leituras por segundo bastam. Para sinais rápidos, entra em cena a regra de Nyquist: para capturar um sinal sem perdê-lo, é preciso amostrar pelo menos duas vezes mais rápido que sua frequência mais alta, e na prática se prefere 5–10 vezes. Para ver o zumbido de 50 Hz da rede elétrica, você precisa de pelo menos 100 leituras/s, e para gravar voz até 4 kHz, de pelo menos 8.000 leituras/s. Se precisar de leituras mais rápidas no Uno, você pode diminuir o prescaler (divisor) do ADC: colocar ADCSRA = (ADCSRA & 0xF8) | 0x04; em setup() ajusta o divisor para 16, o clock do ADC sobe para 1 MHz e analogRead() cai para cerca de 16 µs, à custa de alguma exatidão. No ESP32, chamadas individuais de analogRead() permitem dezenas de milhares de leituras por segundo, e no modo contínuo com DMA (analogContinuous() no Arduino) você pode escolher uma taxa entre 20 kHz e 2 MHz; esse modo só funciona com pinos do ADC1. O ADC do Raspberry Pi Pico roda com seu próprio clock de 48 MHz, termina cada conversão em 96 ciclos, ou seja, 2 µs, e chega a 500.000 leituras por segundo; um laço em MicroPython não acompanha esse ritmo, e para a velocidade máxima você precisa do C SDK e de DMA.

ADC do ESP32: não linearidade, conflito do ADC2 com o Wi-Fi e atenuação

No papel, o ADC de 12 bits do ESP32 mede quatro vezes mais fino que o do Uno, mas na prática há três pontos de atenção. O primeiro é a não linearidade: perto de 0 V, o ADC do ESP32 lê 0 até cerca de 100–150 mV, e no topo ele satura em 4095 antes de a entrada chegar a 3,3 V; a curva entre os dois também não é uma reta perfeita. O segundo é a variação da referência: por projeto, a referência interna do ESP32 é de 1100 mV, mas segundo a Espressif ela varia entre 1000 e 1200 mV de um chip para outro, o que significa um erro de cerca de ±9% em leituras sem calibração. Por isso a Espressif grava dados de calibração nos eFuses dos chips durante a fabricação. A função analogReadMilliVolts() do Arduino usa esses dados para converter o valor bruto diretamente em milivolts calibrados e, na maioria dos casos, é muito mais exata do que calcular analogRead() × 3,3 / 4095. O terceiro é a atenuação (attenuation): o núcleo do ADC só consegue medir até cerca de 1 V, então tensões maiores são reduzidas por um atenuador ajustável na entrada. O padrão no Arduino é 11 dB, que permite leituras até cerca de 3,1 V, mas a faixa exata que a Espressif recomenda para essa configuração é 150–2450 mV. Para sinais pequenos, diminuir a atenuação melhora tanto a exatidão quanto a resolução:

AtenuaçãoConstante no ArduinoFaixa exataUso
0 dBADC_0db100–950 mVSinais pequenos, medição mais fina
2,5 dBADC_2_5db100–1250 mVSaídas de sensores em torno de 1 V
6 dBADC_6db150–1750 mVSinais de nível médio
11 dB (padrão)ADC_11db150–2450 mV (as leituras continuam até cerca de 3,1 V)Potenciômetros e sensores de 0–3,3 V
No ESP32, o ADC2 também é usado pelo driver do Wi-Fi. Depois que o Wi-Fi é iniciado, não é possível ler os pinos do ADC2 (GPIO 0, 2, 4, 12, 13, 14, 15, 25, 26, 27); nesse caso o ESP-IDF devolve um erro de tempo limite (ESP_ERR_TIMEOUT), e nas versões atuais do core do Arduino analogRead() devolve 0. Em projetos com Wi-Fi, ligue sempre os sensores analógicos nos pinos do ADC1: GPIO 32, 33, 34, 35, 36 (VP) e 39 (VN). Desses, os 34–39 são somente entrada e não têm resistores de pull-up internos, o que os torna ideais para leituras analógicas. Os GPIO 0, 2, 12 e 15 também são pinos de boot (strapping), então não servem de jeito nenhum para sensores analógicos.
C++ (Arduino IDE)
1// ESP32 ADC: ham değer ve kalibre milivolt / ESP32 ADC: raw value and calibrated millivolts
2// Potansiyometre: 3V3, GND ve orta bacak GPIO 34 / Pot: 3V3, GND and wiper to GPIO 34
3const int POT_PIN = 34;      // ADC1_CH6, Wi-Fi açıkken de çalışır / ADC1_CH6, works with Wi-Fi on
4
5void setup() {
6  Serial.begin(115200);
7  analogReadResolution(12);                     // 0-4095 (varsayılan / default)
8  analogSetPinAttenuation(POT_PIN, ADC_11db);   // yaklaşık 3,1 V'a kadar / up to about 3.1 V
9}
10
11void loop() {
12  uint32_t rawSum = 0;
13  uint32_t mvSum = 0;
14  for (int i = 0; i < 16; i++) {                // 16 ölçümün ortalaması / average of 16 readings
15    rawSum += analogRead(POT_PIN);              // ham ADC değeri / raw ADC value
16    mvSum += analogReadMilliVolts(POT_PIN);     // eFuse kalibrasyonlu mV / eFuse-calibrated mV
17  }
18  float raw = rawSum / 16.0;
19  float naiveV = raw * 3.3 / 4095.0;            // basit formül / naive formula
20  float calibratedV = mvSum / 16.0 / 1000.0;    // kalibre edilmiş / calibrated
21
22  Serial.printf("Ham / Raw: %4.0f  Formul / Formula: %.3f V  Kalibre / Calibrated: %.3f V\n",
23                raw, naiveV, calibratedV);
24  delay(500);
25}

O código mostra dois resultados lado a lado: o valor bruto convertido com a fórmula simples e o valor calibrado por analogReadMilliVolts(). Conforme você gira o potenciômetro para uma das pontas, vai perceber a diferença aumentar, e lá embaixo, onde a fórmula mostra 0,000 V, o multímetro ainda mede cerca de 0,1 V. analogSetPinAttenuation() muda a atenuação de um único pino, enquanto analogSetAttenuation() muda a de todos os pinos. O ESP32 é bem mais ruidoso que o Uno, principalmente enquanto o Wi-Fi está transmitindo; a própria Espressif recomenda adicionar um capacitor de 100 nF na entrada e tirar a média de várias amostras, que é o que a média de 16 leituras do código faz. Chips mais novos, como o ESP32-S3 e o ESP32-C3, usam uma calibração mais avançada por ajuste de curva, mas os números dos pinos e as regras do ADC2 variam conforme o modelo, então confira sempre o mapa de pinos da sua placa (ferramenta Pinagem). Explicamos como montar um divisor para medir tensões acima de 3,3 V no guia de divisor de tensão.

ADC no Raspberry Pi Pico (MicroPython)

O Raspberry Pi Pico tem três entradas analógicas que você pode usar externamente: GP26 (ADC0), GP27 (ADC1) e GP28 (ADC2). O GP29 (ADC3) mede um terço da tensão de alimentação VSYS na placa, e o ADC4 está ligado ao sensor de temperatura interno do chip. A função read_u16() do MicroPython escala o resultado de 12 bits para a faixa 0–65535, para que o mesmo código funcione em placas diferentes, mas a resolução real continua sendo de 4096 degraus. O RP2040 não tem uma tensão de referência separada; ele usa a própria alimentação do ADC como referência. No Pico, essa alimentação (ADC_VREF, pino 35) vem da saída do regulador chaveado (SMPS) de 3,3 V, filtrada por um resistor de cerca de 200 Ω. O datasheet da placa da Raspberry Pi deixa claras três consequências: a exatidão dos 3,3 V é limitada, a alimentação é um pouco ruidosa e a corrente que o ADC consome cria um offset de cerca de 30 mV. As soluções estão no mesmo documento: colocar o GP23 em HIGH para passar o regulador ao modo PWM, com menos ondulação, ligar um canal do ADC sem uso ao AGND e subtrair sua leitura como offset e, para uma exatidão muito melhor, ligar uma referência de 3,0 V, como o LM4040, entre ADC_VREF e AGND (a faixa de medição passa a ser 0–3,0 V). O ADC do RP2040 também é conhecido por ter pequenos saltos (erros de DNL) nos valores 512, 1536, 2560 e 3584; tirar a média de várias leituras reduz o efeito deles. No Pico W, o GP23 é reservado ao chip sem fio e o modo do regulador é controlado pelo WL_GPIO1, então apague as linhas do GP23 no código abaixo se estiver usando um Pico W.

MicroPython
1from machine import ADC, Pin
2import time
3
4pot = ADC(26)                 # GP26 = ADC0 (pin 31)
5chip_temp = ADC(4)            # dahili sıcaklık sensörü / internal temperature sensor
6VREF = 3.3                    # ADC_VREF; multimetreyle ölçüp düzelt / measure and correct with a multimeter
7
8# Yalnız Pico ve Pico 2 (W değil): SMPS PWM moduna, daha az gürültü / Plain Pico and Pico 2 only (not W): SMPS to PWM mode, less noise
9smps_mode = Pin(23, Pin.OUT)
10smps_mode.value(1)
11
12
13def read_average(adc, samples=16):
14    total = 0
15    for _ in range(samples):
16        total += adc.read_u16()           # 0-65535 (12 bit ölçeklenmiş / 12-bit scaled)
17    return total / samples
18
19
20while True:
21    raw = read_average(pot)
22    volts = raw * VREF / 65535            # sayıyı volta çevir / convert the number to volts
23    t_volts = read_average(chip_temp) * VREF / 65535
24    temp_c = 27 - (t_volts - 0.706) / 0.001721    # RP2040 veri sayfası formülü / RP2040 datasheet formula
25    print("ADC: {:5d}  {:.3f} V  Yonga / Chip: {:.1f} C".format(int(raw), volts, temp_c))
26    time.sleep(0.5)

Formas de reduzir o ruído do ADC

Mesmo medindo uma tensão estável, é normal o valor do ADC oscilar um ou dois degraus; a quantização, a ondulação na alimentação, a interferência captada por fios longos e motores ou transmissões de Wi-Fi próximos contribuem para isso. No Uno, uma oscilação de ±1–2 degraus é considerada saudável; muito mais que isso geralmente indica um problema no circuito. Você pode combater o ruído tanto no hardware quanto no software:

  • Adicione um capacitor: Um capacitor cerâmico de 100 nF entre o pino analógico e o GND filtra interferências rápidas e, com fontes de alta resistência, oferece uma carga pronta ao capacitor de amostragem e retenção.
  • Mantenha os fios curtos: Se o cabo do sensor for longo, trance os fios de sinal e de GND; passe os fios de motores e relés longe das linhas analógicas.
  • Faça o aterramento direito: Não deixe a corrente de retorno de cargas de alta corrente, como motores, relés e fitas de LED, passar pelo fio GND do sensor; junte os GNDs em um único ponto (aterramento em estrela).
  • Use uma referência limpa: A alimentação USB é ruidosa; para medições de tensão absoluta, a referência interna ou um CI de referência externo dão resultados mais estáveis.
  • Descarte a primeira leitura depois de trocar de canal: O multiplexador na entrada do ADC pode carregar resíduo do canal anterior; ao ler vários pinos em sequência, jogue fora uma leitura em cada pino.
  • Tire a média: A média de N leituras reduz o ruído aleatório em cerca de √N vezes; 16 leituras reduzem o ruído a um quarto.
  • Sobreamostragem (oversampling): Se você somar 4^n leituras e deslocar o resultado n bits para a direita, ganha n bits extras de resolução; deslocar a soma de 16 leituras em 2 bits transforma os 10 bits do Uno em 12. Para isso funcionar, o sinal precisa ter pelo menos um degrau de ruído natural.
  • Filtros de mediana e exponencial: Um filtro de mediana elimina picos repentinos causados por motores, enquanto uma média móvel exponencial (EMA) gera uma curva suave usando pouquíssima memória.
C++ (Arduino IDE)
1// Ham, ortalama ve EMA filtreli ADC değerleri / Raw, averaged and EMA-filtered ADC values
2// Serial Plotter ile izle / Watch with the Serial Plotter
3const int SENSOR_PIN = A0;
4const float ALPHA = 0.1;     // EMA katsayısı (0-1) / EMA coefficient (0-1)
5float ema = 0;
6
7void setup() {
8  Serial.begin(115200);
9  analogRead(SENSOR_PIN);              // ilk okumayı at / discard the first reading
10  ema = analogRead(SENSOR_PIN);        // filtreyi başlat / seed the filter
11}
12
13void loop() {
14  int raw = analogRead(SENSOR_PIN);    // ham değer / raw value
15
16  long sum = 0;
17  for (int i = 0; i < 16; i++) {       // 16 ölçüm topla / sum 16 readings
18    sum += analogRead(SENSOR_PIN);
19  }
20  float average = sum / 16.0;          // ortalama (0-1023) / average (0-1023)
21
22  ema += ALPHA * (raw - ema);          // üstel hareketli ortalama / exponential moving average
23
24  Serial.print(F("ham:"));
25  Serial.print(raw);
26  Serial.print(F(" ortalama:"));
27  Serial.print(average);
28  Serial.print(F(" ema:"));
29  Serial.println(ema);
30  delay(20);
31}

Quando você carregar o código e abrir o Plotter Serial no Arduino IDE, vai ver três linhas: o valor bruto treme, a média de 16 leituras fica visivelmente mais calma e a EMA é a curva mais suave, mas reage às mudanças um pouco mais tarde. O coeficiente ALPHA é escolhido entre 0 e 1: 0.1 significa que cada nova leitura contribui com 10% para o resultado, então, grosso modo, as últimas 10 leituras têm efeito; aumente o valor e a resposta fica mais rápida, mas o ruído cresce. Qual filtro escolher depende do sinal; uma EMA forte combina com uma temperatura que muda devagar, enquanto uma média curta é melhor para um joystick que precisa de resposta rápida. Comparamos médias móveis, filtros de mediana e histerese com exemplos reais de sensores no guia de filtragem de dados de sensores.

Uma breve introdução ao DAC: do digital para o analógico

Um DAC (conversor digital-analógico) faz o contrário de um ADC: recebe um número e produz uma tensão proporcional a ele. Escreva 0 em um DAC de 8 bits e você terá 0 V, escreva 255 e terá algo perto da tensão de alimentação, escreva 128 e terá cerca da metade. Os DACs mais simples são feitos com uma escada de resistores chamada R-2R. Vamos esclarecer aqui uma confusão comum: analogWrite() no Arduino Uno não é um DAC, ela gera PWM; na verdade o pino alterna rapidamente entre 0 V e 5 V. Isso funciona bem para brilho de LED e velocidade de motor, mas se você realmente precisa de uma tensão estável, tem que adicionar um filtro passa-baixa RC na saída PWM; você pode calcular a constante de tempo do filtro com a ferramenta Constante de tempo RC. Quanto às placas com DAC de verdade: o ESP32 tem dois DACs de 8 bits nos GPIO 25 e GPIO 26, usados com dacWrite(pino, valor), enquanto o ESP32-S3 e o ESP32-C3 não têm DAC. O Arduino Uno R4 tem um DAC de 12 bits no pino A0. Para o Uno R3, o Nano e o Pico, o caminho mais fácil é o módulo MCP4725 de 12 bits, ligado por I2C. Com um DAC você pode gerar som, produzir ondas senoidais ou triangulares e até ligar a saída do DAC a uma entrada de ADC para testar o ADC com tensões conhecidas:

C++ (Arduino IDE)
1// ESP32 DAC ile sinüs dalgası / Sine wave with the ESP32 DAC
2// Çıkış GPIO 25'te, osiloskopla izle / Output on GPIO 25, watch it with an oscilloscope
3const int DAC_PIN = 25;      // DAC1 = GPIO 25 (DAC2 = GPIO 26)
4const int STEPS = 64;        // bir periyottaki nokta sayısı / points per period
5uint8_t sineTable[STEPS];
6
7void setup() {
8  for (int i = 0; i < STEPS; i++) {
9    sineTable[i] = 128 + 127 * sin(2 * PI * i / STEPS);  // 1-255 arası tablo / table between 1-255
10  }
11}
12
13void loop() {
14  for (int i = 0; i < STEPS; i++) {
15    dacWrite(DAC_PIN, sineTable[i]);   // 0 → 0 V, 255 → yaklaşık 3,3 V / 0 → 0 V, 255 → about 3.3 V
16    delayMicroseconds(150);            // yaklaşık 100 Hz / roughly 100 Hz
17  }
18}

Ideias de projetos com o ADC

  • Voltímetro digital: Meça de 0 a 25 V com um divisor de tensão e mostre o resultado em um LCD; os passos estão no guia Como fazer um voltímetro com Arduino.
  • Luz noturna automática: Leia a tensão de um LDR e acenda os LEDs quando escurecer.
  • Vaso inteligente: Use a saída analógica de um sensor de umidade do solo para ligar uma bomba quando a terra secar.
  • Robô controlado por joystick: Os dois eixos de um joystick são duas entradas analógicas separadas; transforme os valores em velocidade e direção dos motores.
  • Medidor de corrente: Leia a tensão proporcional à corrente de um ACS712 para ver quanta corrente um aparelho consome.
  • Medidor de nível sonoro: Amostre rapidamente a saída analógica de um sensor de som KY-038 e acenda uma barra de LEDs de acordo com o valor de pico.
  • Indicador de bateria: Meça a tensão em um projeto alimentado por bateria e mostre a carga restante em porcentagem em um display.

Erros comuns e como corrigi-los

SintomaCausa provávelSolução
O valor oscila aleatoriamente sem nada ligadoO pino está flutuandoLigue o sensor; não leia pinos sem uso ou ligue-os ao GND
O valor trava em 1023 (4095 no ESP32)A entrada está acima da referência ou INTERNAL está selecionadoAjuste a referência ou a atenuação e reduza tensões altas com um divisor
No ESP32, analogRead() devolve 0 quando o Wi-Fi é ligadoO sensor está em um pino do ADC2Use os pinos do ADC1, GPIO 32–39
O ESP32 mostra 0 para tensões pequenas e 4095 para tensões grandesO ADC não é linear nas extremidadesUse analogReadMilliVolts() e mantenha o sinal entre 150–2450 mV
A tensão calculada difere do multímetro em 3–5%Vref não é 5,00 V (alimentação USB)Meça o pino 5V e coloque o valor em VREF, ou adicione um fator de calibração
Ao ler dois pinos em sequência, um valor afeta o outroMultiplexador e resistência da fonte altaDescarte a primeira leitura após trocar de canal, mantenha a fonte abaixo de 10 kΩ e adicione 100 nF
Os valores pulam quando um motor ou relé funcionaRuído na linha de GND compartilhada, queda na alimentaçãoDê às cargas um retorno de GND próprio, use capacitores e um filtro de mediana
As leituras ficaram erradas depois de aplicar tensão no AREFO AREF foi usado sem chamar analogReference(EXTERNAL)Selecione EXTERNAL primeiro ou ligue ao AREF por meio de um resistor de 5 kΩ
Depois de selecionar INTERNAL, o potenciômetro chega a 1023 na metade do cursoA referência de 1,1 V afeta todos os pinos analógicosVolte para DEFAULT antes de ler sensores raciométricos e descarte algumas leituras
No Pico, a leitura fica acima de 0 mesmo com a entrada em GNDOffset do ADC e ruído no ADC_VREFLigue um canal ao AGND, meça o offset e subtraia; coloque o GP23 em HIGH
O jeito mais rápido de verificar um circuito com ADC é medir uma tensão conhecida. Primeiro ligue a entrada analógica ao GND e confira se aparece um valor próximo de 0. Depois pegue uma pilha AA cuja tensão você mediu com o multímetro e ligue o polo negativo ao GND e o positivo ao pino analógico: para cerca de 1,5 V, você deve ver em torno de 307 no Uno, em torno de 1500 mV com analogReadMilliVolts() no ESP32 e em torno de 29.800 com read_u16() no Pico. Se o resultado bater, seu código e sua ligação estão corretos; se não, o problema provavelmente está na tensão de referência ou no GND comum.

O ADC é a ponte entre o mundo físico e o seu código: quando você conhece a resolução, a tensão de referência e a taxa de amostragem, também sabe o que cada número na tela representa e até que ponto pode confiar nele. No Uno, meça a referência direito; no ESP32, use os pinos do ADC1 e analogReadMilliVolts(); no Pico, leve em conta o offset e o ruído; depois acalme o resultado com médias e filtros. No app BlueGrays você encontra projetos baseados em leituras analógicas, como medir a intensidade da luz com LDR, um voltímetro digital com LCD, medição de temperatura com NTC e controle de servo e do brilho de LED com potenciômetro, cada um com esquema do circuito e código passo a passo.

Perguntas frequentes

O que é um ADC e para que serve?

Um ADC (conversor analógico-digital) é o circuito que transforma a tensão em um pino em um número que o microcontrolador pode processar. Ele é usado para ler componentes com saída analógica, como potenciômetros, LDRs e sensores de temperatura e umidade. No Arduino, o comando analogRead() aciona esse conversor.

Qual é a diferença entre sinal analógico e digital?

Um sinal analógico pode assumir qualquer valor dentro de uma faixa e varia continuamente, enquanto um sinal digital é formado apenas por níveis específicos, LOW e HIGH no Arduino. digitalRead() só diz se um pino está em 0 ou 1, enquanto analogRead() informa quanta tensão existe na forma de um número.

Por que o analogRead do Arduino devolve valores de 0 a 1023?

O ADC do Arduino Uno é de 10 bits e produz 2^10 = 1024 degraus diferentes, numerados de 0 a 1023. O valor 0 representa 0 V, e 1023 representa um degrau abaixo da tensão de referência (normalmente 5 V). Os ADCs de 12 bits do ESP32 e do Pico devolvem valores de 0 a 4095.

Como converter o valor do ADC em tensão?

Use a fórmula tensão = valor do ADC × tensão de referência / número de degraus. No Arduino Uno isso fica V = valor × 5,0 / 1024; no ESP32, analogReadMilliVolts() fornece diretamente milivolts calibrados. No Pico, use V = valor × 3,3 / 65535 para o valor de read_u16() do MicroPython.

Os pinos do ADC2 do ESP32 funcionam com Wi-Fi?

Não. No ESP32, o driver do Wi-Fi também usa a unidade ADC2, então não é possível ler os pinos do ADC2 (GPIO 0, 2, 4, 12–15, 25–27) enquanto o Wi-Fi está ligado. Em projetos com Wi-Fi, ligue os sensores analógicos nos pinos do ADC1 (GPIO 32–39).

O que é um DAC e qual a diferença para um ADC?

Um DAC (conversor digital-analógico) faz o contrário de um ADC: transforma um número em tensão. O ADC é usado para medir a tensão que vem de um sensor; o DAC, para produzir uma tensão, como som ou um sinal. O Arduino Uno não tem DAC e analogWrite() gera PWM; o ESP32 tem dois DACs de 8 bits nos GPIO 25 e 26, e o Uno R4 tem um DAC de 12 bits no A0.

Ver todos os projetos
Medição da intensidade da luz com LDR
#11Iniciante

Medição da intensidade da luz com LDR

Quer ver a luminosidade do seu quarto em números? O LDR, um pequeno componente sensível à luz, mede a luz ambiente, e o Arduino exibe o valor na tela do computador a cada meio segundo. Cubra o sensor

4.6(81)
139
Voltímetro digital com display LCD
#56Intermediário
Premium

Voltímetro digital com display LCD

Descubra a tensão de uma pilha ou de um adaptador de alimentação com um medidor feito por você. Um divisor formado por dois resistores reduz a tensão alta a um nível que a placa consegue ler, e o Ardu

4.5(27)
36
Leitura da intensidade da luz com módulo LDR e ESP32
#113Iniciante

Leitura da intensidade da luz com módulo LDR e ESP32

Acompanhe em tempo real no Monitor Serial o valor bruto do ADC do módulo LDR e a porcentagem relativa de luz calculada a partir de referências de escuridão e claridade. Essa porcentagem não é uma medida em lux. O projeto ensina a lógica de calibração do módulo. É ideal fazê-lo antes do projeto 10, pois ajuda a determinar o valor do limiar.

4.6(36)
55
Brilho do LED com potenciômetro no ESP32 (analógico → PWM)
#115Intermediário
Premium

Brilho do LED com potenciômetro no ESP32 (analógico → PWM)

Neste projeto, controlamos o brilho de um LED de forma analógica com um potenciômetro. O pino ADC do ESP32 lê a tensão de 0-3,3V do potenciômetro e converte esse valor em um sinal PWM (modulação por largura de pulso), enviado ao LED. Assim, ao girar o potenciômetro, o brilho do LED aumenta e diminui gradualmente. Com Arduino Core 3.0+, você pode usar analogWrite() diretamente; no ESP32-S2/S3, a resolução do ADC é fixada em 12 bits.

4.5(19)
32
Medição de temperatura com NTC e display LCD 2x16
#44Iniciante
Premium

Medição de temperatura com NTC e display LCD 2x16

Meça a temperatura ao seu redor com um sensor que parece uma pequena conta. Esse componente, chamado NTC, deixa a eletricidade passar com mais facilidade à medida que aquece; o Arduino lê essa mudança

4.5(33)
44
Uso de servo motor com potenciômetro
#36Iniciante
Premium

Uso de servo motor com potenciômetro

Conforme você gira o botão do potenciômetro, o braço do servo motor gira junto: uma extremidade do botão corresponde a zero grau, e a outra, a meia volta. O Arduino lê continuamente a posição do botão

4.6(37)
52
Controle de LEDs com joystick
#59Intermediário
Premium

Controle de LEDs com joystick

Empurre a alavanca do joystick até o fim em qualquer direção e o LED correspondente acende: são quatro cores diferentes para direita, esquerda, cima e baixo. Ao soltar a alavanca, ela volta ao centro

4.7(50)
67
Luminária com mistura de cores e ESP32 (3 potenciômetros + LED RGB + OLED)
#138Avançado
Premium

Luminária com mistura de cores e ESP32 (3 potenciômetros + LED RGB + OLED)

Uma luminária inteligente que permite misturar a cor que você quiser girando três potenciômetros com o ESP32! Ao girar os potenciômetros de vermelho, verde e azul, o LED RGB de cátodo comum muda de cor em tempo real. O display OLED SSD1306 mostra os valores de cada cor na faixa de 0–255, barras de preenchimento e o código HEX da cor para a web, como #FF8040.

4.7(6)
10