Entradas e saídas: botao, potenciometro e LED — Arduino e IoT — semana 5 do 1o trimestre

Informatica · Conteudo · publicado em 02/10/2026
Semana 5 · Entradas e saídas: botao, potenciometro e LED — Material de Apoio Arduino

Semana 5 de 13· 1o trimestre · 01/02 a 30/04

Entradas e saídas: botao, potenciometro e LED

A primeira aula com dois lados: o mundo real fala, o ESP32 responde.

Aula 1 — Botao: entrada digital, pull-up e anti-vibracao

Objetivos

  • Declarar um pino como INPUT_PULLUP e explicar o que o resistor interno está fazendo.
  • Ler o botão com digitalRead e traduzir o nível invertido em "apertado" e "solto".
  • Aplicar anti-vibração por tempo e por estado para contar um aperto só uma vez.
  • Montar o circuito do botão sem resistor externo e dizer por que o kit não tem um pull-up de 10 kΩ.

Material

  • 1 ESP32 DevKit V1 por aluno, com o cabo USB
  • 1 protoboard de 830 pontos e 1 jogo de jumpers por aluno
  • 2 a 5 LEDs de 3,3 V e 2 a 5 resistores de 330 Ω por aluno
  • 2 a 5 push buttons de 4 pinos por aluno
  • 1 módulo de alimentação MB102 por dupla
  • Folha com o esquema do botão e a tabela de níveis impressa, uma por dupla

Conceitos

Entrada digital e o pino flutuante

Um pino de entrada lê HIGH ou LOW. Quando nada está ligado nele, ele não lê nem um nem outro: lê flutuante, e o valor depende do ruído da mesa, da mão do aluno, do jumper vizinho. O programa não dá erro — ele lê lixo e age sobre ele.

É por isso que toda entrada precisa de um resistor de pull-up ou de pull-down: para segurar um nível quando ninguém está mandando sinal.

O pull-up interno e a leitura invertida

INPUT_PULLUP liga, dentro do próprio ESP32, um resistor que leva o pino para 3,3 V. A configuração do botão é:

SituaçãoNível no pinodigitalRead devolve
Botão soltoo pull-up seguraHIGH
Botão apertadoo botão puxa para o GNDLOW

Duas consequências que o aluno precisa internalizar: a leitura é invertida (apertado é LOW, não HIGH), e o circuito é mais simples porque o resistor não precisa existir na protoboard. Um botão são dois fios: um para o pino, um para o GND.

O INPUT_PULLDOWN também existe e faz o contrário: segura o pino em LOW e o botão puxa para 3,3 V. A leitura também é invertida. O curso usa INPUT_PULLUP porque ele é mais robusto contra ruído e não depende de 3,3 V chegar no botão.

Anti-vibração: por que o botão gruda

Contato mecânico não fecha uma vez. Ele vibra: fecha, abre por um instante, fecha, abre — tudo isso dentro de um ou dois milissegundos. Um laço que olha o botão a cada volta do loop pega essa vibração umas dez vezes e produz dez contagens de um aperto só.

Há duas formas de corrigir, e a aula usa as duas:

  1. Por tempo: só olhar o botão a cada 50 ms. A vibração acaba antes da próxima leitura.
  2. Por estado: contar só na borda, quando o estado muda de solto para apertado. A leitura continua a cada 50 ms, mas o contagem++ só acontece uma vez por aperto.

A segunda é mais robusta: mesmo que a vibração atravesse a janela de tempo, ela não gera contagem nova porque o estado já mudou.

Como o botão se comporta com o pull-up

Quando o aluno aperta o botão, ele não envia 3,3 V para o ESP32: ele puxa o pino para o GND. Isso é o oposto do que a maioria dos iniciantes imagina, e é a causa de "meu botão só funciona invertido".

Esse mesmo arranjo é o que o dia 9 usa no display, e o que o dia 11 reaproveita no projeto final: botão entre pino e GND, com o pull-up interno fazendo o resto.

Atividade

Montagem:

  • Um dos lados do push button no GPIO15, por jumper.
  • O lado vizinho do mesmo botão na trilha GND da protoboard, com outro jumper até o GND da placa.
  • Resistor de 330 Ω entre o GPIO2 e um lado do LED de resposta.
  • O lado livre do LED na trilha + da protoboard.

No push button de 4 pinos, os pinos do mesmo lado já estão ligados internamente. O botão só conduz em pares diagonalmente opostos: pinos da mesma fileira, nunca o par vizinho da outra fileira.

  1. Grave a resolução e confirme que o serial imprime a linha de cabeçalho contagem | leitura | comentario.
  2. Sem nada no botão, anote o que o serial mostra na coluna leitura. Diga qual nível a entrada está lendo e por que.
  3. Aperte e solte o botão uma vez. Anote quanto a contagem subiu. Se subiu mais de um, esse é o contato vibrando: escreva no caderno que correção de anti-vibração está faltando.
  4. Confira se pinMode(PINO_BOTAO, INPUT_PULLUP) está no setup, e escreva no caderno o que aconteceria se essa linha fosse removida.
  5. Descomente, comente e teste: escreva uma versão sem a comparação && !estadoAnterior, mantendo o if (apertado). Meça quanto a contagem sobe em dez apertos e compare com a versão da resolução.
  6. Troque o botão do GPIO15 para o GPIO4, mantenha o GND e grave. Confirme que funciona igual e escreva por que o resistor de 330 Ω do LED não pode cumprir o papel do pull-up do botão.

Nota: 10 pontos. Critério de fim: um aperto do botão soma exatamente 1 na contagem, e o item 5 está medido e escrito.

Resolucao

// Aula 1 do dia 5: botão, entrada digital, pull-up e anti-vibração.
//
// Três coisas acontecem nesta aula e as três precisam ser mostradas separadas:
// o pino começa como entrada, o pull-up interno segura o nível alto sozinho,
// e o contato do botão vibra no instante do aperto.

#include <Arduino.h>

const int PINO_BOTAO = 15;
const int PINO_LED = 2;
const int ANTIVIBRACAO_MS = 50;   // espera o contato assentar

// O botão só conta depois de passar este tempo sem mudar de estado. É a
// prática do dia: menos de 50 ms é imperceptível para o olho.
unsigned long instanteDaLeitura = 0;
bool estadoAnterior = false;
bool botaoSolto = true;

int contagem = 0;

void setup() {
  // INPUT_PULLUP liga, dentro da placa, um resistor que puxa o pino para 3,3 V
  // quando ninguém está apertando. Sem resistor externo no kit, é este que
  // segura o nível.
  pinMode(PINO_BOTAO, INPUT_PULLUP);
  pinMode(PINO_LED, OUTPUT);

  Serial.begin(115200);
  Serial.println();
  Serial.println("=== dia 5, aula 1: botao com pull-up ===");
  Serial.println();
  Serial.println("Aperte o botao quantas vezes quiser e veja a contagem subir.");
  Serial.println("contagem | leitura | comentario");
}

void loop() {
  unsigned long agora = millis();

  // Guarda de tempo: só olha o botão a cada 50 ms. Fora desse tempo, o
  // botão seria lido milhares de vezes por volta do laço.
  if (agora - instanteDaLeitura >= ANTIVIBRACAO_MS) {
    instanteDaLeitura = agora;

    // Com INPUT_PULLUP a leitura é INVERTIDA: solto devolve HIGH,
    // apertado devolve LOW. Este `== LOW` é o que traduz isso para
    // "apertado", e é onde o aluno costuma errar.
    bool apertado = (digitalRead(PINO_BOTAO) == LOW);

    // Anti-vibração por estado: conta só na BORDA, quando muda de solto para
    // apertado. Sem esta comparação, um aperto só vira uma contagem porque o
    // contato vibra por alguns milissegundos e o laço lê essa vibração umas
    // dez vezes.
    if (apertado && !estadoAnterior) {
      contagem++;
      digitalWrite(PINO_LED, !digitalRead(PINO_LED));
    }
    estadoAnterior = apertado;
    botaoSolto = !apertado;

    Serial.print(contagem);
    Serial.print("   |   ");
    Serial.print(apertado ? "LOW" : "HIGH");
    Serial.print("   |   ");
    Serial.println(botaoSolto ? "solto (pull-up segura)" : "apertado (puxa para GND)");
  }
}

Por que assim e não de outro jeito. O digitalRead está protegido por duas camadas: o if de tempo impede a leitura a cada volta do loop, e a comparação apertado && !estadoAnterior impede a contagem repetida. Uma sem a outra resolve; as duas juntas é o que o botão de verdade exige, e o item 5 prova isso na frente da turma.

A leitura invertida está escrita como digitalRead(PINO_BOTAO) == LOW, e o nome da variável é apertado. Assim o resto do código fala português — if (apertado) em vez de if (digitalRead(...) == LOW) repetido quatro vezes. Nomear a leitura na hora é o que impede o aluno de inverter o sentido em metade do programa.

O digitalWrite(PINO_LED, !digitalRead(PINO_LED)) inverte o LED a cada aperto. Ele usa digitalRead num pino de saída, e isso funciona: em um pino declarado OUTPUT, o digitalRead devolve o nível que foi colocado nele. É o mesmo truque que o alternar do dia 4, e o aluno já viu.

O cabeçalho do setup diz para apertar o botão, e o loop não tem delay. A leitura acontece a cada 50 ms, o suficiente para o olho acompanhar e imperceptível para quem aperta.

Criterios de correcao

CritérioPontos
Botão entre GPIO15 e GND, com par diagonal oposto3 pontos
INPUT_PULLUP no setup e leitura invertida com == LOW3 pontos
Anti-vibração por tempo e por estado presentes3 pontos
Item 5 medido e escrito no caderno1 ponto

Erros comuns

ErroComo apareceCorrecao
Esquecer INPUT_PULLUPContagem pula sozinha, sem ninguem apertar"Sem pull-up o pino fica flutuante e le qualquer coisa. Toda entrada precisa de um resistor que segure o nivel."
Ler apertado como HIGH"Apertou e o LED apagou""Com pull-up, apertado e LOW. O botao puxa para o GND. Inverta a comparacao."
Botão ligado entre pino e 3,3 VNada acontece ao apertar"O botao vai para o GND, não para o positivo. E o pull-up que segura o lado de cima."
Pinos diagonalmente opostos do botãoBotao as vezes funciona, as vezes não"No push button de 4 pinos so conduz o par diagonalmente oposto. Os da mesma fileira já estão ligados."
Anti-vibracao so por tempo, com janela curtaAparicao de contagem dobrada em aperto rapido"Use os dois: tempo para não ler tao direto, e comparacao de borda para contar so na mudanca de estado."
Comparar com == LOW e esquecer o ! do estado anteriorContagem sobe a cada leitura enquanto o botao fica apertado"Falta o !. So conta quando muda de solto para apertado, não a cada leitura enquanto esta apertado."
Usar INPUT_PULLDOWN sem trocar o circuitoLeitura invertida do jeito errado"PULLDOWN também inverte. Com ele, apertado e HIGH e o circuito precisa ir para o 3,3 V."
Colocar 330 Ω no botao achando que e o pull-upBotao funciona inconsistemente em bancada fria"330 Ω e resistor de LED. Pull-up de botao e da ordem de 10 kΩ, ou então o interno da placa."

Desafio extra

Escreva uma função bool botaoApertado(int pino) que encapsule o INPUT_PULLUP e a leitura invertida, devolvendo true quando o botão está apertado. Chame-a em dois botões diferentes, GPIO15 e GPIO4, e faça o LED da placa acender quando os dois estiverem apertados ao mesmo tempo, apagar quando só um estiver e ficar piscando quando nenhum estiver. Escreva no caderno quantas linhas o loop tem com a função e quantas tinha sem ela.

>

A resolucao, compilada

// Aula 1 do dia 5: botão, entrada digital, pull-up e anti-vibração.
//
// Três coisas acontecem nesta aula e as três precisam ser mostradas separadas:
// o pino começa como entrada, o pull-up interno segura o nível alto sozinho,
// e o contato do botão vibra no instante do aperto.

#include <Arduino.h>

const int PINO_BOTAO = 15;
const int PINO_LED = 2;
const int ANTIVIBRACAO_MS = 50;   // espera o contato assentar

// O botão só conta depois de passar este tempo sem mudar de estado. É a
// prática do dia: menos de 50 ms é imperceptível para o olho.
unsigned long instanteDaLeitura = 0;
bool estadoAnterior = false;
bool botaoSolto = true;

int contagem = 0;

void setup() {
  // INPUT_PULLUP liga, dentro da placa, um resistor que puxa o pino para 3,3 V
  // quando ninguém está apertando. Sem resistor externo no kit, é este que
  // segura o nível.
  pinMode(PINO_BOTAO, INPUT_PULLUP);
  pinMode(PINO_LED, OUTPUT);

  Serial.begin(115200);
  Serial.println();
  Serial.println("=== dia 5, aula 1: botao com pull-up ===");
  Serial.println();
  Serial.println("Aperte o botao quantas vezes quiser e veja a contagem subir.");
  Serial.println("contagem | leitura | comentario");
}

void loop() {
  unsigned long agora = millis();

  // Guarda de tempo: só olha o botão a cada 50 ms. Fora desse tempo, o
  // botão seria lido milhares de vezes por volta do laço.
  if (agora - instanteDaLeitura >= ANTIVIBRACAO_MS) {
    instanteDaLeitura = agora;

    // Com INPUT_PULLUP a leitura é INVERTIDA: solto devolve HIGH,
    // apertado devolve LOW. Este `== LOW` é o que traduz isso para
    // "apertado", e é onde o aluno costuma errar.
    bool apertado = (digitalRead(PINO_BOTAO) == LOW);

    // Anti-vibração por estado: conta só na BORDA, quando muda de solto para
    // apertado. Sem esta comparação, um aperto só vira uma contagem porque o
    // contato vibra por alguns milissegundos e o laço lê essa vibração umas
    // dez vezes.
    if (apertado && !estadoAnterior) {
      contagem++;
      digitalWrite(PINO_LED, !digitalRead(PINO_LED));
    }
    estadoAnterior = apertado;
    botaoSolto = !apertado;

    Serial.print(contagem);
    Serial.print("   |   ");
    Serial.print(apertado ? "LOW" : "HIGH");
    Serial.print("   |   ");
    Serial.println(botaoSolto ? "solto (pull-up segura)" : "apertado (puxa para GND)");
  }
}

Sem saída de compilação gravada. Rode python3 validar.py -t 1 dia05 aula1.

Aula 2 — PWM e potenciometro: o analogico entra no digital

Objetivos

  • Explicar o que é PWM e por que ele produz brilho intermediário em um pino digital.
  • Ler o potenciômetro com analogRead e saber que o retorno vai de 0 a 4095.
  • Converter a faixa do ADC para a faixa do PWM com map e ler o resultado como porcentagem.
  • Suavizar a leitura com filtro de média e justificar por que o LED deixa de piscar sozinho.

Material

  • 1 ESP32 DevKit V1 por aluno, com o cabo USB
  • 1 protoboard de 830 pontos e 1 jogo de jumpers por aluno
  • 2 a 5 LEDs de 3,3 V e 2 a 5 resistores de 330 Ω por aluno
  • 1 potenciômetro de 10 kΩ de 3 pinos por aluno
  • 1 módulo de alimentação MB102 por dupla
  • Folha com as três faixas numéricas do dia impressa, uma por dupla

Conceitos

PWM: brilho falso com pino honesto

analogWrite(pino, 255) não coloca 3,3 V no pino. Ele alterna o pino entre HIGH e LOW muito rápido, e a fração de tempo em que fica ligado se chama duty cycle:

ValorDuty cycleO que o olho vê
00%apagado
6425%brinco fraco
12850%meia luz
255100%aceso

O pino continua digital: só existem HIGH e LOW. A sensação de "analogico" vem do olho, que não consegue seguir a piscada e integra o que enxerga. É por isso que o nome é modulação por largura de pulso: o que muda é a largura do pulso, não a altura.

A frequência padrão do ESP32 é alta o suficiente para isso não aparecer. O duty cycle é o que o aluno controla — e o valor vai de 0 a 255, não de 0 a 100 nem de 0 a 4095.

O ADC: o pino que lê tensão

analogRead é o outro sentido da mesma história: em vez de mandar um nível para fora, ele lê uma tensão e devolve um inteiro.

O ADC do ESP32 tem 12 bits, o que dá 4096 níveis — de 0 a 4095. Não é 0 a 4096, e o map com 4095 no fim é o que garante que o valor máximo do potenciômetro chegue em 255 e não em 254.

Os pinos do ADC no ESP32 são os que só fazem entrada: os GPIO32 a GPIO39. O GPIO34 é o mais usado, porque é analógico puro e não tem pull-up nem pull-down interno. Se o aluno ligar o potenciômetro num pino comum como o GPIO2, a leitura sai errada.

map converte faixa, não unidade

int brilho = map(leituraBruta, 0, 4095, 0, 255);

map não converte voltas em luminosidade, nem pessoas emvoted. Ele só recomeça a reta: onde a leitura valia 0 agora vale 0, onde valia 4095 agora vale 255, e o meio é escalado junto.

É por isso que ele não serve para converter volts. Para isso, a conta é multiplicação e divisão: leitura * 3.3 / 4095.0. Com 3 inteiro em vez de 3.3, o resultado perde o resto e dá metade do valor — o mesmo defeito da aula 2 do dia 2, agora com consequência visível.

Filtro de média

O cursor do potenciômetro é uma peça de metal sobre uma trilha. O contato é imperfeito, e a leitura crua salta de um valor para outro sozinha, mesmo com a mão longe do potenciômetro. Com o analogWrite ligado direto nesse número, o LED pisca sozinho num ritmo rápido e constante.

A correção é somar oito leituras e dividir por oito. O resultado é uma média, o ruído se cancela parcialmente, e o LED fica parado. O custo é a latência: a leitura passa a descrever o que o cursor fez recentemente, e não o que ele está fazendo agora.

Atividade

Montagem:

  • O pino do meio do potenciômetro no GPIO34, por jumper.
  • O pino de uma das pontas na trilha GND da protoboard, ligado ao GND da placa.
  • O pino da outra ponta na trilha + da protoboard, ligado ao 3V3 da placa.
  • Resistor de 330 Ω entre o GPIO2 e um lado do LED.
  • O lado livre do LED na mesma trilha + do potenciômetro.

O potenciômetro de 3 pinos tem duas pontas de alimentação e um pino central, que é a varredura. Se o pino central não ir no GPIO34, a leitura sai qualquer coisa.

  1. Grave a resolução e gire o cursor do potenciômetro de uma ponta à outra. Confirme que as quatro colunas do serial andam juntas.
  2. Anote os valores da coluna cru nas duas pontas do curso e no meio do cursor. Diga se os três números são simétricos.
  3. Complete a tabela do caderno: cru vale 4095 na uma ponta e 0 na outra. Quanto vale o pwm em cada uma? Use a fórmula e não a tela.
  4. Remova temporariamente o filtro de média, deixe uma leitura só e grave. Gire o cursor lentamente e anote o que o LED faz. Depois volte o filtro e repita.
  5. Troque analogReadResolution(12) por analogReadResolution(10) e grave. Anote o valor máximo que aparece na coluna cru com o cursor no fim do curso e explique, em uma frase, por que o map com 4095 nunca chega em 255.
  6. Escreva no caderno a linha que converte a leitura do ADC em volts com precisão de centésimos, e diga qual é a diferença entre essa linha e a linha do map da atividade.

Nota: 10 pontos. Critério de fim: o brilho do LED acompanha o cursor de forma contínua e o item 5 está respondido com o número máximo observado.

Resolucao

// Aula 2 do dia 5: PWM e potenciômetro, o analógico entra no digital.
//
// O potentiômetro entrega uma TENSÃO, não um número. O `analogRead` transforma
// essa tensão em um inteiro de 0 a 4095 (12 bits), e o `analogWrite` faz o
// caminho inverso: número de 0 a 255 vira duty cycle. Este sketch liga as
// duas pontas e mostra os dois números crus antes de convertê-los.

#include <Arduino.h>

const int PINO_POTENCIOMETRO = 34;   // GPIO34 é só entrada: serve para o potenciômetro
const int PINO_LED = 2;
const int LEITURA_MAXIMA_ADC = 4095;
const int PWM_MAXIMO = 255;
const int INTERVALO_MS = 100;
const int TAMANHO_DA_AMOSTRA = 8;    // quantas leituras somar antes de dividir

// Instante da última leitura. Esta aula NÃO usa delay para esperar: o laço
// precisa ficar livre para responder ao potenciômetro enquanto imprime.
unsigned long instanteDaLeitura = 0;
int leituraBruta = 0;

void setup() {
  pinMode(PINO_LED, OUTPUT);

  // Pede ao ADC a máxima precisão: 12 bits, de 0 a 4095. Sem esta linha o
  // ESP32 usa 10 bits, de 0 a 1023, e o `map` com 4095 nunca chega no fim.
  analogReadResolution(12);

  // A atenuação é a faixa de tensão que o ADC mede. ADC_11db mede até perto
  // de 3,3 V — é o que o potenciômetro do kit entrega.
  analogSetPinAttenuation(PINO_POTENCIOMETRO, ADC_11db);

  Serial.begin(115200);
  Serial.println();
  Serial.println("=== dia 5, aula 2: PWM e potenciometro ===");
  Serial.println();
  Serial.println("Gire o cursor do potenciometro.");
  Serial.println("cru | volts | pwm | brilho %");
}

void loop() {
  unsigned long agora = millis();

  if (agora - instanteDaLeitura >= INTERVALO_MS) {
    instanteDaLeitura = agora;

    // Filtro de média: soma 8 leituras e divide. O potentiômetro tem um
    // cursor de metal que suja a trilha, e a leitura crua fica pulando de
    // 2047 para 2049 sozinha. A média não deixa o LED piscar sozinho.
    int soma = 0;
    for (int i = 0; i < TAMANHO_DA_AMOSTRA; i++) {
      soma += analogRead(PINO_POTENCIOMETRO);
    }
    int leituraCrua = soma / TAMANHO_DA_AMOSTRA;

    // Guardando em variável em vez de repetir a conta: o `analogWrite` é o
    // único lugar que precisa do número, e ele precisa do valor suavizado.
    leituraBruta = leituraCrua;

    // analogWrite NÃO devolve o que o pino tem: ele MANDA um duty cycle de 0
    // a 255. Escrever 255 é tensão cheia; 0 é desligado.
    int brilho = map(leituraBruta, 0, LEITURA_MAXIMA_ADC, 0, PWM_MAXIMO);
    analogWrite(PINO_LED, brilho);

    float volts = leituraBruta * 3.3 / LEITURA_MAXIMA_ADC;
    int percentual = brilho * 100 / PWM_MAXIMO;

    Serial.print(leituraBruta);
    Serial.print("   |   ");
    Serial.print(volts);
    Serial.print("   |   ");
    Serial.print(brilho);
    Serial.print("   |   ");
    Serial.println(percentual);
  }
}

Por que assim e não de outro jeito. As quatro colunas do serial existem para o professor mostrar que um número físico vira três números diferentes conforme a pergunta que se faz: cru, tensão, duty cycle. O aluno que só imprime o duty cycle não sabe mais se o potenciômetro está no fim ou se o map está errado.

O filtro de média soma oito leituras. Oito foi escolhido porque é o suficiente para abafar o salto sem deixar o LED atrasar; sete ou quinze servem igual, e o professor pode pedir a troca e perguntar por que ainda funciona.

A tensão é calculada com 3.3 e não com map, e a linha está logo abaixo da do brilho. Essa proximidade é o argumento do dia: as duas conversões estão lado a lado, e só uma delas está certa.

A atenuação ADC_11db é o que permite medir até perto de 3,3 V. Sem ela, o ADC lê até cerca de 1,1 V e a leitura satura no meio do curso — o defeito que aparece quando o aluno troca o potenciômetro pelo LDR no dia 8 sem ajustar a linha.

Criterios de correcao

CritérioPontos
Potenciômetro com o pino central no GPIO34 e as pontas em 3V3 e GND3 pontos
pinMode do LED em OUTPUT antes do analogWrite2 pontos
analogReadResolution(12) presente e item 5 respondido com o número medido3 pontos
Filtro de média presente e o efeito da remoção descrito no caderno2 pontos

Erros comuns

ErroComo apareceCorrecao
Potenciometro no GPIO2Leitura sempre perto de zero ou de 4095"O ADC so existe nos pinos GPIO32 a GPIO39. Use o GPIO34."
Usar 4096 no mapBrilho maximo em 254, nunca chega a 255"O ADC vai de 0 a 4095: são 4096 niveis, numerados de zero. O ultimo e 4095."
Escrever 3 inteiro na conversao para voltsTensão aparece com metade do valor"Ponha 3.3. Inteiro descarta o resto da divisão e o número sai pela metade."
Achar que analogWrite manda tensãoAluno acha que 128 e 1,65 volt"analogWrite manda duty cycle, de 0 a 255. Não ha tensão intermedia no pino."
Esquecer analogReadResolution(12)Leitura para em 1023 e o brilho nunca chega ao fim"Sem essa linha o ADC usa 10 bits. Ponha 12 e o número vai até 4095."
Ponto central do potenciometro no GNDLeitura fixa, cursor não muda nada"O pino central e a varredura. Ele vai no pino analogico; as pontas vao para 3V3 e GND."
Filtro de media com divisor erradoBrilho para na metade depois da mediao"A soma foi de oito leituras, então divide por oito. Divisor diferente muda a escala toda."
Fio do 3V3 do potenciometro no 5VLeitura satura em 4095"O ADC do ESP32 vai até 3,3 V. Alimenta o circuito com o 3V3, e o 5V fica para o LED."

Desafio extra

Faça o LED responder ao potenciômetro de forma não linear: em vez do map linear, escreva uma linha que acenda o LED só quando o cursor passar da metade, e aí apague completamente nos últimos 20% do curso. Depois explique no caderno por que essa linha não é um map e qual seria o problema de usar map para chegar nela.

>

A resolucao, compilada

// Aula 2 do dia 5: PWM e potenciômetro, o analógico entra no digital.
//
// O potentiômetro entrega uma TENSÃO, não um número. O `analogRead` transforma
// essa tensão em um inteiro de 0 a 4095 (12 bits), e o `analogWrite` faz o
// caminho inverso: número de 0 a 255 vira duty cycle. Este sketch liga as
// duas pontas e mostra os dois números crus antes de convertê-los.

#include <Arduino.h>

const int PINO_POTENCIOMETRO = 34;   // GPIO34 é só entrada: serve para o potenciômetro
const int PINO_LED = 2;
const int LEITURA_MAXIMA_ADC = 4095;
const int PWM_MAXIMO = 255;
const int INTERVALO_MS = 100;
const int TAMANHO_DA_AMOSTRA = 8;    // quantas leituras somar antes de dividir

// Instante da última leitura. Esta aula NÃO usa delay para esperar: o laço
// precisa ficar livre para responder ao potenciômetro enquanto imprime.
unsigned long instanteDaLeitura = 0;
int leituraBruta = 0;

void setup() {
  pinMode(PINO_LED, OUTPUT);

  // Pede ao ADC a máxima precisão: 12 bits, de 0 a 4095. Sem esta linha o
  // ESP32 usa 10 bits, de 0 a 1023, e o `map` com 4095 nunca chega no fim.
  analogReadResolution(12);

  // A atenuação é a faixa de tensão que o ADC mede. ADC_11db mede até perto
  // de 3,3 V — é o que o potenciômetro do kit entrega.
  analogSetPinAttenuation(PINO_POTENCIOMETRO, ADC_11db);

  Serial.begin(115200);
  Serial.println();
  Serial.println("=== dia 5, aula 2: PWM e potenciometro ===");
  Serial.println();
  Serial.println("Gire o cursor do potenciometro.");
  Serial.println("cru | volts | pwm | brilho %");
}

void loop() {
  unsigned long agora = millis();

  if (agora - instanteDaLeitura >= INTERVALO_MS) {
    instanteDaLeitura = agora;

    // Filtro de média: soma 8 leituras e divide. O potentiômetro tem um
    // cursor de metal que suja a trilha, e a leitura crua fica pulando de
    // 2047 para 2049 sozinha. A média não deixa o LED piscar sozinho.
    int soma = 0;
    for (int i = 0; i < TAMANHO_DA_AMOSTRA; i++) {
      soma += analogRead(PINO_POTENCIOMETRO);
    }
    int leituraCrua = soma / TAMANHO_DA_AMOSTRA;

    // Guardando em variável em vez de repetir a conta: o `analogWrite` é o
    // único lugar que precisa do número, e ele precisa do valor suavizado.
    leituraBruta = leituraCrua;

    // analogWrite NÃO devolve o que o pino tem: ele MANDA um duty cycle de 0
    // a 255. Escrever 255 é tensão cheia; 0 é desligado.
    int brilho = map(leituraBruta, 0, LEITURA_MAXIMA_ADC, 0, PWM_MAXIMO);
    analogWrite(PINO_LED, brilho);

    float volts = leituraBruta * 3.3 / LEITURA_MAXIMA_ADC;
    int percentual = brilho * 100 / PWM_MAXIMO;

    Serial.print(leituraBruta);
    Serial.print("   |   ");
    Serial.print(volts);
    Serial.print("   |   ");
    Serial.print(brilho);
    Serial.print("   |   ");
    Serial.println(percentual);
  }
}

Sem saída de compilação gravada. Rode python3 validar.py -t 1 dia05 aula2.