Hoje vou te ensirar a obter tensões analógicas com DAC R2R, usando apenas um microcontrolador ESP32 e alguns resistores. O segredo é a forma como os resistores são conectados e como os pinos do microcontrolador são acionados.
O artigo no qual me baseei para escrever este é da Digikey, neste link. A ideia é usar resistores de dois valores difentes, um o dobro do outro, para criar uma espécie de escada ou cascata. A quantidade de saídas digitais usada define a resolução do conversor digital para analógico.

No meu caso vamos utiliar apenas seis bits, portanto seis pinos do nosso microcontrolador. O cálculo da resolução da tensão de saída é o seguinte:
2^6 = 64, dois elevado à sexta potência é igual a 64, ou seja são possíveis 64 níveis diferentes de tensão com apenas 6 bits. Para um microcontrolador alimentado em 3,3V, a resolução por bit é portanto:
3,3 / 64 = 0,05156 mV . Portanto cada bit variando gera uma variação de 51,56 mV na saída. Se formos comparar com um conversor 12 bit por exemplo, teremos uma resolução de 3,3 / 2^12 -> 3,3 / 4096: 805 uV. O conversor DAC 12 bit é 64 vezes mais fino que o nosso de 6 bit.
Para fins didáticos e algumas aplicações mais simples, um conversor digital para analógico DAC 6 bit é mais que suficiente. Se você quiser saber mais sobre um conversor integrado, veja este artigo anterior sobre o MCP4725.
O hardware
Diferente da maioria das montagens aqui do blog, o experimento de hoje exige mais atenção e cuidado. Isto porque teremos que encaixar doze (12) resistores na nossa protoboard, além de um potenciômetro e o ESP32-C3 (compre aqui).
Apesar disso eu consegui fazer a montagem completa em uma protoboard de 400 pinos, bem pequena. O diagrama esquemático da montagem está abaixo:

Alguns detalhes interessantes: eu coloquei um LED no pino 10 (D10) apenas para ficar piscando, para fins estéticos mesmo. O potenciômetro no pino A0 (pino) define quanta tensão de saída teremos no nosso conversor DAC.
Os pinos D1 até D6 são nossos bits efetivos, aqueles que vão alterar a tensão de saída do DAC. Cada um destes pinos tem em série um resistors de 10k Ohm, que leva a uma série de resistores de 4k7 Ohm. Aqui um detalhe importante: o ideia seria os valores serem o dobro um do outro (R/2R lembra?).
O mais próximo que consegui foi 4k7 e 10k Ohm. Para fins de experimento e demonstração da técnica, está ótimo. O valor do potenciômetro escolhido foi 10k Ohm, porém literalmente qualquer valor seria possível. Abaixo veja uma foto da montagem em bancada:

Tensões analógicas com DAC R2R
Bom, conhecemos a teoria de funcionamento e a montagem do circuito, porém como funciona esta conversão na prática?. Como é possível seis (6) pinos digitais gerarem uma tensão analógica variável?. Veja abaixo inicialmente o índice de cada pino digital no array de controle, bem como qual bit ele representa.
| Array index | Pin | Bit |
|---|---|---|
| 0 | D1 | bit 0 (LSB) |
| 1 | D2 | bit 1 |
| 2 | D3 | bit 2 |
| 3 | D4 | bit 3 |
| 4 | D5 | bit 4 |
| 5 | D6 | bit 5 (MSB) |
Mas como cada saída digital tem um peso na composição da tensão de saída?. Observe que o bit 5 (MSB, bit mais significativo) tem peso de 1/2. Ou seja, ele sozinho, se ativado coloca 3,3/2 V (1,65 V) na saída.
Já o bit 0 tem peso 1/64, adicionando apenas 3,3/64 V (51,56 mV) à saída. Aqui espero que você já tenha sacado a ideia: combinando os 5 bits você pode obter qualquer tensão entre 0 V e 3,3 V. Isto respeitando a granularidade de 51,56 mV do bit 0.
| Bit | Pin | Resistor | Weight | Effect on output |
|---|---|---|---|---|
| Bit 5 (MSB) | D1 | 4.7k | 1/2 | Big change |
| Bit 4 | D2 | 10k | 1/4 | Medium |
| Bit 3 | D3 | 20k | 1/8 | Small |
| Bit 2 | D4 | 40k | 1/16 | Smaller |
| Bit 1 | D5 | 80k | 1/32 | Tiny |
| Bit 0 (LSB) | D6 | 160k | 1/64 | Very tiny |
O Firmware
Fiz o código para meu ESP32-C3 no software IDE do Arduino, versão 2.3.8. Porém qualquer versão acima de 1.8 vai funcionar para você. o Código completo está aqui neste link do Github e também abaixo.
#define potentiometer 2
#define LED 10
#define D1 3
#define D2 4
#define D3 5
#define D4 6
#define D5 7
#define D6 21
unsigned long LEDtime= 0;
unsigned long analogConversion= 0;
int rawAnalogValue= 0;
int sixBitValue= 0;
int bitValue= 0;
const int bitPins[] = {D1, D2, D3, D4, D5, D6};
void setup() {
// put your setup code here, to run once:
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(10, OUTPUT);
pinMode(21, OUTPUT);
analogReadResolution(12);
}
void loop() {
if (millis() - LEDtime >= 200) {
LEDtime += 200;
digitalWrite(LED, !digitalRead(LED));
}
if(millis() - analogConversion >= 100){
analogConversion += 100;
rawAnalogValue= analogRead(potentiometer);
// Convert 12-bit → 6-bit by shifting right 6 bits
sixBitValue = rawAnalogValue >> 6; // 0–63
// Output each bit to the LEDs
for (int i = 0; i < 6; i++) {
bitValue = (sixBitValue >> i) & 1;
digitalWrite(bitPins[i], bitValue);
}
}
}
O código todo não é bloqueante, isto significa que não existem delay() inseridos. Tudo é feito com controle de tempo via millis() (porém poderia ser feito com micros() e com interrupções também). Inicialmente eu defino os nomes dos pinos: potenciômetro, LED, D1 .. D6.
No setup() eu defino todos os pinos digitais como saídas, exceto o potenciômetro. Então a cada 200 ms eu inverto o estado do LED, efetivamente fazendo-o piscar. E a cada 100 ms eu faço uma aquisição analógica, bem como o cálculo de conversão de inteiros para binário.
Isto porque minha leitura analógica do potenciômetro é entre 0 e 4095 inteiros. O resultado que eu quero obter é em 6 bits (seis saídas). Portanto preciso além de converter de inteiro para digital, ainda converter de 12 bits para 6 bits.
Inicialmente para converter entre 12 bit e 6 bit eu faço a seguinte operação:
sixBitValue = rawAnalogValue >> 6; // 0–63
Ela desloca minha informação 6 bits para a direita, efetivamente “eliminando” os 6 bits menos significativos. É o mesmo que dividir por 64.
Já o último passo é converter esta informação em 6 bits para binário, para poder acionar cada saída. Isto é feito pelo código abaixo. Ele desloca cada bit (um por vez) e compara com o nível lógico 1.
for (int i = 0; i < 6; i++) {
bitValue = (sixBitValue >> i) & 1;
digitalWrite(bitPins[i], bitValue);
}
Resultado final – demonstração
Copie o código completo acima e cole-o na sua IDE do Arduino. Conecte seu ESP32-C3 via cabo USB ao computador. Clique na setinha verde “->” UPLOAD no canto superior esquerdo da IDE. Aguardo alguns segundos e veja o código começar a rodar.
Pegue um multímetro e coloque na escala de tensão DC 20 V (ou algo similar), pois vamos medir até 3,3 V. Meça entre o GND do ESP32 e o último resistor de 4k7 Ohm. Gire o potenciômetro e veja a tensão variando entre 0 V e 3,3 V.

Se quiser comprar o ESP32-C3 deste experimento, use meu link do Aliexpress. Caso tenha dúvidas, pode me achar na aba de comentários do TikTok, Instagram ou Youtube (procure por “FritzenLab”), ou logo abaixo no campo de comentários.





