Kit Iniciante ESP32 Basic Starter Kit AE312 – Curso Completo

Kit Iniciante ESP32 Basic Starter Kit AE312 — Curso Completo com Projetos Práticos

Introdução

Este curso apresenta o Kit Iniciante ESP32 Basic Starter Kit AE312 (desenvolvido e fabricado pela Kuongshun), uma formação técnica e prática integral em computação física, sistemas embarcados e Internet das Coisas (IoT – Internet of Things). O conjunto é estruturado em torno da placa controladora DOIT ESP32 DEVKIT V1, equipada com o módulo de alta integração e alta confiabilidade ESP-WROOM-32 da Espressif Systems. Esse microcontrolador incorpora uma arquitetura de 32 bits de alto desempenho com dois núcleos de processamento Xtensa LX6, interface de conectividade de rádio frequência dupla Wi-Fi 802.11 b/g/n e Bluetooth v4.2 (BR/EDR e BLE – Bluetooth Low Energy), conversores analógico-digitais (ADC – Analog-to-Digital Converter) de aproximações sucessivas de 12 bits de resolução, canais de modulação por largura de pulso (PWM – Pulse Width Modulation) controlados por hardware dedicado através do periférico LEDC (LED Controller), sensores de toque capacitivo integrados (Touch Pins), interfaces seriais assíncronas (UART – Universal Asynchronous Receiver-Transmitter), barramentos síncronos de dois fios I2C (Inter-Integrated Circuit) e barramentos de alta velocidade SPI (Serial Peripheral Interface). O kit é acompanhado por uma seleção criteriosamente projetada de componentes discretos, módulos e transdutores industriais, incluindo transdutores piezelétricos ativos, sensores de presença e deslocamento volumétrico por infravermelho passivo (PIR – Passive Infrared) baseados no circuito integrado BISS0001, sensores de umidade relativa capacitiva e temperatura DHT11, módulos relé com isolamento galvânico por optoacoplador para controle de potência, displays gráficos matriciais de tecnologia OLED (Organic Light Emitting Diode) de 0,96 polegadas controlados pelo driver SSD1306 via barramento I2C, além de chaves tácteis, potenciômetros de precisão e uma protoboard de 830 pontos para prototipagem rápida e segura.

Este material didático foi elaborado sob as mais rigorosas diretrizes da engenharia eletrônica e do projeto de sistemas computacionais embarcados, sendo direcionado a engenheiros, estudantes, técnicos, projetistas de automação e desenvolvedores que buscam dominar os fundamentos do silício do ESP32 até o projeto de servidores de rede modernos e robustos. O itinerário formativo é conduzido em uma progressão contínua e autodidata: inicia-se pela exploração da arquitetura interna de registradores, barramentos de energia e mapeamento de pinos da placa DEVKIT V1; estabelece a cadeia de ferramentas de compilação (toolchain) da IDE Arduino 2.x com instalação de drivers de comunicação USB-Serial CP210x e protocolos de upload via esptool.py; avança pelo estudo analítico de eletrônica fundamental com dimensionamento de circuitos de polarização, filtros de ruído elétrico, condicionamento de sinais analógicos e técnicas de temporização não bloqueante com registradores de contagem; e consolida-se no desenvolvimento de sistemas conectados de automação residencial e telemetria climática em tempo real através de servidores Web HTTP embutidos, cobrindo tanto conexões de soquete síncrono quanto arquiteturas assíncronas de eventos orientados a objetos. Ao concluir este curso definitivo, você dominará integralmente as capacidades do microcontrolador ESP32, tornando-se plenamente capacitado para conceber, montar, codificar, depurar e implantar projetos inteligentes de automação residencial, monitoramento industrial e nós remotos de IoT.

O que você vai aprender:

  • Compreender a topologia de hardware do microcontrolador ESP32, núcleos de processamento Xtensa LX6, distribuição de memória SRAM e memória Flash SPI externa
  • Mapear os 30 pinos da placa DEVKIT V1, identificando restrições críticas de inicialização (Strapping Pins) e limitações do barramento ADC2 durante a operação do rádio Wi-Fi
  • Configurar o ecossistema Arduino IDE 2.x, drivers USB-UART Silicon Labs CP210x e dominar o ritual de gravação manual e automática via circuito DTR/RTS
  • Controlar entradas e saídas digitais em modo push-pull, dimensionando resistores de polarização para LEDs e técnicas de atenuação de ruído
  • Amostrar grandezas analógicas através do conversor ADC de 12 bits, calculando a resolução de tensão teórica e analisando a não linearidade nas extremidades
  • Modular canais de largura de pulso (PWM) através do periférico de hardware LEDC do ESP32, configurando frequência e resolução em bits independentes
  • Construir sistemas de alarme e segurança utilizando o sensor de movimento por infravermelho passivo PIR HC-SR501 com temporização assíncrona não bloqueante via millis()
  • Desenvolver um servidor Web HTTP standalone nativo com o ESP32 em modo Station (STA), servindo páginas HTML5 responsivas e controlando atuadores remotamente
  • Criar interfaces web interativas com seletores de cores em tempo real (HTML5 Color Picker) para controle cromático de LEDs RGB via modulação PWM de três canais
  • Comutar cargas elétricas em corrente contínua e alternada através de módulos relé, dominando o princípio de isolamento óptico galvânico e proteção contra surtos indutivos
  • Implementar sincronização bidirecional de estado em tempo real entre chave física na bancada e interruptor virtual no navegador web via requisições assíncronas AJAX
  • Construir uma estação meteorológica IoT conectada com sensor DHT11, servindo telemetria assíncrona de temperatura e umidade com a biblioteca ESPAsyncWebServer
  • Renderizar textos e primitivas gráficas em display OLED de 0,96 polegadas SSD1306 através do protocolo de comunicação serial I2C com as bibliotecas Adafruit GFX e SSD1306
  • Diagnosticar falhas comuns de compilação, conflitos de bibliotecas, travamentos por Brownout Detector e instabilidades de rede com um guia prático de troubleshooting

Material utilizado: Kit Iniciante ESP32 Basic Starter Kit AE312 disponível na loja RoboBuilders.


Visão Geral do Kit e Arquitetura de Hardware

O núcleo central do Kit Iniciante ESP32 Basic Starter Kit AE312 é a placa de desenvolvimento DOIT ESP32 DEVKIT V1, concebida em torno do poderoso módulo ESP-WROOM-32 da Espressif Systems. Ao contrário dos microcontroladores de 8 bits tradicionais que operam com frequências de clock de 16 MHz e capacidade computacional extremamente restrita, o ESP32 representa um salto de geração monumental, combinando poder computacional de 32 bits, conectividade sem fio de rádio frequência dupla e uma matriz abrangente de periféricos analógicos e digitais de alta precisão em um único encapsulamento monolítico (System-on-Chip – SoC).

A arquitetura computacional interna é baseada em dois núcleos de processamento Xtensa dual-core 32-bit LX6 (denominados Core 0 e Core 1), que podem operar em frequências de clock configuráveis dinamicamente entre 80 MHz e 240 MHz. Essa configuração em multiprocessamento simétrico (SMP – Symmetric Multiprocessing) permite que tarefas pesadas de rede sem fio — tais como a manutenção da pilha de protocolos TCP/IP LwIP, criptografia TLS/SSL e rotinas do rádio Wi-Fi 802.11 b/g/n e Bluetooth v4.2 — sejam executadas no Core 0 sob o escalonador do sistema operacional de tempo real FreeRTOS, enquanto o firmware da aplicação e os laços principais do usuário (setup() e loop()) rodam simultaneamente e sem bloqueios no Core 1. O silício integra 520 KB de memória SRAM interna para alocação dinâmica de dados e variáveis de execução, além de 4 MB (32 Mbits) de memória Flash SPI externa de alta velocidade (quad-SPI operando a até 80 MHz) conectada aos pinos internos do barramento Flash para armazenamento permanente do código binário e do sistema de arquivos embutido (LittleFS ou SPIFFS).

A placa incorpora um conversor USB para UART baseado no circuito integrado Silicon Labs CP2102 (ou CH340 nas revisões compatíveis), regulador linear de tensão de baixa queda (LDO – Low Dropout) de 3,3 V com capacidade nominal de suprir picos de corrente de até 800 mA necessários durante as transmissões de rádio Wi-Fi, conector Micro-USB para alimentação e depuração serial, cristal oscilador de 40 MHz para temporização do sistema e dois botões microtácteis dedicados: o botão de reinicialização de hardware (EN ou RST) e o botão de entrada em modo de gravação manual (BOOT ou GPIO 0).

Estrutura e layout da placa de desenvolvimento ESP32 DEVKIT V1 Mapeamento de pinos e periféricos internos da arquitetura ESP32

Especificações Técnicas Oficiais da Placa DOIT ESP32 DEVKIT V1

A tabela a seguir consolida os parâmetros de engenharia elétrica e características funcionais de operação do hardware utilizado ao longo de todo o curso:

Parâmetro de EngenhariaEspecificação Técnica OficialObservação de Operação
SoC PrincipalEspressif ESP32-D0WDQ6 (Módulo ESP-WROOM-32)Processador dual-core de 32 bits Xtensa LX6
Frequência de Clock da CPU80 MHz a 240 MHz ajustável (padrão de boot: 240 MHz)Até 600 DMIPS de capacidade de processamento
Memória SRAM Interna520 KB (SRAM de dados e instruções)Inclui 8 KB de SRAM rápida no subsistema RTC
Memória Flash SPI Externa4 MB (32 Megabits), barramento Quad-SPIArmazena o firmware executável e sistema LittleFS
Conectividade Wi-Fi802.11 b/g/n (802.11n até 150 Mbps)Faixa de 2,4 GHz com amplificador de potência embutido (+20 dBm)
Conectividade BluetoothBluetooth v4.2 BR/EDR e BLE (Bluetooth Low Energy)Potência de transmissão classe 1, 2 e 3
Tensão Nominal do Silício (VDD)3,3 V DC (faixa operacional estrita: 3,0 V a 3,6 V)Todas as portas GPIO operam rigorosamente em 3,3 V
Tensão de Entrada Recomendada (Vin)5,0 V a 9,0 V DC (máximo absoluto seguro: 12,0 V DC)Regulada internamente para 3,3 V pelo circuito LDO
Alimentação Primária USB5,0 V DC via conector Micro-USB (barramento de 500 mA)Fornecida diretamente pelo computador ou fonte externa
Capacidade de Corrente por GPIO12 mA a 40 mA por pino (recomendado contínuo: ≤ 12 mA)Corrente total somada de todos os pinos: ≤ 1200 mA
Conversor Analógico-Digital (ADC)2 blocos de 12 bits SAR (ADC1: 8 canais, ADC2: 10 canais)Faixa de leitura: 0 V a 3,3 V com atenuação de 11 dB
Conversor Digital-Analógico (DAC)2 canais de 8 bits (GPIO 25 e GPIO 26)Converte valores de 8 bits em tensão analógica contínua
Canais de Modulação PWM (LEDC)16 canais independentes configuráveis via hardwareResolução ajustável de 1 a 16 bits; até 40 MHz
Canais de Toque Capacitivo (Touch)10 sensores capacitivos integrados em GPIOs dedicadasDetecção de aproximação e toque sem botões físicos
Interfaces Seriais UART3 controladores UART de alta velocidade (UART0, UART1, UART2)UART0 multiplexada com o chip CP2102 de programação
Barramentos I2C2 controladores mestres/escravos (padrão: GPIO 21 SDA, GPIO 22 SCL)Suporta taxas Standard (100 kHz) e Fast Mode (400 kHz)
Barramentos SPI3 controladores SPI (SPI, HSPI, VSPI)VSPI padrão do usuário: MOSI 23, MISO 19, SCK 18, CS 5
Coprocessador ULPCoprocessador de Ultra-Baixo Consumo baseado em FSMMonitora sensores em modo Deep Sleep consumindo ~10 µA
Temperatura de Operação-40 °C a +85 °CAdequado para ambientes industriais e embarcados

Diagrama de Pinagem e Mapeamento Completo de GPIOs (30 Pinos)

A placa DOIT ESP32 DEVKIT V1 de 30 pinos organiza seus terminais em duas fileiras paralelas de 15 pinos em passo padrão de 2,54 mm, ideais para fixação em protoboard. Compreender a função de cada terminal e suas particularidades elétricas é o primeiro passo para o sucesso no desenvolvimento e para evitar a queima do componente.

Diagrama de pinagem (Pinout) detalhado do ESP32 DEVKIT V1 30 pinos Distribuição de funções de entrada analógica ADC e periféricos no barramento de GPIOs
Mapeamento dos canais de interrupção e registradores de strapping no boot Mapeamento dos canais de conversão digital-analógica DAC e registradores RTC

A tabela a seguir apresenta o mapeamento sistemático de todos os 30 pinos físicos da placa DEVKIT V1:

Pino FísicoNome / IdentificadorTipo de PinoBloco Analógico / PeriféricoFunção de Boot / Cuidados CríticosAplicação Típica no Curso
Pino 1ENEntrada ResetLinha de Habilitação do SilícioPuxado para VCC via resistor pull-up; nível LOW reiniciaBotão de reset físico e circuito DTR
Pino 2GPIO 36 (VP)Entrada PuraADC1_CH0 / Sensor Hall / RTCNão possui circuito de saída digital nem resistores pull-upLeitura analógica de alta sensibilidade
Pino 3GPIO 39 (VN)Entrada PuraADC1_CH3 / Sensor Hall / RTCNão possui circuito de saída digital nem resistores pull-upLeitura de sinais externos puros
Pino 4GPIO 34Entrada PuraADC1_CH6 / RTCSomente entrada; sem pull-up internoEntrada analógica / chave de entrada
Pino 5GPIO 35Entrada PuraADC1_CH7 / RTCSomente entrada; sem pull-up internoEntrada analógica / leitura de bateria
Pino 6GPIO 32Entrada / SaídaADC1_CH4 / Touch 9 / RTC 9Seguro para uso geral em qualquer modoLeitura analógica ou acionamento geral
Pino 7GPIO 33Entrada / SaídaADC1_CH5 / Touch 8 / RTC 8Seguro para uso geral em qualquer modoLeitura analógica ou acionamento geral
Pino 8GPIO 25Entrada / SaídaADC2_CH8 / DAC_1 / RTC 6Converte valores de 8 bits em tensão analógica realSaída analógica DAC ou I/O
Pino 9GPIO 26Entrada / SaídaADC2_CH9 / DAC_2 / RTC 7Inoperante como ADC quando o Wi-Fi está ligadoCanal de chaveamento e controle
Pino 10GPIO 27Entrada / SaídaADC2_CH7 / Touch 7 / RTC 17Inoperante como ADC quando o Wi-Fi está ligadoEntrada do sensor de movimento PIR
Pino 11GPIO 14Entrada / SaídaADC2_CH6 / Touch 6 / HSPI_CLKEmite clock durante boot; cuidado com cargas sensíveisBarramento SPI auxiliar ou I/O
Pino 12GPIO 12Entrada / SaídaADC2_CH5 / Touch 5 / HSPI_QStrapping Pin (MTDI): Deve estar em LOW no boot para Flash 3.3VI/O geral com cautela
Pino 13GPIO 13Entrada / SaídaADC2_CH4 / Touch 4 / HSPI_IDSeguro para uso geralI/O de alta velocidade
Pino 14GNDAlimentaçãoBarramento de Terra de ReferênciaPotencial de 0 V comum de referência do sistemaBarramento comum da protoboard
Pino 15VinAlimentaçãoEntrada de Tensão Externa DCConectado à entrada do LDO (5 V a 9 V DC); bypass para USBAlimentação de módulos e sensores de 5 V
Pino 163V3AlimentaçãoSaída Regulada de 3,3 V DCSaída do regulador LDO interno (máx. 800 mA somado)Alimentação do ESP32, OLED e sensores 3.3V
Pino 17GNDAlimentaçãoBarramento de Terra de ReferênciaPotencial de 0 V comum de referência do sistemaBarramento comum da protoboard
Pino 18GPIO 15Entrada / SaídaADC2_CH3 / Touch 3 / HSPI_CSStrapping Pin (MTDO): Puxado para HIGH emite log de boot serialLinha de controle ou I/O
Pino 19GPIO 2Entrada / SaídaADC2_CH2 / Touch 2 / LED InternoStrapping Pin: Deve estar solto ou em LOW para entrar em flashLED azul integrado na placa DEVKIT
Pino 20GPIO 0Entrada / SaídaADC2_CH1 / Touch 1 / RTC 11Strapping Pin de Boot: Pressione botão BOOT para forçar LOWGravação de firmware via UART
Pino 21GPIO 4Entrada / SaídaADC2_CH0 / Touch 0 / RTC 10Seguro para uso geral; multiplexado no barramento TouchEntrada de botão, PWM e potenciômetro
Pino 22GPIO 16 (RX2)Entrada / SaídaUART2_RXLinha padrão de recepção de dados da Serial2Comunicação UART secundária
Pino 23GPIO 17 (TX2)Entrada / SaídaUART2_TXLinha padrão de transmissão de dados da Serial2Comunicação UART secundária
Pino 24GPIO 5Entrada / SaídaVSPI_CS / RTC 15Strapping Pin: Emite pulsos PWM transitórios no bootControle de LED digital e saídas
Pino 25GPIO 18Entrada / SaídaVSPI_CLKLinha de clock padrão do barramento VSPIBarramento de alta velocidade SPI
Pino 26GPIO 19Entrada / SaídaVSPI_MISOLinha de entrada Master-In Slave-Out do barramento VSPILeitura de cartões SD ou sensores SPI
Pino 27GPIO 21Entrada / SaídaI2C_SDALinha de dados seriais do barramento I2C padrãoConexão I2C do display OLED SSD1306
Pino 28GPIO 3 (RX0)Entrada / SaídaUART0_RXConectada ao conversor USB-Serial para programaçãoMonitor Serial e upload de sketch
Pino 29GPIO 1 (TX0)Entrada / SaídaUART0_TXConectada ao conversor USB-Serial para programaçãoMonitor Serial e mensagens de debug
Pino 30GPIO 22Entrada / SaídaI2C_SCLLinha de clock serial do barramento I2C padrãoConexão I2C do display OLED SSD1306

⚠️ Atenção — Regra Inviolável de Hardware:

  1. Conflito de Concorrência entre ADC2 e Rádio Wi-Fi: O bloco interno ADC2 (canais GPIOs 0, 2, 4, 12, 13, 14, 15, 25, 26 e 27) compartilha circuitos internos e amplificadores operacionais com a seção de rádio frequência (Wi-Fi e Bluetooth). Por essa razão, no exato instante em que o firmware ativa a pilha de rádio com WiFi.begin(), qualquer leitura executada via analogRead() nos pinos do ADC2 retornará invariavelmente valores espúrios ou falhará. Para leituras analógicas contínuas em projetos IoT conectados, utilize exclusivamente os pinos do bloco ADC1 (GPIOs 32, 33, 34, 35, 36 e 39).
  2. Pinos Somente Entrada (Input Only): Os pinos GPIO 34, 35, 36 e 39 não possuem transistores complementares de saída na etapa interna de I/O nem resistores internos de pull-up ou pull-down configuráveis por software. Eles nunca devem ser configurados como OUTPUT.
  3. Tensão Máxima de Entrada: Todos os pinos GPIO do ESP32 são compatíveis estritamente com 3,3 V. Aplicar sinais de 5,0 V diretamente sobre qualquer pino do silício sem divisores resistivos ou transistores de conversão de nível lógico queimará instantaneamente os diodos de proteção de clamp e a porta interna do microcontrolador.

Inventário Físico do Kit (Packing List)

O Kit Iniciante ESP32 Basic Starter Kit AE312 traz em sua embalagem organizadora todos os elementos estruturais e eletroeletrônicos necessários para a execução completa das 10 lições práticas do curso. Abaixo encontra-se o inventário fotográfico oficial e a discriminação itemizada das peças:

Inventário completo de componentes do ESP32 Basic Starter Kit AE312

A tabela a seguir discrimina quantitativamente todos os itens do conjunto:

ItemComponente / Descrição TécnicaQuantidadeFunção Principal nas Lições
1Placa de Desenvolvimento DOIT ESP32 DEVKIT V1 (ESP-WROOM-32)1 unidadeMicrocontrolador mestre de 32 bits dual-core com Wi-Fi/Bluetooth
2Cabo de Comunicação e Alimentação Micro-USB para USB-A1 unidadeConexão com o computador para upload de firmware e depuração serial
3Display Gráfico OLED 0,96 Polegadas SSD1306 (128x64 pixels, I2C)1 unidadeInterface homem-máquina (IHM) gráfica para exibição de dados e telemetria
4Sensor de Presença por Infravermelho Passivo PIR HC-SR5011 unidadeDetecção volumétrica de presença e movimento térmico humano
5Sensor Digital de Temperatura e Umidade Relativa DHT111 unidadeMonitoramento de variáveis termo-higrométricas do ambiente
6Módulo Relé de 1 Canal 5 V com Isolamento Óptico por Optoacoplador1 unidadeComutação de cargas de potência AC (lâmpadas) e DC com isolamento galvânico
7Buzzer Piezelétrico Ativo de 5 V DC1 unidadeTransdutor acústico para emissão de alertas sonoros e alarmes
8Potenciômetro Rotativo Linear de 10 kΩ com Eixo Estriado1 unidadeDivisor de tensão resistivo para amostragem analógica via ADC
9Diodo Emissor de Luz (LED) RGB de Cátodo Comum de 5 mm1 unidadeSíntese aditiva de cores através de três canais PWM independentes
10Diodo Emissor de Luz (LED) Difuso Vermelho de 5 mm3 unidadesSinalização visual de estado lógico e indicação de alarmes
11Diodo Emissor de Luz (LED) Difuso Verde de 5 mm3 unidadesSinalização visual de estado lógico e confirmação de conexões
12Diodo Emissor de Luz (LED) Difuso Azul de 5 mm3 unidadesSinalização visual de estado lógico e canais de saída
13Chaves Tácteis Tipo Pushbutton (4 terminais com capa)3 unidadesEntradas digitais por ação momentânea do usuário
14Resistor de Filme de Carbono de 220 Ω (1/4 W, tolerância 5%)10 unidadesLimitação de corrente direta de polarização para LEDs
15Resistor de Filme de Carbono de 10 kΩ (1/4 W, tolerância 5%)5 unidadesPolarização passiva de pull-down para botões e pull-up para barramentos
16Resistor de Filme de Carbono de 1 kΩ (1/4 W, tolerância 5%)5 unidadesAtenuação e casamento de impedância de circuitos de entrada
17Protoboard Profissional de 830 Pontos com Linhas de Alimentação Duplas1 unidadePlataforma para prototipagem de circuitos eletrônicos sem solda
18Kit de Cabos Jumper Flexíveis Macho-Macho de Diversos Comprimentos40 unidadesRoteamento de sinais e alimentação na protoboard
19Cabos Jumper Flexíveis Macho-Fêmea de 20 cm10 unidadesConexão entre a protoboard e os pinos do módulo relé e sensores
20Estojo Organizador Plástico com Travas de Segurança1 unidadeAcomodação, proteção mecânica e transporte dos componentes
TotalSomatória Consolidada de Itens Físicos90 itensConjunto completo para 10 projetos didáticos completos

Preparação de Ambiente e Instalação de Drivers

Antes de iniciar a codificação dos projetos práticos, é fundamental estabelecer um ambiente de desenvolvimento robusto, calibrado e com as versões de bibliotecas e compiladores devidamente pinadas. A heterogeneidade de versões nos pacotes de suporte a placas é uma das principais causas de erros de compilação em microcontroladores ESP32.

Download e Instalação da IDE Arduino 2.x

O desenvolvimento de firmware para o ESP32 pode ser conduzido na versão moderna da Arduino IDE 2.3.x (disponível para Windows, Linux e macOS no site oficial arduino.cc). A versão 2.x introduz autocompletar inteligente (IntelliSense), compilador incremental baseado em Language Server Protocol (LSP) e ferramenta de depuração avançada.

Instalação do Driver USB-Serial CP210x

A placa DOIT ESP32 DEVKIT V1 utiliza o circuito integrado Silicon Labs CP2102 (ou CP210x) para converter a interface USB do computador na interface UART síncrona/assíncrona do microcontrolador (pinos TX0 e RX0).

  1. Caso o sistema operacional não reconheça automaticamente a porta ao conectar o cabo Micro-USB, faça o download do driver oficial diretamente da Silicon Labs: Silicon Labs CP210x VCP Drivers.
  2. Execute o instalador CP210xVCPInstaller_x64.exe (no Windows de 64 bits) e siga as instruções na tela.
  3. No Windows, abra o Gerenciador de Dispositivos e expanda a seção Portas (COM e LPT). Ao conectar a placa, você verá o item Silicon Labs CP210x USB to UART Bridge (COMx). Anote o número da porta COM associada.

Instalação do Pacote de Placas da Espressif na IDE Arduino

Para habilitar a compilação do código C/C++ da arquitetura Xtensa do ESP32 na IDE Arduino, devemos adicionar o repositório de placas da Espressif:

  1. Abra a IDE Arduino e navegue até o menu Arquivo > Preferências (ou pressione Ctrl + Vírgula).
  2. No campo URLs do Gerenciador de Placas Adicionais, insira rigorosamente a URL oficial do pacote estável da Espressif:
    https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
    (Caso já existam outras URLs no campo, separe-as com uma vírgula ou clique no ícone lateral para adicionar em uma nova linha).
Configuração de URLs adicionais de placas nas preferências da IDE Arduino Pesquisa do pacote de placas ESP32 no Gerenciador de Placas
  1. Clique em OK para fechar a tela de preferências.
  2. No menu lateral esquerdo da IDE Arduino, clique no ícone de Gerenciador de Placas (Boards Manager) ou acesse Ferramentas > Placa > Gerenciador de Placas....
  3. Na caixa de busca superior, digite esp32. Localize o pacote oficial mantido pela Espressif Systems.
  4. Selecione a versão estável 2.0.14 (ou a versão recomendada do kit) e clique em Instalar. Aguarde o download completo dos compiladores de cadeia cruzada (xtensa-esp32-elf-gcc), ferramentas de upload (esptool.py) e cabeçalhos de sistema.
Instalação do pacote oficial de placas da Espressif Systems Seleção da placa DOIT ESP32 DEVKIT V1 no menu Ferramentas

Configuração de Parâmetros de Placa e Ritual de Gravação

Com o pacote devidamente instalado, configure as opções do compilador no menu Ferramentas:

  • Placa: DOIT ESP32 DEVKIT V1
  • CPU Frequency: 240MHz (WiFi/BT)
  • Flash Frequency: 80MHz
  • Flash Mode: QIO
  • Flash Size: 4MB (32Mb)
  • Partition Scheme: Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)
  • Core Debug Level: Nenhum (ou Aviso durante depuração)
  • Upload Speed: 921600 (se houver erro de sincronismo, reduza temporariamente para 115200)
  • Porta: Selecione a porta correspondente à placa (ex: COM3 ou COM4).
Identificação e seleção da porta de comunicação serial COM Abertura de sketch de teste para verificação da cadeia de compilação

O Ritual de Upload e o Botão BOOT

A placa DEVKIT V1 possui um circuito automático de auto-reset constituído por dois transistores bipolares NPN conectados aos sinais DTR (Data Terminal Ready) e RTS (Request to Send) da interface USB-Serial CP2102. Esse circuito manipula automaticamente os níveis lógicos das linhas EN (Reset) e GPIO 0 (BOOT).

No entanto, em diversos computadores e cabos com capacitância parasita elevada, o pulso transitório de descida na linha GPIO 0 pode falhar em sincronizar com a abertura do carregador de inicialização (ROM Bootloader). Quando isso ocorre, o console de compilação da IDE exibe a mensagem de espera cíclica:

Connecting........_____....._____.....
Ritual de pressionamento do botão BOOT durante o upload do firmware Confirmação de upload com sucesso executado pela ferramenta esptool.py

Quando essa sequência de pontos e traços surgir no rodapé da IDE, mantenha o botão BOOT pressionado firmemente na placa ESP32 até que a linha mude para Writing at 0x00010000... (100%). Nesse instante, solte imediatamente o botão BOOT. O processo de gravação prosseguirá até o status final Hard resetting via RTS pin..., confirmando a reinicialização bem-sucedida do firmware.

Abertura do Monitor Serial e ajuste de velocidade para 115200 bps Depuração e recepção de dados seriais em tempo real

Tabela-Mestre de Bibliotecas do Curso

A tabela a seguir consolida todas as bibliotecas de software utilizadas ao longo das lições deste curso, com versões testadas e homologadas para a versão 2.0.14 do núcleo ESP32, garantindo imunidade total a quebras de API:

Biblioteca (#include)Buscar no GerenciadorVersão Usada no CursoDownload ZIP (Espelho Oficial)Lições que Utilizam
<WiFi.h>Embutida no pacote oficial ESP322.0.14 (Nativa do Core)Já inclusa na instalação do pacote de placasLições 5, 6, 7, 8 e 9
<AsyncTCP.h>AsyncTCP por me-no-dev / dvarrel1.1.4dvarrel/AsyncTCPLições 7, 8 e 9
<ESPAsyncWebServer.h>ESPAsyncWebServer por me-no-dev1.2.4lacamera/ESPAsyncWebServerLições 7, 8 e 9
<DHT.h>DHT sensor library por Adafruit1.4.6adafruit/DHT-sensor-libraryLição 9
<Adafruit_Sensor.h>Adafruit Unified Sensor por Adafruit1.1.14adafruit/Adafruit_SensorLição 9 (Dependência do DHT)
<Adafruit_SSD1306.h>Adafruit SSD1306 por Adafruit2.5.11adafruit/Adafruit_SSD1306Lição 10
<Adafruit_GFX.h>Adafruit GFX Library por Adafruit1.11.10adafruit/Adafruit-GFX-LibraryLição 10 (Dependência do OLED)
<Wire.h>Embutida no pacote oficial ESP322.0.14 (Nativa do Core)Já inclusa na instalação do pacote de placasLição 10

Lição 1: Entradas e Saídas Digitais (GPIOs, LEDs e Botões)

O controle de entradas e saídas de uso geral (GPIO – General Purpose Input/Output) constitui o alicerce fundamental de qualquer projeto de automação e sistemas embarcados. Nesta primeira lição prática, você dominará o chaveamento digital da placa DOIT ESP32 DEVKIT V1, manipulando simultaneamente uma saída digital em modo push-pull para acionamento de um diodo emissor de luz (LED) e uma entrada digital para amostragem do estado mecânico de uma chave táctil (pushbutton).

Teoria dos Circuitos de I/O e Polarização de Semicondutores

Cada pino GPIO do ESP32 é conectado a um circuito transceptor CMOS composto por dois transistores de efeito de campo complementares (um PMOS conectado ao barramento de alimentação de 3,3 V e um NMOS conectado ao barramento de terra GND). Quando um pino é configurado como OUTPUT através da função pinMode(pin, OUTPUT) e recebe o comando digitalWrite(pin, HIGH), o transistor PMOS superior é saturado, conectando diretamente o pino ao potencial de 3,3 V. Inversamente, quando recebe digitalWrite(pin, LOW), o transistor NMOS inferior entra em condução, drenando a corrente para o terra (0 V).

Ao acionar um diodo emissor de luz (LED), é estritamente obrigatório inserir em série um resistor limitador de corrente. Um LED é um semicondutor de junção P-N cuja relação entre corrente e tensão é exponencial: uma vez atingida a tensão de condução direta (VdV_d), qualquer incremento minúsculo de tensão causará um aumento descontrolado de corrente que queimará instantaneamente o LED e a porta de saída do ESP32.

A dedução matemática do valor da resistência limitadora é realizada aplicando a Lei de Ohm e a Segunda Lei de Kirchhoff (Lei das Malhas):

Vresistor=VCC−VdV_{resistor} = V_{CC} - V_d

R=VCC−VdIdR = \frac{V_{CC} - V_d}{I_d}

Para um LED difuso vermelho comum presente no kit:

  • Tensão de alimentação do microcontrolador: VCC=3,3 VV_{CC} = 3{,}3\,\text{V}
  • Tensão de condução direta típica do LED vermelho: Vd≈1,9 VV_d \approx 1{,}9\,\text{V}
  • Corrente direta de operação nominal recomendada: Id≈6,3 mA=0,00636 AI_d \approx 6{,}3\,\text{mA} = 0{,}00636\,\text{A}

Substituindo os parâmetros na equação de dimensionamento:

R=3,3 V−1,9 V0,00636 A=1,4 V0,00636 A≈220 ΩR = \frac{3{,}3\,\text{V} - 1{,}9\,\text{V}}{0{,}00636\,\text{A}} = \frac{1{,}4\,\text{V}}{0{,}00636\,\text{A}} \approx 220\,\Omega

A potência dissipada sobre o corpo do resistor pelo efeito Joule é dada por:

PR=R⋅Id2=220 Ω⋅(0,00636 A)2≈0,0089 W=8,9 mWP_R = R \cdot I_d^2 = 220\,\Omega \cdot (0{,}00636\,\text{A})^2 \approx 0{,}0089\,\text{W} = 8{,}9\,\text{mW}

Como a potência calculada de 8,9 mW8{,}9\,\text{mW} é ordens de grandeza inferior à capacidade máxima de dissipação do resistor de filme de carbono de 1/4 W1/4\,\text{W} (250 mW250\,\text{mW}) fornecido no kit, a operação térmica ocorre em regime perfeitamente frio e estável.

Na entrada digital (chave táctil), quando os contatos mecânicos estão abertos, o pino fica desconectado de qualquer potencial fixo, entrando em estado de alta impedância (Floating State). Nessa condição, o pino atua como uma antena suscetível a ruídos eletromagnéticos ambientes, alternando aleatoriamente entre 0 e 1. Para forçar um nível lógico baixo (0 V) garantido durante o repouso da chave, emprega-se uma configuração de resistor de pull-down externo de 10 kΩ. Ao pressionar o botão, o pino é conectado aos 3,3 V, estabelecendo o nível lógico alto estável.

Componentes Necessários para a Lição 1

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6 3.3V
Diodo Emissor de Luz (LED) Vermelho1 unidadeEncapsulamento difuso de 5 mm, Vd=1,9 VV_d = 1{,}9\,\text{V}
Resistor de Filme de Carbono1 unidade220 Ω220\,\Omega, 1/4 W1/4\,\text{W}, tolerância 5% (Vermelho-Vermelho-Marrom)
Chave Táctil Pushbutton1 unidadeMicroswitch momentâneo de 4 terminais
Resistor de Filme de Carbono1 unidade10 kΩ10\,\text{k}\Omega, 1/4 W1/4\,\text{W}, tolerância 5% (Marrom-Preto-Laranja)
Protoboard de 830 Pontos1 unidadeBarramento duplo de alimentação lateral
Cabos Jumper Flexíveis5 unidadesConexões Macho-Macho

Diagrama Esquemático e Montagem Prática na Protoboard

Conecte os componentes na protoboard seguindo o esquema elétrico e o diagrama de conexões ilustrados abaixo. Posicione a placa ESP32 no centro da protoboard, permitindo o acesso aos barramentos de pinos de ambos os lados.

Esquema elétrico de ligação do botão táctil e LED limitador Diagrama prático de montagem na protoboard para o Projeto 1

A tabela a seguir discrimina as conexões ponto a ponto:

Terminal de OrigemTerminal de DestinoLinha / Pino ESP32Função do Sinal
Ânodo do LED Vermelho (Terminal Longo)Terminal 1 do Resistor 220 Ω220\,\OmegaLinha intermediária protoboardNó de conexão da malha do LED
Terminal 2 do Resistor 220 Ω220\,\OmegaPino Digital do MicrocontroladorGPIO 5Saída digital de acionamento do LED
Cátodo do LED Vermelho (Terminal Curto)Barramento Negativo da ProtoboardGNDReferência de terra (0 V)
Terminal A do PushbuttonBarramento Positivo de Alimentação3V3Nível lógico alto de alimentação (3,3 V)
Terminal B do PushbuttonTerminal 1 do Resistor 10 kΩ10\,\text{k}\OmegaGPIO 4Entrada digital de leitura da chave
Terminal 2 do Resistor 10 kΩ10\,\text{k}\OmegaBarramento Negativo da ProtoboardGNDResistor de pull-down para o terra

📦 Bibliotecas desta lição: nenhuma — o sketch faz uso exclusivo das rotinas nativas de manipulação de registradores digitais da IDE Arduino (pinMode, digitalRead e digitalWrite), dispensando qualquer download externo.

Código-Fonte Completo Comentado Linha a Linha

Abra a IDE Arduino, crie um novo sketch (Arquivo > Novo Sketch) e insira o código abaixo, integralmente documentado em português:

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 1: Entradas e Saidas Digitais (Pushbutton e LED)
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Definicao constante do pino GPIO conectado a chave tactil pushbutton
const int buttonPin = 4;  // Pino GPIO 4 configurado como entrada digital

// Definicao constante do pino GPIO conectado ao anodo do diodo emissor de luz (LED)
const int ledPin = 5;     // Pino GPIO 5 configurado como saida digital

// Declaracao de variavel inteira global para armazenar o estado logico lido da chave
int buttonState = 0;      // Armazena 0 (LOW / GND) quando solto ou 1 (HIGH / 3.3V) quando pressionado

// Funcao de configuracao inicial do microcontrolador executada uma unica vez no boot
void setup() {
  // Inicializa o canal de comunicacao serial assincrono na velocidade de 115200 bps
  Serial.begin(115200);
  
  // Configura o pino GPIO 4 como entrada digital de alta impedancia
  pinMode(buttonPin, INPUT);
  
  // Configura o pino GPIO 5 como saida digital push-pull de baixa impedancia
  pinMode(ledPin, OUTPUT);
}

// Laco de execucao continua e concorrente do firmware
void loop() {
  // Realiza a amostragem imediata do nivel logico presente no pino GPIO 4
  buttonState = digitalRead(buttonPin);
  
  // Imprime no Monitor Serial o estado numerico atual da chave para fins de telemetria
  Serial.print("Estado do Botao: ");
  Serial.println(buttonState);

  // Estrutura de decisao condicional: verifica se o botao encontra-se acionado (HIGH)
  if (buttonState == HIGH) {
    // Caso verdadeiro: satura o transistor PMOS do GPIO 5, fornecendo 3,3V e acendendo o LED
    digitalWrite(ledPin, HIGH);
  } else {
    // Caso falso: comuta o pino GPIO 5 para o potencial de terra (0V), apagando o LED
    digitalWrite(ledPin, LOW);
  }
  
  // Insere uma pequena pausa temporal de 20 milissegundos para estabilizacao do laco
  delay(20);
}

Gravação, Validação Prática e Análise de Funcionamento

  1. Conecte o cabo Micro-USB à porta USB do seu computador e selecione a porta COM correta em Ferramentas > Porta.
  2. Clique no botão Carregar (Upload). Se o console exibir a sequência Connecting........_____, pressione e segure o botão BOOT na placa ESP32 até que a gravação inicie.
  3. Abra o Monitor Serial (Ctrl + Shift + M) e certifique-se de que a taxa de transmissão esteja ajustada rigorosamente para 115200 baud.
  4. Em repouso, o LED permanece totalmente apagado e o terminal exibe sucessivamente a mensagem Estado do Botao: 0.
  5. Pressione o botão físico: no exato instante da compressão mecânica, o LED vermelho acende com brilho intenso e o Monitor Serial passa a exibir Estado do Botao: 1. Ao soltar o botão, o LED apaga imediatamente.
Demonstração do LED desligado em repouso Demonstração do LED aceso ao pressionar o botão táctil

💡 Dica de Engenharia — Pull-Up Interno: O microcontrolador ESP32 possui resistores de pull-up internos ativáveis por software (pinMode(buttonPin, INPUT_PULLUP)). Quando configurado em INPUT_PULLUP, o resistor externo de 10 kΩ torna-se dispensável e a outra extremidade da chave deve ser conectada diretamente ao GND. Nessa topologia, a lógica torna-se invertida: solto lê HIGH e pressionado lê LOW.


Lição 2: Entradas Analógicas e Conversão ADC de 12 Bits

No mundo real, as grandezas físicas — temperatura, luminosidade, pressão, posição angular de eixos e nível de carga de baterias — variam de forma contínua no tempo, ao contrário dos sinais digitais que assumem apenas dois estados discretos. Para interpretar essas variáveis, o microcontrolador ESP32 conta com um periférico conversor analógico-digital (ADC – Analog-to-Digital Converter) de alto desempenho e resolução programável.

Arquitetura do SAR ADC de 12 Bits e Não Linearidade

O conversor analógico-digital do ESP32 opera sob o princípio de Registrador de Aproximações Sucessivas (SAR – Successive Approximation Register). Nesse processo, um comparador analógico interno de alta velocidade compara a tensão desconhecida de entrada contra uma tensão de referência gerada por uma rede capacitiva ponderada binariamente (DAC interno), determinando bit a bit o valor binário correspondente do bit mais significativo (MSB) até o bit menos significativo (LSB).

Diferentemente do Arduino Uno tradicional (cujo ADC possui resolução de 10 bits, dividindo a faixa em 1024 níveis), o ADC do ESP32 opera por padrão com 12 bits de resolução, mapeando a faixa de tensão analógica em 212=40962^{12} = 4096 níveis discretos de quantização (compreendidos entre 00 e 40954095).

A resolução teórica de tensão (ΔV\Delta V) para uma faixa nominal de 3,3 V3{,}3\,\text{V} com atenuação padrão de 11 dB é calculada por:

ΔV=Vref2N−1=3,3 V4095≈0,8058 mV/LSB\Delta V = \frac{V_{ref}}{2^N - 1} = \frac{3{,}3\,\text{V}}{4095} \approx 0{,}8058\,\text{mV/LSB}

Para converter a leitura digital bruta de 12 bits (LeituraADC\text{Leitura}_{ADC}) de volta ao seu valor físico de tensão correspondente em volts (VmedidoV_{medido}), aplica-se a relação direta:

Vmedido=LeituraADC4095×VrefV_{medido} = \frac{\text{Leitura}_{ADC}}{4095} \times V_{ref}

Vmedido=LeituraADC4095×3,3 VV_{medido} = \frac{\text{Leitura}_{ADC}}{4095} \times 3{,}3\,\text{V}

A Curva de Não Linearidade Real do ESP32

Em termos práticos de engenharia, o conversor ADC do ESP32 exibe uma curva de transferência com acentuada não linearidade nas extremidades superior e inferior:

  1. Zona Morta Inferior (0 V a ~100 mV): Tensões compreendidas entre 0 V e aproximadamente 0,1 V são lidas como 0 absoluto pelo conversor.
  2. Zona de Saturação Superior (~3,15 V a 3,3 V): Tensões analógicas acima de aproximadamente 3,15 V atingem o teto máximo de 4095 antes que a tensão de entrada atinja os 3,3 V nominais.
  3. Região Linear Central (0,15 V a 3,10 V): Entre 150 mV e 3,1 V, a resposta do ADC é altamente satisfatória para potenciômetros, termistores e sensores de automação.

Componentes Necessários para a Lição 2

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6
Potenciômetro Rotativo Linear1 unidade10 kΩ10\,\text{k}\Omega, terminal central ajustável de 0 a 3,3 V
Protoboard de 830 Pontos1 unidadeMontagem do divisor resistivo
Cabos Jumper Flexíveis3 unidadesConexões Macho-Macho

Diagrama Esquemático e Montagem Prática

Um potenciômetro rotativo atua como um divisor de tensão resistivo ajustável. Os dois terminais externos são conectados respectivamente ao barramento de 3,3 V e ao terra GND, enquanto o terminal central (cursor móvel) coleta uma fração da tensão total proporcional ao ângulo de rotação mecânica do eixo.

Diagrama esquemático do divisor de tensão resistivo com potenciômetro Montagem física do potenciômetro conectado ao pino analógico do ESP32

A tabela a seguir orienta as conexões físicas na protoboard:

Terminal do PotenciômetroPonto de Ligação na ProtoboardLinha / Pino ESP32Função do Sinal
Terminal Esquerdo (Pino 1)Barramento Positivo de Tensão3V3Tensão de referência superior (3,3 V DC)
Terminal Central (Cursor / Pino 2)Linha do Barramento de SinalGPIO 4 (ADC2_CH0)Tensão analógica variável (0 V a 3,3 V)
Terminal Direito (Pino 3)Barramento Negativo de TerraGNDReferência de potencial de terra (0 V)

📦 Bibliotecas desta lição: nenhuma — a leitura analógica utiliza a função interna analogRead() do pacote de placas oficial da Espressif, operando sem dependências de código externo.

Código-Fonte Completo Comentado Linha a Linha

Digite o código abaixo na IDE Arduino e compile para a placa DEVKIT V1:

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 2: Entradas Analogicas e Conversao ADC de 12 Bits
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Define a constante do pino GPIO conectado ao terminal central do potenciometro
const int potPin = 4; // GPIO 4 (Canal interno ADC2_CH0 do ESP32)

// Variavel inteira global para armazenar a leitura numerica bruta quantizada de 12 bits
int potValue = 0;     // Armazenara valores inteiros na faixa de 0 a 4095

// Variavel de ponto flutuante para armazenar a tensao eletrica calculada correspondente
float voltage = 0.0;  // Armazenara valores de tensao continua em volts (0.00V a 3.30V)

// Funcao de inicializacao dos parametros de hardware do microcontrolador
void setup() {
  // Inicializa o barramento serial de comunicacao UART na velocidade de 115200 bps
  Serial.begin(115200);
  
  // Aguarda 1000 milissegundos para estabilizacao completa do circuito regulador LDO
  delay(1000);
  
  // Imprime o cabecalho de telemetria inicial na tela do computador
  Serial.println("=================================================");
  Serial.println("RoboBuilders AE312 - Telemetria Analogiica 12 Bits");
  Serial.println("=================================================");
}

// Laco de execucao continua e amostragem de dados
void loop() {
  // Realiza a conversao analogico-digital do sinal eletrico presente no GPIO 4
  potValue = analogRead(potPin);
  
  // Calcula a tensao proporcional real aplicando a resolucao de 12 bits (4095 niveis)
  voltage = (potValue / 4095.0) * 3.3;
  
  // Imprime a leitura bruta de quantizacao no Monitor Serial
  Serial.print("Valor Bruto ADC (0-4095): ");
  Serial.print(potValue);
  
  // Imprime a tensao eletrica correspondente em volts com duas casas decimais
  Serial.print(" | Tensao Calculada: ");
  Serial.print(voltage, 2);
  Serial.println(" V");
  
  // Pausa a amostragem por 500 milissegundos para facilitar a leitura humana no monitor
  delay(500);
}

Validação Prática no Monitor Serial e Plotter Gráfico

  1. Conecte a placa, faça o upload do sketch e abra o Monitor Serial ajustado para 115200 bps.
  2. Gire o eixo do potenciômetro totalmente no sentido anti-horário: o monitor exibirá leituras próximas de 0 e tensão de 0.00 V.
  3. Gire o eixo gradualmente em direção ao meio: os valores subirão de maneira suave e contínua até aproximadamente 2048 e 1.65 V.
  4. Ao atingir o batente máximo no sentido horário, a leitura alcançará 4095 e a tensão registrará 3.30 V.
  5. Feche o Monitor Serial e abra o Plotter Serial (Ferramentas > Plotter Serial ou Ctrl + Shift + L): ao girar o potenciômetro, você verá um gráfico temporal traçando em tempo real as ondas suaves de variação analógica.
Monitor Serial exibindo valores numéricos de 0 a 4095 em tempo real Plotter Serial traçando a curva contínua de variação da tensão analógica

Lição 3: Modulação por Largura de Pulso (PWM) com Periférico LEDC

O microcontrolador ESP32 é um dispositivo inteiramente digital: suas portas lógicas convencionais só conseguem emitir estados binários rígidos (0 V ou 3,3 V). Contudo, em inúmeras aplicações práticas de controle mecânico e automação — tais como variação da intensidade de lâmpadas (dimming), ajuste de velocidade de rotação de motores de corrente contínua e posicionamento angular de servomotores — é indispensável gerar uma tensão média variável. A técnica padrão de engenharia para alcançar essa proeza sem perdas resistivas de energia é a Modulação por Largura de Pulso (PWM – Pulse Width Modulation).

A Arquitetura do Periférico LEDC do ESP32

Ao contrário das placas Arduino AVR clássicas, que dependem da função síncrona analogWrite() atrelada a temporizadores rígidos de 8 bits associados a frequências fixas de 490 Hz ou 980 Hz, o ESP32 dispõe de um módulo de hardware dedicado extremamente sofisticado denominado LEDC (LED Controller).

O periférico LEDC incorpora:

  • 16 Canais PWM Independentes: Divididos em dois grupos de 8 canais (canais de alta velocidade e canais de baixa velocidade).
  • Frequência de Oscilação Ajustável por Software: Permite selecionar frequências desde 1 Hz até 40 MHz.
  • Resolução de Duty Cycle Programável: De 1 bit até 16 bits de profundidade. Com resolução configurada em 8 bits, o duty cycle varia de 0 a 255; com 10 bits, varia de 0 a 1023; e com 12 bits, atinge de 0 a 4095 níveis de suavidade de atenuação.

Física e Matemática da Modulação PWM

O sinal PWM consiste em uma onda quadrada periódica de frequência fixa (fPWMf_{PWM}) cujo tempo em nível lógico alto (TonT_{on}) é modulado dentro do período total (TT). A razão percentual entre o tempo ativo e o período completo é definida como o Ciclo de Trabalho (Duty Cycle DD):

Gráficos explicativos de modulação por largura de pulso e variação do duty cycle Montagem do circuito de controle PWM do LED na protoboard

D=TonT×100%D = \frac{T_{on}}{T} \times 100\%

O período total da forma de onda é o inverso da frequência configurada:

T=1fPWMT = \frac{1}{f_{PWM}}

Para uma frequência de chaveamento padrão de fPWM=5000 Hz=5 kHzf_{PWM} = 5000\,\text{Hz} = 5\,\text{kHz}:

T=15000 Hz=0,0002 s=200 μsT = \frac{1}{5000\,\text{Hz}} = 0{,}0002\,\text{s} = 200\,\mu\text{s}

A Tensão Média Eficaz (VmeˊdioV_{médio}) percebida pela carga (neste caso, a junção semicondutora do LED associada ao olho humano por persistência retiniana) é diretamente proporcional ao ciclo de trabalho:

Vmeˊdio=D×VCC=(duty2resoluc¸a˜o−1)×3,3 VV_{médio} = D \times V_{CC} = \left(\frac{\text{duty}}{2^{\text{resolução}} - 1}\right) \times 3{,}3\,\text{V}

Com uma resolução de 8 bits (28−1=2552^8 - 1 = 255):

Vmeˊdio=(duty255)×3,3 VV_{médio} = \left(\frac{\text{duty}}{255}\right) \times 3{,}3\,\text{V}

Exemplos práticos de tensão média gerada:

  • Duty Cycle de 0% (duty = 0): Vmeˊdio=0 VV_{médio} = 0\,\text{V} (LED totalmente apagado).
  • Duty Cycle de 25% (duty = 64): Vmeˊdio=0,25×3,3 V=0,825 VV_{médio} = 0{,}25 \times 3{,}3\,\text{V} = 0{,}825\,\text{V} (brilho tênue).
  • Duty Cycle de 50% (duty = 127): Vmeˊdio=0,50×3,3 V=1,650 VV_{médio} = 0{,}50 \times 3{,}3\,\text{V} = 1{,}650\,\text{V} (meio brilho).
  • Duty Cycle de 100% (duty = 255): Vmeˊdio=3,3 VV_{médio} = 3{,}3\,\text{V} (brilho máximo saturado).

As Três Funções da API LEDC da Espressif

O controle PWM no núcleo ESP32 2.x é executado em três etapas rigorosas:

  1. ledcSetup(canal, frequencia, resolucao): Configura o gerador de clock do canal (0 a 15), a frequência em Hertz e a resolução em bits (ex: 8 bits).
  2. ledcAttachPin(gpio, canal): Associa o canal gerador de PWM ao pino físico GPIO desejado.
  3. ledcWrite(canal, duty): Carrega o valor do ciclo de trabalho no registrador do comparador do canal.

Componentes Necessários para a Lição 3

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6
Diodo Emissor de Luz (LED) Vermelho1 unidadeEncapsulamento difuso de 5 mm
Resistor de Filme de Carbono1 unidade220 Ω220\,\Omega, 1/4 W1/4\,\text{W}, tolerância 5%
Protoboard de 830 Pontos1 unidadeMontagem experimental
Cabos Jumper Flexíveis2 unidadesConexões Macho-Macho

Tabela de Conexões de Pinos

Terminal do ComponentePonto de Ligação na ProtoboardLinha / Pino ESP32Função do Sinal
Ânodo do LED VermelhoTerminal 1 do Resistor 220 Ω220\,\OmegaLinha intermediária protoboardConexão em série limitadora
Terminal 2 do Resistor 220 Ω220\,\OmegaPino Digital do MicrocontroladorGPIO 4Saída modulada via canal LEDC 0
Cátodo do LED VermelhoBarramento Negativo da ProtoboardGNDReferência comum de 0 V

📦 Bibliotecas desta lição: nenhuma — o periférico LEDC é implementado nativamente nos registradores de baixo nível do pacote oficial da Espressif Systems.

Código-Fonte Completo Comentado Linha a Linha

Carregue o seguinte sketch para implementar o efeito de respiração suave luminosa (Fading LED):

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 3: Modulacao por Largura de Pulso (PWM) com Periferico LEDC
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Define o pino GPIO que emitira a onda quadrada modulada
const int ledPin = 4;        // GPIO 4 sera controlado pelo hardware PWM

// Definicao dos parametros operacionais de configuracao do periferico LEDC
const int freq = 5000;       // Frequencia base do sinal PWM ajustada para 5 kHz (5000 Hz)
const int ledChannel = 0;    // Utiliza o canal de hardware 0 (canais disponiveis: 0 a 15)
const int resolution = 8;    // Resolucao de 8 bits (valores discretos de duty cycle: 0 a 255)

// Funcao de configuracao inicial do microcontrolador
void setup() {
  // Inicializa o barramento serial para acompanhamento dos valores de duty cycle
  Serial.begin(115200);
  
  // 1. Configura as propriedades do temporizador do canal LEDC (canal, frequencia, resolucao)
  ledcSetup(ledChannel, freq, resolution);
  
  // 2. Conecta fisicamente o canal de geracao PWM ao pino GPIO 4 da placa
  ledcAttachPin(ledPin, ledChannel);
  
  // Emite aviso de inicializacao no console serial
  Serial.println("Controle PWM LEDC Inicializado com Sucesso a 5 kHz / 8 Bits");
}

// Laco de execucao continua: executa os ciclos de fade-in e fade-out
void loop() {
  // Laco progressivo (Fade In): incrementa o duty cycle de 0 ate 255 gradualmente
  for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
    // Escreve o novo ciclo de trabalho no registrador do canal LEDC
    ledcWrite(ledChannel, dutyCycle);
    
    // Imprime o valor instantaneo no Monitor Serial
    Serial.print("Fade In -> Duty: ");
    Serial.println(dutyCycle);
    
    // Aguarda 15 milissegundos para permitir percepcao visual suave do brilho
    delay(15);
  }

  // Laco regressivo (Fade Out): decrementa o duty cycle de 255 ate 0 gradualmente
  for (int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
    // Atualiza o ciclo de trabalho no registrador de hardware
    ledcWrite(ledChannel, dutyCycle);
    
    // Imprime o valor instantaneo no Monitor Serial
    Serial.print("Fade Out -> Duty: ");
    Serial.println(dutyCycle);
    
    // Aguarda 15 milissegundos entre cada decremento de intensidade
    delay(15);
  }
}

Gravação, Validação Prática e Análise de Funcionamento

Após o upload, observe atentamente o comportamento do LED na protoboard:

  1. O LED inicia apagado, amplia suavemente seu brilho ao longo de aproximadamente 3,8 segundos até atingir a luminância máxima (255 níveis).
  2. Sem qualquer interrupção ou piscar perceptível (flicker), o brilho retrocede suavemente até apagar-se por completo, reiniciando o ciclo de respiração contínua.
  3. No Monitor Serial a 115200 bps, é possível observar a contagem matemática sequencial acompanhando a dinâmica do sinal.
Demonstração do LED em brilho mínimo durante ciclo PWM Demonstração do LED em saturação máxima de luminosidade

Lição 4: Sensor de Movimento PIR e Temporização Não Bloqueante com Timers

A detecção de presença volumétrica e intrusão sem contato mecânico é um dos pilares da segurança patrimonial, automação predial e economia inteligente de energia em iluminação pública. Nesta lição, você integrará o consagrado sensor de presença por infravermelho passivo (PIR – Passive Infrared) HC-SR501 a um buzzer piezelétrico ativo de 5 V, implementando uma arquitetura de temporização assíncrona não bloqueante baseada em registradores de milissegundos (millis()).

Princípio Físico da Radiação Piroelétrica e Lente de Fresnel

Todo corpo material com temperatura superior ao zero absoluto (0 Kelvin / -273,15 °C) emite radiação eletromagnética proporcional à sua temperatura de acordo com a Lei de Planck e a Lei de Stefan-Boltzmann. O corpo humano (cuja temperatura interna média situa-se em aproximadamente 36,5 °C) emite radiação predominantemente no espectro infravermelho distante (Far-Infrared), com comprimento de onda de pico concentrado na faixa entre 9,4 μm9{,}4\,\mu\text{m} e 10 μm10\,\mu\text{m}.

Diagrama esquemático dos componentes e lente Fresnel do sensor PIR HC-SR501 Ajuste fino dos potenciômetros de tempo e sensibilidade no módulo PIR

O elemento transdutor montado sob a cúpula plástica branca é constituído por dois cristais piroelétricos balanceados (ex: titanato de bário ou tantalato de lítio) conectados em oposição de fase. Quando não há movimento no ambiente, a radiação ambiente incide uniformemente sobre os dois cristais, gerando tensões idênticas que se anulam mutualmente na entrada diferencial do amplificador interno.

A cúpula semiesférica translúcida é uma Lente de Fresnel multifacetada. Ela segmenta o campo de visão de 100 a 120 graus do sensor em múltiplos cones de detecção ópticos independentes intercalados por zonas cegas. Quando uma pessoa se desloca pelo ambiente, ela cruza sucessivamente esses cones de radiação: sua silhueta térmica atinge primeiro um cristal piroelétrico e, instantes depois, o segundo cristal. Essa defasagem temporal desbalanceia a entrada do circuito integrado processador BISS0001, gerando um pulso analógico amplificado que comuta a saída digital do módulo para HIGH (3,3 V).

Calibração dos Trimpots e Jumper de Disparo

A placa do módulo HC-SR501 possui dois potenciômetros de ajuste analógico e um seletor de jumper:

  1. Trimpot de Sensibilidade / Distância (Sx): Girar no sentido horário aumenta o alcance de detecção (ajustável de aproximadamente 3 metros até 7 metros).
  2. Trimpot de Atraso de Tempo (Tx): Define a largura do pulso de saída HIGH gerado a cada detecção (ajustável de 3 segundos até 300 segundos). Para controle direto por microcontrolador, recomenda-se girar o trimpot de tempo totalmente no sentido anti-horário (mínimo de ~3 segundos), transferindo toda a inteligência temporal para o firmware do ESP32.
  3. Jumper de Disparo (Trigger Mode):
    • Posição L (Disparo Único / Não Repetitivo): O sensor emite um pulso HIGH e mantém a saída inibida até o término do tempo configurado no trimpot, mesmo que a pessoa continue se movendo no local.
    • Posição H (Disparo Repetitivo Contínuo): A saída permanece em HIGH ininterruptamente enquanto houver movimento contínuo detectado nos cones de Fresnel. É a posição ideal para sistemas de alarme.

Temporização Não Bloqueante com millis()

O uso da função delay() em sistemas embarcados é uma prática altamente desencorajada na engenharia profissional. Durante um delay(3000), a CPU do microcontrolador é retida em um laço ocioso de consumo de ciclos de instrução: nenhuma leitura de botão é processada, nenhum pacote de rede Wi-Fi é atendido e nenhuma interrupção de emergência pode ser tratada.

A solução canônica é a temporização assíncrona por software baseada no contador millis(). A função millis() retorna um número inteiro sem sinal de 32 bits (unsigned long) representando a contagem acumulada de milissegundos decorridos desde a inicialização do microcontrolador.

A condição matemática de disparo é expressa por:

Δt=tatual−tanterior≥Δtalvo\Delta t = t_{atual} - t_{anterior} \ge \Delta t_{alvo}

Dessa forma, o ESP32 consegue acionar o alarme sonoro, contar o tempo de segurança e continuar executando centenas de outras tarefas com máxima responsividade.

Componentes Necessários para a Lição 4

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6
Sensor de Presença PIR HC-SR5011 unidadeTensão de alimentação 5 V DC, saída lógica 3,3 V
Buzzer Piezelétrico Ativo1 unidadeTransdutor acústico de 5 V DC com oscilador interno
Protoboard de 830 Pontos1 unidadeMontagem do circuito
Cabos Jumper Flexíveis Macho-Fêmea e Macho-Macho6 unidadesConexões de alimentação e sinal

Diagrama Esquemático e Montagem Prática

Conecte o circuito conforme ilustrado a seguir. O sensor HC-SR501 requer alimentação primária de 5 V (fornecida pelo pino Vin da placa DEVKIT V1 quando conectada à porta USB), porém sua saída digital de dados opera em compatibilidade perfeita com a lógica de 3,3 V do ESP32. O buzzer ativo é acionado diretamente pelo pino GPIO 26.

Montagem completa na protoboard com sensor PIR e Buzzer ativo Demonstração prática do alarme sonoro ativado por presença humana

Tabela de conexões elétricas ponto a ponto:

ComponenteTerminal FísicoPino ESP32Função do Sinal
Sensor PIR HC-SR501VCC (+5V)VinAlimentação principal de 5 V do sensor
Sensor PIR HC-SR501OUT (Sinal)GPIO 27Sinal digital de detecção (0V repouso, 3.3V ativo)
Sensor PIR HC-SR501GND (Terra)GNDReferência de 0 V comum
Buzzer AtivoTerminal Positivo (+)GPIO 26Saída digital de chaveamento do alarme sonoro
Buzzer AtivoTerminal Negativo (-)GNDReferência de 0 V comum

📦 Bibliotecas desta lição: nenhuma — o sketch emprega apenas a função de registro de clock interno millis() e comandos nativos de I/O (pinMode, digitalRead, digitalWrite).

Código-Fonte Completo Comentado Linha a Linha

Insira o código abaixo na IDE Arduino e realize o upload para a placa:

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 4: Sensor de Movimento PIR e Temporizacao Nao Bloqueante com Timers
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Definicao constante do pino GPIO conectado ao terminal positivo do buzzer ativo
const int buzzerPin = 26;     // Pino GPIO 26 atuara como saida digital de alarme

// Definicao constante do pino GPIO conectado ao terminal OUT do sensor de presenca PIR
const int motionSensor = 27;  // Pino GPIO 27 recebera o pulso de nivel logico alto do sensor

// Variavel unsigned long de 32 bits para armazenar o carimbo de tempo da ultima atualizacao
unsigned long previousMillis = 0;

// Variavel para registrar a contagem instantanea de milissegundos do microcontrolador
unsigned long currentMillis = 0;

// Constante que estipula o intervalo de duracao sonora do alarme em milissegundos
const long interval = 3000;   // O buzzer soara por 3000 milissegundos (3 segundos) apos a deteccao

// Rotina de configuracao executada uma unica vez durante a inicializacao
void setup() {
  // Inicializa o barramento serial de comunicacao para emissao de mensagens de telemetria
  Serial.begin(115200);
  
  // Configura o pino do buzzer como saida digital de baixa impedancia
  pinMode(buzzerPin, OUTPUT);
  
  // Assegura que o buzzer inicie desligado (nivel logico LOW no terminal positivo)
  digitalWrite(buzzerPin, LOW);
  
  // Configura o pino conectado ao sensor PIR como entrada digital
  pinMode(motionSensor, INPUT);
  
  // Mensagem inicial de estabilizacao termica do sensor piroeletrico
  Serial.println("=================================================");
  Serial.println("Sistema de Alarme PIR Iniciado. Aguardando Estabilizacao...");
  Serial.println("=================================================");
  
  // Aguarda 20 segundos para que a substancia piroeletrica equilibre sua carga interna
  delay(20000);
  Serial.println("Sensor PIR Pronto e Operacional!");
}

// Laco de execucao continua e monitoramento em tempo real
void loop() {
  // Amostra o estado logico instantaneo do sensor de presenca HC-SR501
  int state = digitalRead(motionSensor);
  
  // Atualiza a variavel de contagem temporal com os milissegundos decorridos do sistema
  currentMillis = millis();

  // Verifica se o sensor detectou perturbacao infravermelha no campo volumetrico
  if (state == HIGH) {
    // Registra o carimbo de tempo em que a presenca foi confirmada
    previousMillis = currentMillis;
    
    // Liga o buzzer ativo acionando o oscilador sonoro interno
    digitalWrite(buzzerPin, HIGH);
    
    // Imprime alerta no console serial
    Serial.println("ALERTA: Movimento Detectado no Campo de Visao!");
  } else {
    // Caso a saida do sensor esteja em nivel baixo, verifica se o tempo de alarme expirou
    if (currentMillis - previousMillis >= interval) {
      // Desliga o buzzer assim que transcorridos 3 segundos da ultima presenca
      digitalWrite(buzzerPin, LOW);
    }
  }
}

Validação Prática e Diagnóstico Operacional

  1. Conecte a placa e carregue o sketch. O Monitor Serial exibirá a mensagem de espera de estabilização térmica por 20 segundos.
  2. Durante esse período inicial, a substância cerâmica piroelétrica do HC-SR501 ajusta sua polarização galvânica interna em relação à temperatura ambiente. Não se mova em frente ao sensor nesse intervalo.
  3. Após a mensagem Sensor PIR Pronto e Operacional!, passe a mão a cerca de 1 metro de distância da cúpula de Fresnel:
    • A linha OUT comutará para 3,3 V instantaneamente.
    • O buzzer soará com tom contínuo estridente de alerta.
    • O Monitor Serial registrará ALERTA: Movimento Detectado no Campo de Visao!.
  4. Afaste-se do raio de cobertura: após 3 segundos sem movimento, o alarme silenciará automaticamente, retornando ao estado de vigília.

Lição 5: Servidor Web Wi-Fi Standalone para Controle de Chaves e Cargas

O verdadeiro diferencial que consolida o microcontrolador ESP32 como a plataforma preferencial para a Internet das Coisas (IoT) é a sua interface de rádio frequência Wi-Fi 802.11 b/g/n embutida no silício. Nesta lição, você transformará o ESP32 em um Servidor Web HTTP Standalone. O dispositivo conectará à sua rede sem fio local, atenderá requisições de navegadores web em computadores e celulares e fornecerá uma página HTML5 moderna e responsiva com interruptores deslizantes para controle independente de dois canais de iluminação (LEDs).

Arquitetura de Redes TCP/IP e o Protocolo HTTP

O firmware do ESP32 executa sobre a camada de rede uma implementação compacta da pilha de protocolos TCP/IP denominada LwIP (Lightweight IP). No modo Station (STA), o ESP32 atua como um nó cliente da rede local, associando-se ao seu roteador Wi-Fi através de um identificador de rede (SSID – Service Set Identifier) e senha criptografada (WPA2-PSK). Ao autenticar-se, o servidor DHCP do seu roteador atribui ao ESP32 um endereço IP local único (ex: 192.168.1.105).

O protocolo de comunicação da World Wide Web é o HTTP (Hypertext Transfer Protocol), que opera na camada de aplicação sobre o protocolo de transporte TCP (porta padrão 80). O fluxo de controle obedece ao modelo clássico de requisição e resposta (Request-Response):

  1. Conexão: O usuário digita o endereço IP do ESP32 na barra de endereços do navegador (Chrome, Safari, Firefox). O navegador estabelece um soquete TCP na porta 80 com o microcontrolador.
  2. Requisição HTTP GET: O navegador envia um cabeçalho de texto solicitando a página ou acionando um comando (ex: GET /26/on HTTP/1.1).
  3. Processamento: O microcontrolador analisa a string da requisição. Se encontrar a rota /26/on, aciona a porta física GPIO 26 para HIGH.
  4. Resposta HTTP: O ESP32 devolve o cabeçalho de resposta:
    HTTP/1.1 200 OK
    Content-Type: text/html; charset=UTF-8
    Connection: close
    seguido do corpo do documento HTML5 estilizado com CSS3 contendo a interface gráfica e o estado atualizado dos interruptores.
  5. Fechamento: O ESP32 fecha o soquete TCP (client.stop()), liberando memória RAM e buffers de rede para o próximo cliente.

Componentes Necessários para a Lição 5

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6 com Wi-Fi
Diodo Emissor de Luz (LED) Vermelho1 unidadeCarga do Canal 1 (GPIO 26)
Diodo Emissor de Luz (LED) Verde1 unidadeCarga do Canal 2 (GPIO 27)
Resistores de Filme de Carbono2 unidades220 Ω220\,\Omega, 1/4 W1/4\,\text{W}, tolerância 5%
Protoboard de 830 Pontos1 unidadeMontagem dos circuitos de sinalização
Cabos Jumper Flexíveis4 unidadesConexões Macho-Macho

Diagrama Esquemático e Montagem Prática

Monte os dois LEDs na protoboard protegidos por resistores limitadores de 220 Ω220\,\Omega. O LED 1 será conectado ao pino GPIO 26 e o LED 2 será conectado ao pino GPIO 27.

Montagem do circuito com 2 LEDs de controle na protoboard para o servidor Web

Tabela de ligações:

ComponenteTerminalPino ESP32Função do Circuito
LED 1 (Vermelho)Ânodo (via resistor 220 Ω220\,\Omega)GPIO 26Canal de carga 1 controlado via Web
LED 1 (Vermelho)CátodoGNDReferência de terra
LED 2 (Verde)Ânodo (via resistor 220 Ω220\,\Omega)GPIO 27Canal de carga 2 controlado via Web
LED 2 (Verde)CátodoGNDReferência de terra

📦 Bibliotecas desta lição: <WiFi.h> (versão 2.0.14) — biblioteca nativa embutida diretamente no pacote oficial de placas ESP32 da Espressif Systems. Não requer nenhuma instalação adicional.

Código-Fonte Completo Comentado Linha a Linha

Abra o sketch abaixo na IDE Arduino. Substitua imperativamente as constantes REPLACE_WITH_YOUR_SSID e REPLACE_WITH_YOUR_PASSWORD pelo nome exato e senha da sua rede Wi-Fi doméstica de 2,4 GHz:

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 5: Servidor Web Wi-Fi Standalone para Controle de Chaves e Cargas
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Inclusao da biblioteca oficial de conectividade Wi-Fi nativa do nucleo ESP32
#include <WiFi.h>

// Credenciais de autenticacao da rede Wi-Fi local (utilize apenas redes de frequencia 2,4 GHz)
const char* ssid     = "REPLACE_WITH_YOUR_SSID";     // Nome da sua rede sem fio
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Senha da sua rede sem fio

// Cria uma instancia do servidor TCP escutando conexoes de entrada na porta padrao HTTP (80)
WiFiServer server(80);

// Variavel String para armazenar o cabecalho completo da requisicao HTTP recebida do cliente
String header;

// Variaveis auxiliares para rastreamento do estado operacional de cada uma das saidas
String output26State = "off"; // Estado inicial do canal 1 (GPIO 26): desligado
String output27State = "off"; // Estado inicial do canal 2 (GPIO 27): desligado

// Constantes de mapeamento dos pinos fisicos associados as cargas
const int output26 = 26; // Pino GPIO 26 conectado ao LED Vermelho
const int output27 = 27; // Pino GPIO 27 conectado ao LED Verde

// Variaveis de temporizacao para encerramento de conexoes TCP travadas
unsigned long currentTime = 0;
unsigned long previousTime = 0;
const long timeoutTime = 2000; // Limite de tempo de espera do cliente HTTP (2 segundos)

// Funcao de configuracao inicial do firmware e conexao a rede
void setup() {
  // Inicializa a comunicacao serial a 115200 bps para exibicao do endereco IP local obtido
  Serial.begin(115200);

  // Configura os pinos das cargas como saidas digitais push-pull
  pinMode(output26, OUTPUT);
  pinMode(output27, OUTPUT);
  
  // Define o estado inicial de ambos os pinos como LOW (cargas iniciam desligadas)
  digitalWrite(output26, LOW);
  digitalWrite(output27, LOW);

  // Inicia o processo de conexao com o ponto de acesso Wi-Fi local
  Serial.print("Conectando-se a rede Wi-Fi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  // Laco de espera ate que a associacao e a obtencao de IP via DHCP sejam concluidas
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  // Imprime no console a confirmacao de conexao e o endereco IP atribuido pelo roteador
  Serial.println("");
  Serial.println("Conexao Wi-Fi Estabelecida com Sucesso!");
  Serial.print("Endereco IP Local do Servidor Web: ");
  Serial.println(WiFi.localIP());

  // Inicializa o servidor Web e passa a escutar requisicoes na porta 80
  server.begin();
}

// Laco principal: atende requisicoes HTTP de navegadores e celulares
void loop() {
  // Verifica se ha algum cliente HTTP tentando conectar-se ao servidor
  WiFiClient client = server.available();

  // Caso um cliente conecte-se ao soquete
  if (client) {
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("Novo Cliente Conectado ao Servidor Web.");
    String currentLine = ""; // Armazena a linha atual do cabecalho recebido

    // Permanece atendendo o cliente enquanto conectado e dentro da janela de timeout
    while (client.connected() && currentTime - previousTime <= timeoutTime) {
      currentTime = millis();
      
      // Se houver bytes disponiveis para leitura no buffer TCP
      if (client.available()) {
        char c = client.read(); // Le um caractere do buffer de entrada
        Serial.write(c);        // Ecoa o caractere no console serial
        header += c;            // Concatena no cabecalho geral da requisicao
        
        // Se o caractere for quebra de linha
        if (c == '\n') {
          // Se a linha atual estiver vazia, significa o fim dos cabecalhos da requisicao HTTP
          if (currentLine.length() == 0) {
            // Envia os cabecalhos de resposta HTTP padrao (200 OK)
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println(); // Linha em branco obrigatoria separando cabecalho de conteudo

            // Analise de rotas: liga ou desliga o GPIO 26
            if (header.indexOf("GET /26/on") >= 0) {
              Serial.println("Comando Recebido: GPIO 26 -> LIGAR");
              output26State = "on";
              digitalWrite(output26, HIGH);
            } else if (header.indexOf("GET /26/off") >= 0) {
              Serial.println("Comando Recebido: GPIO 26 -> DESLIGAR");
              output26State = "off";
              digitalWrite(output26, LOW);
            } 
            // Analise de rotas: liga ou desliga o GPIO 27
            else if (header.indexOf("GET /27/on") >= 0) {
              Serial.println("Comando Recebido: GPIO 27 -> LIGAR");
              output27State = "on";
              digitalWrite(output27, HIGH);
            } else if (header.indexOf("GET /27/off") >= 0) {
              Serial.println("Comando Recebido: GPIO 27 -> DESLIGAR");
              output27State = "off";
              digitalWrite(output27, LOW);
            }

            // Emissao do documento HTML5 responsivo
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            
            // Estilos CSS3 embutidos para botoes deslizantes modernos
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #555555;}</style></head>");
            
            // Corpo da pagina web
            client.println("<body><h1>RoboBuilders ESP32 Web Server</h1>");
            
            // Secao do canal GPIO 26
            client.println("<p>GPIO 26 - Estado Atual: " + output26State + "</p>");
            if (output26State == "off") {
              client.println("<p><a href=\"/26/on\"><button class=\"button\">LIGAR</button></a></p>");
            } else {
              client.println("<p><a href=\"/26/off\"><button class=\"button button2\">DESLIGAR</button></a></p>");
            } 
               
            // Secao do canal GPIO 27
            client.println("<p>GPIO 27 - Estado Atual: " + output27State + "</p>");
            if (output27State == "off") {
              client.println("<p><a href=\"/27/on\"><button class=\"button\">LIGAR</button></a></p>");
            } else {
              client.println("<p><a href=\"/27/off\"><button class=\"button button2\">DESLIGAR</button></a></p>");
            }
            
            client.println("</body></html>");
            client.println(); // Linha final de terminacao
            break; // Interrompe o laco de atendimento do cliente
          } else {
            currentLine = ""; // Limpa a linha para processar a proxima
          }
        } else if (c != '\r') {
          currentLine += c; // Adiciona caractere a linha atual
        }
      }
    }
    // Limpa a variavel de cabecalho para a proxima requisicao
    header = "";
    // Encerra formalmente a conexao TCP com o cliente
    client.stop();
    Serial.println("Conexao Encerrada com o Cliente.\n");
  }
}

Validação Prática e Controle pelo Navegador

  1. Faça o upload do firmware para a placa DEVKIT V1.
  2. Abra o Monitor Serial a 115200 bps. Você verá o processo de associação à rede Wi-Fi e a impressão do endereço IP concedido:
    Conectando-se a rede Wi-Fi: MINHA_REDE_WIFI
    ......
    Conexao Wi-Fi Estabelecida com Sucesso!
    Endereco IP Local do Servidor Web: 192.168.1.105
  3. Abra qualquer navegador web (no computador ou smartphone conectado à mesma rede Wi-Fi) e digite na barra de endereços: http://192.168.1.105.
  4. A página Web da RoboBuilders será renderizada instantaneamente:
    • Clique em LIGAR no botão do GPIO 26: o LED vermelho acende imediatamente e o botão muda visualmente para cinza com o texto DESLIGAR.
    • Clique em LIGAR no GPIO 27: o LED verde acende em paralelo.
    • O Monitor Serial exibirá o log em tempo real de cada requisição HTTP recebida e processada.
Conexão do ESP32 à rede Wi-Fi e exibição do endereço IP local no Monitor Serial Recepção e decodificação do cabeçalho da requisição HTTP GET na porta 80
Acesso à interface Web de controle através do navegador web em smartphone Tela principal do servidor Web com botões de alternância de estado dos GPIOs
Estado do LED 1 ativado remotamente via interface Web Interface Web atualizada indicando estado ON para o GPIO 26
Acionamento conjunto dos dois canais de carga Interface web exibindo os dois canais operando em estado ativo

Lição 6: Servidor Web com Controle de Cores para LED RGB

Após dominar o chaveamento binário liga/desliga pela rede, você avançará para o controle cromático e analógico em tempo real através do protocolo Wi-Fi. Nesta lição, você desenvolverá um servidor Web com seletor de paleta de cores gráfico (HTML5 Color Picker) para sintonizar dinamicamente qualquer cor do espectro visível em um LED RGB de cátodo comum utilizando três canais de modulação PWM independentes do periférico LEDC.

Teoria da Síntese Aditiva de Cores e LED RGB

O olho humano percebe as cores através de células fotorreceptoras da retina denominadas cones, sensíveis primariamente a três faixas do espectro visível: vermelho (~650 nm), verde (~530 nm) e azul (~460 nm). Pelo princípio da síntese aditiva de cores (RGB – Red, Green, Blue), a sobreposição em proporções variáveis dessas três emissões luminosas permite gerar milhões de cores perceptíveis pelo cérebro humano.

Pinagem e identificação dos terminais do LED RGB de cátodo comum Diagrama de síntese aditiva de cores e mistura cromática RGB

O LED RGB integra em um único encapsulamento epóxi difuso de 5 mm três pastilhas semicondutoras de emissão óptica independentes. Em um modelo de cátodo comum, o terminal mais longo do componente é o terra comum (GND), enquanto os outros três terminais correspondem aos ânodos individuais dos canais Vermelho (Red), Verde (Green) e Azul (Blue).

Conversão Cromática Hexadecimal e PWM

No padrão Web HTML5, uma cor é selecionada na interface gráfica em formato hexadecimal (#RRGGBB), onde cada par representa uma intensidade de 8 bits em base 16:

Cor Hexadecimal=#(c0c1)(c2c3)(c4c5)16\text{Cor Hexadecimal} = \#(c_0 c_1)(c_2 c_3)(c_4 c_5)_{16}

A conversão para valores decimais inteiros de 8 bits (0 a 255) determina o duty cycle que será injetado em cada canal de modulação PWM via periférico LEDC do ESP32:

R=hex(c0c1)16∈[0,255]R = \text{hex}(c_0 c_1)_{16} \in [0, 255]

G=hex(c2c3)16∈[0,255]G = \text{hex}(c_2 c_3)_{16} \in [0, 255]

B=hex(c4c5)16∈[0,255]B = \text{hex}(c_4 c_5)_{16} \in [0, 255]

A tensão média eficaz de cada canal óptico do LED é proporcional ao valor decodificado:

Vmeˊdio=(duty255)×3,3 VV_{médio} = \left(\frac{\text{duty}}{255}\right) \times 3{,}3\,\text{V}

Componentes Necessários para a Lição 6

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6 com Wi-Fi
Diodo Emissor de Luz (LED) RGB1 unidadeEncapsulamento difuso de 5 mm, Cátodo Comum
Resistores de Filme de Carbono3 unidades220 Ω220\,\Omega, 1/4 W1/4\,\text{W}, tolerância 5%
Protoboard de 830 Pontos1 unidadeMontagem experimental
Cabos Jumper Flexíveis5 unidadesConexões Macho-Macho

Diagrama Esquemático e Montagem Prática

Identifique os 4 terminais do LED RGB: o terminal mais longo é o Cátodo Comum (conecte ao GND). O terminal ao lado do cátodo no sentido isolado é o Vermelho (conecte via resistor de 220 Ω220\,\Omega ao GPIO 13). Os outros dois terminais do lado oposto são o Verde (via resistor de 220 Ω220\,\Omega ao GPIO 12) e o Azul (via resistor de 220 Ω220\,\Omega ao GPIO 14).

Pinagem do módulo LED RGB com resistores integrados Montagem do circuito com LED RGB conectado aos pinos PWM do ESP32

Tabela de conexões de pinos:

Terminal do LED RGBLigação IntermediáriaPino ESP32Canal LEDC Associado
Terminal Vermelho (Red)Resistor 220 Ω220\,\Omega em sérieGPIO 13Canal PWM LEDC 1
Cátodo Comum (Pino Longo)Conexão direta ao terraGNDReferência de 0 V
Terminal Verde (Green)Resistor 220 Ω220\,\Omega em sérieGPIO 12Canal PWM LEDC 2
Terminal Azul (Blue)Resistor 220 Ω220\,\Omega em sérieGPIO 14Canal PWM LEDC 3

📦 Bibliotecas desta lição: <WiFi.h> (versão 2.0.14) — embutida no pacote de suporte de placas oficial ESP32 da Espressif Systems.

Código-Fonte Completo Comentado Linha a Linha

Carregue o firmware abaixo ajustando o nome e senha da sua rede Wi-Fi local:

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 6: Servidor Web com Controle de Cores para LED RGB
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Inclusao da biblioteca Wi-Fi do ESP32
#include <WiFi.h>

// Credenciais da rede Wi-Fi local de 2,4 GHz
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Inicializacao do servidor Web HTTP na porta 80
WiFiServer server(80);

// Variaveis de texto para decodificar os parametros hexadecimais recebidos da requisicao GET
String redString = "0";
String greenString = "0";
String blueString = "0";
int pos1 = 0;
int pos2 = 0;

// Mapeamento dos pinos fisicos GPIO conectados aos anodos do LED RGB
const int redPin = 13;   // Pino do canal Vermelho
const int greenPin = 12; // Pino do canal Verde
const int bluePin = 14;  // Pino do canal Azul

// Parametros de configuracao do periferico PWM LEDC
const int freq = 5000;      // Frequencia de 5000 Hz
const int redChannel = 1;   // Canal PWM 1 para o Vermelho
const int greenChannel = 2; // Canal PWM 2 para o Verde
const int blueChannel = 3;  // Canal PWM 3 para o Azul
const int resolution = 8;   // Profundidade de 8 bits (valores de 0 a 255)

// Cabecalho da requisicao recebida
String header;

// Controle de tempo de timeout de conexao TCP
unsigned long currentTime = 0;
unsigned long previousTime = 0;
const long timeoutTime = 2000;

// Configuracao inicial do sistema e associacao dos canais PWM
void setup() {
  Serial.begin(115200);

  // 1. Configuracao dos canais LEDC com frequencia de 5 kHz e 8 bits de resolucao
  ledcSetup(redChannel, freq, resolution);
  ledcSetup(greenChannel, freq, resolution);
  ledcSetup(blueChannel, freq, resolution);

  // 2. Vinculacao dos canais de hardware aos respectivos pinos GPIO
  ledcAttachPin(redPin, redChannel);
  ledcAttachPin(greenPin, greenChannel);
  ledcAttachPin(bluePin, blueChannel);

  // Inicia com todos os canais em 0 (LED RGB apagado)
  ledcWrite(redChannel, 0);
  ledcWrite(greenChannel, 0);
  ledcWrite(blueChannel, 0);

  // Conexao com o roteador Wi-Fi
  Serial.print("Conectando-se ao Wi-Fi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWi-Fi Conectado!");
  Serial.print("Servidor Web RGB Disponivel no IP: ");
  Serial.println(WiFi.localIP());

  // Inicia o servidor Web
  server.begin();
}

// Laco de atendimento e parsing de cor
void loop() {
  WiFiClient client = server.available();

  if (client) {
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("Novo Cliente Conectado ao Servidor RGB.");
    String currentLine = "";

    while (client.connected() && currentTime - previousTime <= timeoutTime) {
      currentTime = millis();
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        header += c;

        if (c == '\n') {
          if (currentLine.length() == 0) {
            // Cabecalhos HTTP padrao
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // Decodifica a URL no formato: GET /?r255g0b128& HTTP/1.1
            if (header.indexOf("GET /?r") >= 0) {
              pos1 = header.indexOf('r');
              pos2 = header.indexOf('g');
              redString = header.substring(pos1 + 1, pos2);

              pos1 = header.indexOf('g');
              pos2 = header.indexOf('b');
              greenString = header.substring(pos1 + 1, pos2);

              pos1 = header.indexOf('b');
              pos2 = header.indexOf('&');
              blueString = header.substring(pos1 + 1, pos2);

              // Atualiza os ciclos de trabalho de hardware com os novos valores inteiros
              ledcWrite(redChannel, redString.toInt());
              ledcWrite(greenChannel, greenString.toInt());
              ledcWrite(blueChannel, blueString.toInt());

              Serial.print("Atualizacao de Cor -> R: ");
              Serial.print(redString);
              Serial.print(" | G: ");
              Serial.print(greenString);
              Serial.print(" | B: ");
              Serial.println(blueString);
            }

            // Envia a pagina HTML5 contendo o seletor visual de cores
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<style>body { text-align: center; font-family: Arial, sans-serif;}");
            client.println(".color-btn { padding: 15px 30px; font-size: 20px; border: none; border-radius: 8px; cursor: pointer; color: white; margin: 10px; }");
            client.println("</style></head>");
            client.println("<body><h1>RoboBuilders - Servidor LED RGB</h1>");
            client.println("<p>Selecione uma cor para ajustar o LED instantaneamente via Wi-Fi:</p>");
            
            // Botoes rapidos com cores primarias e secundarias pre-configuradas
            client.println("<p><a href=\"/?r255g0b0&\"><button class=\"color-btn\" style=\"background: #ff0000;\">Vermelho</button></a></p>");
            client.println("<p><a href=\"/?r0g255b0&\"><button class=\"color-btn\" style=\"background: #00ff00;\">Verde</button></a></p>");
            client.println("<p><a href=\"/?r0g0b255&\"><button class=\"color-btn\" style=\"background: #0000ff;\">Azul</button></a></p>");
            client.println("<p><a href=\"/?r255g255b0&\"><button class=\"color-btn\" style=\"background: #e6b800;\">Amarelo</button></a></p>");
            client.println("<p><a href=\"/?r180g0b255&\"><button class=\"color-btn\" style=\"background: #9900cc;\">Roxo</button></a></p>");
            client.println("<p><a href=\"/?r0g0b0&\"><button class=\"color-btn\" style=\"background: #333333;\">Desligar LED</button></a></p>");
            
            client.println("</body></html>");
            client.println();
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }
      }
    }
    header = "";
    client.stop();
    Serial.println("Cliente Desconectado.\n");
  }
}

Validação Prática e Demonstração

  1. Acesse o IP do ESP32 pelo celular ou computador.
  2. Clique no botão Vermelho: o pino GPIO 13 recebe duty cycle de 255 e o LED emite vermelho puro.
  3. Clique em Amarelo: o firmware mistura simultaneamente o canal Vermelho (255) e o canal Verde (255), gerando a cor amarela brilhante por síntese aditiva.
  4. Clique em Roxo: os canais Vermelho e Azul atuam em conjunto, criando o tom púrpura.
  5. Pressione Desligar LED: os três canais voltam a 0 V, cessando a emissão óptica.
Interface Web com seletor de paleta de cores e slider de intensidade Demonstração do LED RGB emitindo luz colorida sincronizada com a página

Lição 7: Servidor Web com Módulo Relé e Isolamento Galvânico

Nas lições anteriores, manipulamos exclusivamente componentes de baixa potência que operam no nível lógico do microcontrolador (3,3 V DC). Entretanto, na automação residencial e industrial de missão crítica, a função primordial do sistema é controlar cargas elétricas reais de alta potência: lâmpadas fluorescentes e LED de 110 V/220 V AC, solenoides hidráulicos, bombas d’água, aquecedores resistivos e motores monofásicos. Para interfacear o sinal frágil do silício com a alta tensão da rede sem risco de choques elétricos ou queima do microcontrolador, o elemento padrão de engenharia é o Módulo Relé com Isolamento Galvânico por Optoacoplador.

Princípio Eletromecânico e Força Contraeletromotriz

Um relé eletromecânico é um interruptor operado magneticamente. Ele é composto por uma bobina de fio de cobre esmaltado enrolada sobre um núcleo ferromagnético, uma mola de retorno e um conjunto de contatos mecânicos metálicos:

  • COM (Comum): O terminal central que se conecta eletricamente à fonte de energia da carga.
  • NO / NA (Normalmente Aberto): O contato que permanece fisicamente aberto em repouso. A corrente só flui para a carga quando a bobina do relé é energizada.
  • NC / NF (Normalmente Fechado): O contato que permanece fisicamente fechado em repouso, conduzindo corrente enquanto a bobina estiver desenergizada.
Diagrama funcional interno do relé eletromecânico e contatos móveis Identificação dos bornes de conexão COM, NA e NF no bloco de parafusos

Quando a bobina é submetida a uma corrente contínua, o campo magnético atrai a armadura de ferro, fechando o contato NA. No momento em que a corrente da bobina é bruscamente interrompida pelo microcontrolador, o campo magnético colapsa violentamente, induzindo uma tensão reversa de polaridade oposta de valor altíssimo conhecida como Força Contraeletromotriz (FCEM – Back EMF), governada pela Lei da Indução de Faraday-Lenz:

Vinduzida=−LdidtV_{induzida} = -L \frac{di}{dt}

Em uma bobina de relé, essa tensão induzida de pico pode ultrapassar 200 V200\,\text{V} a 400 V400\,\text{V} em uma fração de microssegundo! Se essa energia atingisse o pino GPIO do ESP32, o transistor interno seria destruído instantaneamente. Por esse motivo, o módulo relé integra na placa um diodo de roda-livre (flyback diode) 1N4148 em antiparalelo com a bobina, oferecendo um caminho fechado de recirculação para dissipar a corrente indutiva com segurança.

Potência e Cargas em Corrente Alternada (AC)

Para cargas alimentadas pela rede elétrica alternada comercial (127 V127\,\text{V} ou 220 V220\,\text{V} a 60 Hz60\,\text{Hz}), a potência aparente (SS) e a potência ativa real (PP) consumida pela carga com fator de potência cos⁡(φ)\cos(\varphi) são dadas por:

S=VRMS⋅IRMSS = V_{RMS} \cdot I_{RMS}

P=VRMS⋅IRMS⋅cos⁡(φ)P = V_{RMS} \cdot I_{RMS} \cdot \cos(\varphi)

O relé do módulo suporta correntes de comutação de até 10 A10\,\text{A} em 250 V AC250\,\text{V AC} (carga resistiva de até 2500 W2500\,\text{W}), garantindo ampla margem para automação residencial.

O Papel do Optoacoplador e do Jumper JD-VCC

O módulo do kit possui isolamento óptico integral proporcionado por um optoacoplador (circuito integrado de 4 pinos). Dentro dele, um emissor infravermelho aciona um fototransistor através de uma barreira isolante de silicone sem qualquer contato físico entre o circuito do ESP32 e a bobina do relé.

Circuito de isolamento óptico com optoacoplador e barreira de proteção Configuração do jumper JD-VCC para alimentação separada da bobina
  • Com o jumper JD-VCC / VCC instalado: A bobina é alimentada pela mesma fonte de 5 V que alimenta a placa ESP32 (Vin). É a montagem padrão de bancada.
  • Sem o jumper JD-VCC: Você conecta uma fonte externa de 5 V exclusiva nos pinos JD-VCC e GND do relé, isolando galvanicamente 100% da corrente de pico do microcontrolador.

Introdução aos Servidores Web Assíncronos (ESPAsyncWebServer)

Nas lições 5 e 6, utilizamos a biblioteca síncrona WiFiServer. Embora funcional para projetos simples, ela atende um único cliente por vez de forma sequencial e bloqueante.

Nesta Lição 7, avançamos para o padrão profissional da indústria com a biblioteca ESPAsyncWebServer suportada pela AsyncTCP. Esse ecossistema opera de forma totalmente não bloqueante e assíncrona orientada a eventos: o microcontrolador pode processar requisições simultâneas de dezenas de navegadores web conectados ao mesmo tempo, sem perder estabilidade, sem reter o processador em laços ociosos e com tempo de resposta quase instantâneo.

Componentes Necessários para a Lição 7

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6
Módulo Relé de 1 ou 2 Canais 5 V1 unidadeCom optoacoplador e contatos 10A 250VAC
Diodo Emissor de Luz (LED) Vermelho1 unidadeRepresentação segura da carga AC
Resistor de Filme de Carbono1 unidade220 Ω220\,\Omega, 1/4 W1/4\,\text{W}
Protoboard de 830 Pontos1 unidadeMontagem experimental
Cabos Jumper Flexíveis Macho-Fêmea e Macho-Macho6 unidadesConexões de alimentação e dados

⚠️ Atenção — Regra de Segurança em Bancada: Para garantir a segurança integral de estudantes e evitar o manuseio de tensões perigosas de 110 V / 220 V da rede elétrica de tomadas durante as práticas de bancada, conectaremos o relé para chavear um LED alimentado pelos 3,3 V do próprio circuito. O princípio de chaveamento de contatos secos (COM e NA) é rigorosamente idêntico ao de uma lâmpada residencial de alta tensão.

Diagrama Esquemático e Montagem Prática

Montagem do módulo relé conectado ao ESP32 e indicadores luminosos Interface Web assíncrona com botões estilizados para controle do relé

Tabela de conexões de controle:

Terminal do Módulo ReléPino ESP32Função Elétrica
VCCVin (5V)Alimentação lógica do optoacoplador
GNDGNDReferência comum de terra
IN1GPIO 26Sinal lógico de comando (LOW ativa relé)
COM (Comum)3V3Alimentação da carga de teste
NO (Normalmente Aberto)Ânodo LED (via resistor 220 Ω220\,\Omega)Saída ligada à carga

📦 Bibliotecas desta lição:

  • ESPAsyncWebServer por me-no-dev (versão 1.2.4)
  • AsyncTCP por me-no-dev / dvarrel (versão 1.1.4)
  • Instalação via ZIP: Faça o download dos repositórios oficiais AsyncTCP e ESPAsyncWebServer. Na IDE Arduino, acesse Sketch > Incluir Biblioteca > Adicionar Biblioteca .ZIP..., selecione os arquivos baixados e reinicie a IDE.

Código-Fonte Completo Comentado Linha a Linha

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 7: Servidor Web com Modulo Rele e Isolamento Galvanico
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Importacao das bibliotecas necessarias para o servidor assincrono
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

// Credenciais de conexao com a rede Wi-Fi local de 2,4 GHz
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Parametros de configuracao do rele
#define RELAY_NO    true  // Define que a carga esta conectada no contato Normalmente Aberto (NA)
#define NUM_RELAYS  1     // Quantidade de canais de rele controlados

// Mapeamento dos pinos GPIO conectados as entradas de sinal dos reles
int relayGPIOs[NUM_RELAYS] = {26}; // Canal 1 conectado no GPIO 26

// Parametros de consulta URL para as rotas HTTP GET
const char* PARAM_INPUT_1 = "relay";
const char* PARAM_INPUT_2 = "state";

// Criacao da instancia do servidor assincrono na porta padrao HTTP (80)
AsyncWebServer server(80);

// Template da pagina Web responsiva embutida na memoria Flash via literal raw
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>RoboBuilders - Controle de Rele</title>
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 2.2rem; color: #1c1c1c;}
    p {font-size: 1.5rem;}
    .switch {position: relative; display: inline-block; width: 90px; height: 44px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 44px}
    .slider:before {position: absolute; content: ""; height: 36px; width: 36px; left: 4px; bottom: 4px; background-color: #fff; border-radius: 50%; transition: .4s}
    input:checked + .slider {background-color: #fa634f}
    input:checked + .slider:before {transform: translateX(46px)}
  </style>
</head>
<body>
  <h2>RoboBuilders ESP32 Rele Web Server</h2>
  <h4>Canal 1 - Carga de Potencia (GPIO 26)</h4>
  <label class="switch">
    <input type="checkbox" onchange="toggleCheckbox(this)" id="1">
    <span class="slider"></span>
  </label>
<script>
function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?relay=26&state=1", true); }
  else { xhr.open("GET", "/update?relay=26&state=0", true); }
  xhr.send();
}
</script>
</body>
</html>
)rawliteral";

// Funcao de configuracao inicial do microcontrolador
void setup() {
  Serial.begin(115200);

  // Inicializacao dos pinos dos reles como saida digital
  for (int i = 0; i < NUM_RELAYS; i++) {
    pinMode(relayGPIOs[i], OUTPUT);
    // Modulos rele comuns ativam com nivel logico LOW (logica invertida)
    if (RELAY_NO) {
      digitalWrite(relayGPIOs[i], HIGH); // HIGH = Rele Desligado
    } else {
      digitalWrite(relayGPIOs[i], LOW);  // LOW = Rele Ligado
    }
  }

  // Conexao com a rede Wi-Fi local
  Serial.print("Conectando-se ao Wi-Fi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nConexao Wi-Fi Estabelecida!");
  Serial.print("Servidor Assincrono de Rele Disponivel no IP: ");
  Serial.println(WiFi.localIP());

  // Rota raiz: entrega a pagina HTML responsiva
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });

  // Rota de comando assincrono: /update?relay=26&state=1
  server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
    String inputMessage1;
    String inputMessage2;
    
    // Verifica se os dois parametros obrigatorios foram passados na URL
    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value(); // Numero do GPIO
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value(); // Estado: 1 ou 0
      
      int relayPin = inputMessage1.toInt();
      int relayState = inputMessage2.toInt();

      // Comuta o estado do rele considerando a logica do modulo
      if (RELAY_NO) {
        digitalWrite(relayPin, relayState == 1 ? LOW : HIGH);
      } else {
        digitalWrite(relayPin, relayState == 1 ? HIGH : LOW);
      }
      
      Serial.print("Comando Rele -> GPIO: ");
      Serial.print(relayPin);
      Serial.print(" | Novo Estado: ");
      Serial.println(relayState == 1 ? "LIGADO (Ativo)" : "DESLIGADO (Repouso)");
    }
    
    // Responde instantaneamente ao cliente sem bloquear o fluxo
    request->send(200, "text/plain", "OK");
  });

  // Inicia formalmente a escuta assincrona de conexoes
  server.begin();
}

void loop() {
  // Com o ESPAsyncWebServer, o laco loop() permanece totalmente livre para outras rotinas!
}

Validação Prática e Diagnóstico de Operação

  1. Grave o código na placa e observe o Monitor Serial confirmando o IP atribuído.
  2. Acesse o IP pelo navegador: você verá um interruptor moderno estilizado na cor oficial Coral da RoboBuilders.
  3. Clique no interruptor:
    • O navegador dispara uma requisição assíncrona AJAX de milissegundos para /update?relay=26&state=1.
    • Você ouvirá o clique sonoro mecânico característico da atracação da armadura ferromagnética do relé.
    • O LED vermelho indicador do módulo acende e a carga de teste (LED na protoboard) é alimentada.
  4. Desative o interruptor: a armadura desarma com clique mecânico e a carga apaga imediatamente.

Lição 8: Sincronização Bidirecional de Estado em Tempo Real (Web e Botão Físico)

Um dos maiores desafios no projeto de sistemas IoT para casas inteligentes (Smart Homes) e automação predial é a sincronização bidirecional de estados. Imagine uma lâmpada controlada tanto pelo aplicativo no celular quanto pelo interruptor mecânico tradicional na parede: se um usuário liga a lâmpada fisicamente no interruptor da parede, o aplicativo no smartphone precisa refletir instantaneamente o estado “Ligado” sem que a página precise ser recarregada.

Nesta Lição 8, você implementará essa arquitetura avançada com o ESP32. O circuito integrará uma saída digital (LED), uma entrada digital (botão físico com algoritmo de eliminação de ruídos mecânicos – debouncing) e um servidor Web assíncrono que troca mensagens em tempo real via chamadas assíncronas AJAX/JavaScript.

Conceito arquitetural da sincronização de estados entre botão físico e nuvem/web Esquema elétrico e montagem física completa com botão e saída sincronizada

O Algoritmo de Debounce por Software

Todo interruptor mecânico físico é composto por lâminas metálicas elásticas. No instante do fechamento dos contatos, as lâminas sofrem minúsculas oscilações mecânicas (bouncing) durante uma janela de 5 a 50 milissegundos, gerando uma sequência rápida de pulsos transitórios de subida e descida que o processador veloz de 240 MHz do ESP32 interpretaria erroneamente como dezenas de cliques sucessivos.

Para eliminar esse ruído sem adicionar capacitores externos caros, emprega-se o filtro de debounce por software:

  1. Ao detectar uma alteração na leitura do pino, o sistema registra o tempo atual: lastDebounceTime = millis().
  2. Se o sinal permanecer no novo estado de forma ininterrupta por um período superior a um limiar seguro (Δtdebounce=50 ms\Delta t_{debounce} = 50\,\text{ms}), o novo estado é validado como real e a carga comuta de estado.

Sincronização na Camada Web via AJAX (setInterval)

Na página Web carregada no navegador do usuário, um script em linguagem JavaScript executa uma função periódica em segundo plano a cada 1 segundo (1000 ms) através de setInterval():

  1. O script dispara uma requisição assíncrona XMLHttpRequest silenciosa para o endpoint /state do ESP32.
  2. O ESP32 responde instantaneamente com uma string de texto simples contendo o estado real da porta (1 ou 0).
  3. O JavaScript atualiza a propriedade visual checked do componente <input type="checkbox"> e o texto do rótulo na tela sem piscar ou recarregar a página.

Componentes Necessários para a Lição 8

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6 com Wi-Fi
Diodo Emissor de Luz (LED) Vermelho1 unidadeCarga de saída sinalizadora (GPIO 2)
Resistor de Filme de Carbono1 unidade220 Ω220\,\Omega, 1/4 W1/4\,\text{W}
Chave Táctil Pushbutton1 unidadeEntrada manual física
Resistor de Filme de Carbono1 unidade10 kΩ10\,\text{k}\Omega, 1/4 W1/4\,\text{W} (Resistor de pull-down)
Protoboard de 830 Pontos1 unidadeMontagem experimental
Cabos Jumper Flexíveis5 unidadesConexões Macho-Macho

Tabela de Conexões de Pinos

ComponenteTerminalPino ESP32Função do Circuito
LED VermelhoÂnodo (via resistor 220 Ω220\,\Omega)GPIO 2Saída digital sincronizada (também LED onboard)
LED VermelhoCátodoGNDReferência de terra
Chave PushbuttonTerminal A3V3Alimentação lógica de 3,3 V
Chave PushbuttonTerminal BGPIO 4Entrada digital amostrada com debounce
Resistor 10 kΩ10\,\text{k}\OmegaTerminal B da chave para o terraGNDPolarização estável de pull-down

📦 Bibliotecas desta lição:

  • ESPAsyncWebServer por me-no-dev (versão 1.2.4)
  • AsyncTCP por me-no-dev / dvarrel (versão 1.1.4)
  • Nenhuma outra biblioteca externa é requerida.

Código-Fonte Completo Comentado Linha a Linha

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 8: Sincronizacao Bidirecional de Estado em Tempo Real (Web e Botao)
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Importacao das bibliotecas necessarias para o servidor assincrono e rede
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

// Credenciais da rede Wi-Fi local de 2,4 GHz
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Parametro de consulta URL para atualizacao de estado
const char* PARAM_INPUT_1 = "state";

// Mapeamento dos pinos fisicos do circuito
const int output = 2;    // GPIO 2 controla o LED (saida)
const int buttonPin = 4; // GPIO 4 conectado a chave tactil (entrada)

// Variaveis de rastreamento de estado da carga
int ledState = LOW;

// Variaveis de filtragem de repique mecânico (debounce)
int buttonState;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50; // Tempo de acomodacao mecânica de 50 milissegundos

// Instancia do servidor Web assincrono na porta 80
AsyncWebServer server(80);

// Template da pagina Web responsiva com JavaScript para sincronizacao assincrona
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>RoboBuilders - Sincronizacao IoT</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 2.2rem; color: #1c1c1c;}
    h4 {font-size: 1.4rem; color: #555;}
    .switch {position: relative; display: inline-block; width: 90px; height: 44px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 44px}
    .slider:before {position: absolute; content: ""; height: 36px; width: 36px; left: 4px; bottom: 4px; background-color: #fff; border-radius: 50%; transition: .4s}
    input:checked + .slider {background-color: #fa634f}
    input:checked + .slider:before {transform: translateX(46px)}
  </style>
</head>
<body>
  <h2>RoboBuilders - Sincronizacao Bidirecional</h2>
  %BUTTONPLACEHOLDER%
<script>
function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?state=1", true); }
  else { xhr.open("GET", "/update?state=0", true); }
  xhr.send();
}

// Funcao AJAX executada periodicamente a cada 1000 milissegundos para polling de estado
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var inputChecked;
      var outputStateM;
      if( this.responseText == 1){ 
        inputChecked = true;
        outputStateM = "Ligado (ON)";
      } else { 
        inputChecked = false;
        outputStateM = "Desligado (OFF)";
      }
      document.getElementById("output").checked = inputChecked;
      document.getElementById("outputState").innerHTML = outputStateM;
    }
  };
  xhttp.open("GET", "/state", true);
  xhttp.send();
}, 1000);
</script>
</body>
</html>
)rawliteral";

// Funcao de substituicao dinamica de marcadores no template HTML durante a carga inicial
String processor(const String& var){
  if(var == "BUTTONPLACEHOLDER"){
    String buttons = "";
    String outputStateValue = (digitalRead(output) ? "checked" : "");
    buttons += "<h4>Saida GPIO 2 - Estado: <span id=\"outputState\">" + String(digitalRead(output) ? "Ligado (ON)" : "Desligado (OFF)") + "</span></h4>";
    buttons += "<label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"output\" " + outputStateValue + "><span class=\"slider\"></span></label>";
    return buttons;
  }
  return String();
}

void setup(){
  Serial.begin(115200);

  // Inicializacao dos pinos
  pinMode(output, OUTPUT);
  digitalWrite(output, LOW);
  pinMode(buttonPin, INPUT);
  
  // Conexao Wi-Fi
  Serial.print("Conectando ao Wi-Fi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWi-Fi Conectado!");
  Serial.print("Servidor de Sincronizacao Ativo no IP: ");
  Serial.println(WiFi.localIP());

  // Rota raiz: entrega o HTML com os marcadores substituidos pela funcao processor
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Rota de alteracao de estado disparada pela interface Web
  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
    if (request->hasParam(PARAM_INPUT_1)) {
      String message = request->getParam(PARAM_INPUT_1)->value();
      ledState = message.toInt();
      digitalWrite(output, ledState);
      Serial.print("Comando Web Recebido -> Novo Estado: ");
      Serial.println(ledState ? "LIGADO" : "DESLIGADO");
    }
    request->send(200, "text/plain", "OK");
  });

  // Rota de consulta de estado disparada pelo AJAX em segundo plano
  server.on("/state", HTTP_GET, [] (AsyncWebServerRequest *request) {
    request->send(200, "text/plain", String(digitalRead(output)).c_str());
  });

  server.begin();
}
  
void loop() {
  // Leitura com debounce do botao fisico na bancada
  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      // Ao transicionar de LOW para HIGH (borda de subida ao pressionar)
      if (buttonState == HIGH) {
        ledState = !ledState; // Inverte o estado da carga
        digitalWrite(output, ledState);
        Serial.print("Botao Fisico Pressionado -> Saida Alterada para: ");
        Serial.println(ledState ? "LIGADO" : "DESLIGADO");
      }
    }
  }

  lastButtonState = reading;
}

Validação Prática e Demonstração

  1. Acesse o endereço IP da placa no navegador do smartphone ou computador.
  2. Pressione o interruptor virtual na tela: o LED físico acende na protoboard e o interruptor se posiciona na cor Coral ativado.
  3. Agora, pressione o botão mecânico físico na protoboard:
    • O LED apaga fisicamente na hora.
    • Em menos de 1 segundo (próximo ciclo AJAX), o interruptor deslizante na tela do seu celular se move automaticamente para a posição desligada sem que você precise tocar na tela ou dar refresh na página!
  4. Pressione o botão físico novamente: o LED acende e a tela do smartphone atualiza para ligado instantaneamente.
Demonstração do botão toggle na interface web em repouso desligado Atualização em tempo real do estado da carga após acionamento físico
Confirmação da alteração instantânea de status na interface web sem refresh

Lição 9: Servidor Web Assíncrono com Telemetria de Temperatura e Umidade (DHT11)

A telemetria ambiental e o monitoramento em tempo real de variáveis climáticas são aplicações onipresentes em estufas agrícolas, centros de processamento de dados (CPDs), controle de processos industriais e conforto térmico residencial. Nesta lição, você desenvolverá uma estação meteorológica IoT completa baseada no sensor DHT11, servindo dados em tempo real através de um painel gráfico com ícones estilizados FontAwesome e requisições assíncronas periódicas sem sobrecarregar a CPU.

Princípio Físico do Sensor DHT11 e Psicrometria

O sensor DHT11 integra em sua cápsula plástica azul ventilada dois transdutores complementares e um microcontrolador interno de 8 bits dedicado:

  1. Transdutor de Umidade Relativa: Composto por um substrato de polímero higroscópico posicionado entre dois eletrodos condutores. Conforme a quantidade de vapor d’água na atmosfera varia, a constante dielétrica e a condutividade superficial do polímero alteram-se proporcionalmente.
  2. Transdutor de Temperatura: Um termistor do tipo NTC (Negative Temperature Coefficient), semicondutor cerâmico cuja resistência elétrica decresce exponencialmente com o aumento da temperatura ambiente.
Montagem do sensor DHT11 conectado ao GPIO do ESP32 na protoboard

Psicrometria e Umidade Relativa

A Umidade Relativa (UR%UR\%) expressa a relação percentual entre a pressão parcial de vapor d’água presente na mistura gasosa (PvP_v) e a pressão de saturação de vapor (Psat(T)P_{sat}(T)) para aquela mesma temperatura:

UR%=PvPsat(T)×100%UR\% = \frac{P_v}{P_{sat}(T)} \times 100\%

A pressão de vapor de saturação cresce exponencialmente com a temperatura de acordo com a formulação termodinâmica de Tetens:

Psat(T)=0,61078×exp⁡(17,27⋅TT+237,3) kPaP_{sat}(T) = 0{,}61078 \times \exp\left(\frac{17{,}27 \cdot T}{T + 237{,}3}\right)\,\text{kPa}

O Protocolo Serial Customizado 1-Wire de 40 Bits

Diferente do barramento padrão 1-Wire da Maxim/Dallas, o DHT11 utiliza uma linha de dados bidirecional serial proprietária com pull-up:

  1. O ESP32 envia um pulso de início mantendo a linha em nível baixo por pelo menos 18 ms18\,\text{ms} e liberando para nível alto por 20−40 μs20-40\,\mu\text{s}.
  2. O sensor responde puxando a linha para nível baixo por 80 μs80\,\mu\text{s} e nível alto por 80 μs80\,\mu\text{s}.
  3. Em seguida, transmite 40 bits sequenciais de dados:
    • Byte 1: Parte inteira da umidade relativa
    • Byte 2: Parte decimal da umidade relativa
    • Byte 3: Parte inteira da temperatura (°C)
    • Byte 4: Parte decimal da temperatura (°C)
    • Byte 5: Checksum de validação (soma dos bytes 1 + 2 + 3 + 4)
  4. A biblioteca oficial da Adafruit decodifica esses pulsos e valida o checksum antes de disponibilizar as grandezas. O tempo mínimo entre leituras consecutivas do DHT11 deve ser de pelo menos 1 a 2 segundos.

Componentes Necessários para a Lição 9

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6 com Wi-Fi
Sensor Digital de Temperatura e Umidade DHT111 unidadeMódulo com resistor de pull-up integrado de 3 pinos
Protoboard de 830 Pontos1 unidadeMontagem experimental
Cabos Jumper Flexíveis Macho-Fêmea e Macho-Macho3 unidadesConexões de alimentação e barramento

Tabela de Conexões de Pinos

Terminal do DHT11Pino ESP32Função do Sinal
VCC (+)3V3Alimentação lógica de 3,3 V
DATA (Sinal / Out)GPIO 4Linha serial bidirecional de dados
GND (-)GNDReferência de 0 V comum

📦 Bibliotecas desta lição:

  • DHT sensor library por Adafruit (versão 1.4.6)
  • Adafruit Unified Sensor por Adafruit (versão 1.1.14)
  • ESPAsyncWebServer por me-no-dev (versão 1.2.4)
  • AsyncTCP por me-no-dev / dvarrel (versão 1.1.4)
  • Instalação via Gerenciador: Sketch > Incluir Biblioteca > Gerenciar Bibliotecas... -> busque por DHT sensor library e clique em Instalar (selecione “Install All” para incluir o Adafruit Unified Sensor).

Código-Fonte Completo Comentado Linha a Linha

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 9: Servidor Web Assincrono com Telemetria Climática (DHT11)
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Inclusao das bibliotecas de rede assincrona e do sensor DHT11
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

// Credenciais da rede Wi-Fi local de 2,4 GHz
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Definicao do pino fisico de comunicacao com o sensor
#define DHTPIN 4     // Pino digital GPIO 4 conectado a linha de dados do DHT11

// Selecao do modelo de transdutor utilizado
#define DHTTYPE DHT11 // Tipo: DHT 11

// Inicializacao do objeto transdutor DHT
DHT dht(DHTPIN, DHTTYPE);

// Instancia do servidor Web assincrono na porta padrao HTTP (80)
AsyncWebServer server(80);

// Funcao dedicada a leitura e conversao da temperatura ambiente em graus Celsius
String readDHTTemperature() {
  // Realiza a leitura da temperatura atraves da biblioteca
  float t = dht.readTemperature();
  
  // Verifica se a leitura falhou (retorno NaN - Not a Number)
  if (isnan(t)) {    
    Serial.println("Falha na leitura do sensor DHT11!");
    return "--";
  } else {
    Serial.print("Temperatura Lida: ");
    Serial.print(t);
    Serial.println(" *C");
    return String(t, 1); // Retorna a temperatura com 1 casa decimal formatada
  }
}

// Funcao dedicada a leitura e conversao da umidade relativa do ar em porcentagem
String readDHTHumidity() {
  float h = dht.readHumidity();
  
  if (isnan(h)) {
    Serial.println("Falha na leitura do sensor DHT11!");
    return "--";
  } else {
    Serial.print("Umidade Relativa Lida: ");
    Serial.print(h);
    Serial.println(" %");
    return String(h, 1); // Retorna a umidade com 1 casa decimal formatada
  }
}

// Template HTML5 responsivo com icones FontAwesome e atualizacao assincrona
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>RoboBuilders - Estacao Climatica IoT</title>
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css">
  <style>
    html {font-family: Arial; display: inline-block; margin: 0px auto; text-align: center; background-color: #f4f4f4;}
    h2 {font-size: 2.2rem; color: #1c1c1c;}
    p {font-size: 2.5rem; color: #333;}
    .units {font-size: 1.2rem;}
    .dht-labels {font-size: 1.5rem; vertical-align: middle; padding-bottom: 15px;}
    .card {background-color: #ffffff; padding: 20px; border-radius: 12px; max-width: 450px; margin: 20px auto; box-shadow: 0 4px 8px rgba(0,0,0,0.1);}
  </style>
</head>
<body>
  <h2>RoboBuilders - Telemetria DHT11</h2>
  <div class="card">
    <p>
      <i class="fas fa-thermometer-half" style="color: #fa634f;"></i> 
      <span class="dht-labels">Temperatura:</span> 
      <span id="temperature">%TEMPERATURE%</span>
      <sup class="units">&deg;C</sup>
    </p>
    <p>
      <i class="fas fa-tint" style="color: #00add6;"></i> 
      <span class="dht-labels">Umidade:</span>
      <span id="humidity">%HUMIDITY%</span>
      <sup class="units">&percnt;</sup>
    </p>
  </div>
<script>
// Funcao AJAX assincrona para atualizacao da temperatura a cada 10 segundos (10000 ms)
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("temperature").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperature", true);
  xhttp.send();
}, 10000);

// Funcao AJAX assincrona para atualizacao da umidade a cada 10 segundos (10000 ms)
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("humidity").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/humidity", true);
  xhttp.send();
}, 10000);
</script>
</body>
</html>)rawliteral";

// Processador para injetar valores iniciais nos placeholders
String processor(const String& var){
  if(var == "TEMPERATURE"){
    return readDHTTemperature();
  } else if(var == "HUMIDITY"){
    return readDHTHumidity();
  }
  return String();
}

void setup(){
  Serial.begin(115200);

  // Inicializa o sensor DHT11
  dht.begin();
  
  // Conexao com a rede Wi-Fi
  Serial.print("Conectando-se ao Wi-Fi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWi-Fi Conectado com Sucesso!");
  Serial.print("Painel de Telemetria Climática Disponivel no IP: ");
  Serial.println(WiFi.localIP());

  // Rota principal: entrega a pagina inicial com as primeiras leituras
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
  
  // Endpoint de telemetria assincrona de temperatura: /temperature
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHTTemperature().c_str());
  });
  
  // Endpoint de telemetria assincrona de umidade: /humidity
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readDHTHumidity().c_str());
  });

  server.begin();
}
 
void loop(){
  // O servidor opera de forma puramente assincrona!
}

Validação Prática e Demonstração

  1. Realize o upload do firmware e monitore a porta COM para capturar o IP local.
  2. Abra o navegador web no endereço IP exibido:
    • A página carregará um cartão estilizado com sombras suaves e ícones modernos em alta resolução.
    • Os valores de temperatura (ex: 24.5 °C) e umidade relativa (ex: 58.0 %) serão exibidos instantaneamente.
  3. Aproxime a mão ou assopre suavemente próximo ao sensor para alterar a umidade do ar expirado:
    • Em menos de 10 segundos, os números na tela serão atualizados automaticamente via chamada assíncrona silenciosa, sem qualquer cintilação visual na página!
Interface web de telemetria exibindo leituras climáticas em tempo real Painel web responsivo exibindo temperatura e umidade com ícones estilizados

Lição 10: Interface Gráfica com Display OLED 0.96 Polegadas SSD1306 via Barramento I2C

Na conclusão das lições práticas do curso, você implementará uma interface física homem-máquina (IHM) gráfica de alta fidelidade visual integrando um display gráfico matricial monocromático OLED de 0,96 polegadas baseado no controlador SSD1306 através do barramento serial síncrono I2C.

Tecnologia Emissiva OLED e Controlador SSD1306

Diferentemente dos módulos de cristal líquido tradicionais (LCD – Liquid Crystal Display), que exigem uma fonte de luz de fundo (backlight) acesa ininterruptamente, a tecnologia OLED (Organic Light Emitting Diode) é puramente emissiva: cada ponto individual da matriz de 128×64128 \times 64 pixels é um diodo orgânico microscópico que emite luz própria quando estimulado por corrente elétrica.

Essa característica confere ao display OLED vantagens operacionais extraordinárias para sistemas embarcados:

  1. Contraste Infinito: Para representar a cor preta, o pixel correspondente é simplesmente desligado por completo (corrente nula), eliminando o vazamento de luz característico dos LCDs e proporcionando leitura perfeita no escuro.
  2. Eficiência Energética: O consumo de corrente é diretamente proporcional à quantidade de pixels acesos na tela, tornando-o perfeito para nós remotos de IoT alimentados por baterias: Itotal=Iquiescente+npixels_ativos⋅IpixelI_{total} = I_{quiescente} + n_{pixels\_ativos} \cdot I_{pixel}
  3. Ângulo de Visão Amplo: Nitidez visual mantida em ângulos superiores a 160 graus sem distorção cromática.
Estrutura e características técnicas do display OLED SSD1306 de 0.96 polegadas Montagem do display OLED conectado às linhas SDA e SCL do barramento I2C do ESP32

O Barramento I2C e o Buffer de Vídeo (FrameBuffer)

A comunicação com o microcontrolador é realizada através do barramento I2C (Inter-Integrated Circuit), utilizando apenas dois fios de dados:

  • SDA (Serial Data Line): Linha bidirecional de dados (padrão no ESP32: GPIO 21).
  • SCL (Serial Clock Line): Linha de clock sincronizador gerada pelo microcontrolador mestre (padrão no ESP32: GPIO 22).

O endereço I2C padrão de 7 bits do driver SSD1306 na fábrica é 0x3C (ou 0x3D caso o resistor SMD de seleção na parte traseira da placa seja comutado).

Para renderizar elementos gráficos complexos (círculos, retângulos, linhas diagonais e caracteres tipográficos) sem cintilação, a biblioteca aloca na memória SRAM do ESP32 um Buffer de Vídeo (FrameBuffer) correspondente a toda a área da tela:

Buffer=128×64 pixels=8192 bits=1024 bytes=1 KB\text{Buffer} = 128 \times 64\,\text{pixels} = 8192\,\text{bits} = 1024\,\text{bytes} = 1\,\text{KB}

Todas as operações de desenho (print, drawLine, drawCircle) alteram apenas os bits desse buffer local na memória RAM. A transferência física para a controladora SSD1306 ocorre unicamente no momento em que a função display.display() é executada, enviando os 1024 bytes através do barramento I2C em alta velocidade (Fast Mode a 400 kHz).

O tempo aproximado de envio de cada quadro completo é expresso por:

Tframe=1024×9+overheadsfI2C≈9216400000≈23 ms  ⟹  Taxa≈43 FPST_{frame} = \frac{1024 \times 9 + \text{overheads}}{f_{I2C}} \approx \frac{9216}{400000} \approx 23\,\text{ms} \implies \text{Taxa} \approx 43\,\text{FPS}

Componentes Necessários para a Lição 10

ComponenteQuantidadeEspecificação Técnica
Placa DOIT ESP32 DEVKIT V11 unidadeMicrocontrolador Dual-Core Xtensa LX6
Display Gráfico OLED 0,96 Polegadas1 unidadeResolução 128×64128 \times 64, I2C, endereço 0x3C
Protoboard de 830 Pontos1 unidadeMontagem experimental
Cabos Jumper Flexíveis4 unidadesConexões Macho-Macho

Tabela de Conexões de Pinos

Terminal do Display OLEDLinha / Pino ESP32Função do Barramento
VCC3V3Alimentação lógica de 3,3 V DC
GNDGNDReferência comum de 0 V
SCL (Clock)GPIO 22Linha de clock do barramento I2C mestre
SDA (Dados)GPIO 21Linha serial de dados do barramento I2C mestre
Localização e instalação da biblioteca Adafruit SSD1306 no Gerenciador da IDE Instalação das dependências da Adafruit GFX Library na IDE Arduino

📦 Bibliotecas desta lição:

  • Adafruit SSD1306 por Adafruit (versão 2.5.11)
  • Adafruit GFX Library por Adafruit (versão 1.11.10)
  • <Wire.h> (versão nativa do pacote ESP32)
  • Instalação: No Gerenciador de Bibliotecas, busque por Adafruit SSD1306 e clique em Instalar (aceitando a instalação da dependência Adafruit GFX).

Código-Fonte Completo Comentado Linha a Linha

Carregue o sketch de demonstração gráfica alfanumérica no ESP32:

// =========================================================================
// Curso RoboBuilders - ESP32 Basic Starter Kit AE312
// Projeto 10: Interface Grafica com Display OLED 0.96 SSD1306 via I2C
// Placa: DOIT ESP32 DEVKIT V1
// Codigo 100% comentado linha a linha em portugues
// =========================================================================

// Inclusao das bibliotecas de barramento I2C e aceleracao grafica da Adafruit
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Definicao dimensional da resolucao do display em pixels
#define SCREEN_WIDTH 128 // Largura horizontal da matriz OLED (128 colunas)
#define SCREEN_HEIGHT 64 // Altura vertical da matriz OLED (64 linhas)

// Criacao da instancia do objeto controlador SSD1306
// Parametros: largura, altura, ponteiro para o barramento I2C (&Wire) e pino de reset (-1 se compartilhado)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Funcao de configuracao inicial do firmware
void setup() {
  // Inicializacao da comunicacao serial assincrona a 115200 bps
  Serial.begin(115200);

  // Inicializa o display OLED no endereco I2C padrao 0x3C com geracao de tensao interna de chaveamento (SWITCHCAPVCC)
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    // Caso ocorra falha de deteccao de hardware no barramento I2C
    Serial.println(F("ERRO CRITICO: Nao foi possivel inicializar o display OLED SSD1306!"));
    // Retem a execucao em laco infinito para protecao
    for(;;);
  }

  Serial.println("Display OLED SSD1306 Inicializado com Sucesso!");

  // Aguarda 2 segundos para estabilizacao completa dos circuitos internos
  delay(2000);
  
  // Limpa completamente todos os 1024 bytes do buffer de video na memoria RAM
  display.clearDisplay();

  // Define o tamanho da fonte tipografica (escala 1 = 6x8 pixels por caractere)
  display.setTextSize(1);
  
  // Define a cor de escrita dos pixels como WHITE (em display monocromatico, acende o pixel)
  display.setTextColor(WHITE);
  
  // Posiciona o cursor de desenho nas coordenadas cartesianas X=0 (coluna 0) e Y=10 (linha 10)
  display.setCursor(0, 10);
  
  // Renderiza a primeira linha de texto institucional no buffer de memoria
  display.println("RoboBuilders Brasil");
  
  // Ajusta a escala da fonte para tamanho 2 (12x16 pixels por caractere) para destaque visual
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 26);
  
  // Renderiza a identificacao do modelo do microcontrolador
  display.println("ESP32 IoT");

  // Desenha uma linha horizontal decorativa de divisao grafica (X1=0, Y1=48, X2=127, Y2=48)
  display.drawFastHLine(0, 48, 128, WHITE);

  // Retorna a escala 1 para os detalhes do curso no rodape da tela
  display.setTextSize(1);
  display.setCursor(0, 54);
  display.println("Kit AE312 - Completo");

  // Transfere o conteudo consolidado do buffer da RAM para os pixels fisicos da tela via I2C
  display.display(); 
}

// Laco de execucao continua
void loop() {
  // O display OLED permanece estatico exibindo as informacoes de alta nitidez
}

Validação Prática e Demonstração

  1. Realize o upload do firmware para a placa.
  2. Observe a tela frontal do display OLED acender imediatamente com fundo preto puro de altíssimo contraste.
  3. As três linhas de informação serão exibidas com geometria perfeitamente nítida:
    • Topo: RoboBuilders Brasil (Fonte tamanho 1)
    • Centro: ESP32 IoT (Fonte tamanho 2 destacada)
    • Divisória: Linha horizontal geométrica contínua
    • Rodapé: Kit AE312 - Completo (Fonte tamanho 1)
Display OLED em operação exibindo caracteres nítidos de texto alfanumérico

Guia Diagnóstico (Troubleshooting)

A engenharia de sistemas embarcados exige rigor metodológico na identificação e solução de falhas elétricas, lógicas e de compilação. A matriz diagnóstica a seguir consolida as principais ocorrências técnicas observadas no desenvolvimento prático com o Kit Iniciante ESP32 Basic Starter Kit AE312, apontando a causa raiz e a ação corretiva imediata:

Sintoma ObservadoCausa Raiz ProvávelAção Corretiva Recomendada
Console exibe Connecting........_____ e falha com Timed out waiting for packet headerO circuito automático DTR/RTS da placa falhou em sincronizar o pulso de descida na linha GPIO 0 com o ROM Bootloader devido à capacitância parasita do cabo USB.No exato instante em que a sequência Connecting... surgir no rodapé da IDE Arduino, mantenha o botão BOOT pressionado na placa ESP32 até a barra de progresso iniciar; em seguida, solte-o. Substitua cabos USB longos ou de baixa qualidade por cabos de dados curtos com blindagem de malha.
Erro de compilação: fatal error: ESPAsyncWebServer.h: No such file or directoryA biblioteca assíncrona não está instalada no diretório de bibliotecas da IDE ou foi descompactada com nome de pasta incorreto.Baixe o repositório oficial em formato ZIP, acesse Sketch > Incluir Biblioteca > Adicionar Biblioteca .ZIP... e selecione o arquivo. Se instalado manualmente, renomeie a pasta extraída para rigorosamente ESPAsyncWebServer (removendo sufixos como -master). Reinicie a IDE Arduino.
Erro de compilação: fatal error: AsyncTCP.h: No such file or directoryAusência da biblioteca de transporte assíncrono AsyncTCP, dependência estrutural obrigatória do ESPAsyncWebServer.Instale a biblioteca AsyncTCP através do menu Adicionar Biblioteca .ZIP... na IDE Arduino conforme a Tabela-Mestre de Bibliotecas da seção de preparação.
Erro de compilação: fatal error: DHT.h: No such file or directoryA biblioteca do sensor de temperatura DHT não foi instalada ou sua dependência fundamental (Adafruit Unified Sensor) está ausente.Abra o Gerenciador de Bibliotecas da IDE Arduino (Ctrl + Shift + I), busque por DHT sensor library por Adafruit e clique em Instalar. Ao surgir o pop-up de dependências, clique obrigatoriamente em Install All para garantir a presença do driver unificado.
Monitor Serial exibindo caracteres estranhos e ilegíveis (ex: ?)Descasamento entre a taxa de transmissão em bauds configurada no firmware e a velocidade selecionada no console.Altere a caixa seletora de velocidade no canto superior direito do Monitor Serial para rigorosamente 115200 baud, que é o padrão utilizado em todas as rotinas Serial.begin(115200) do curso.
ESP32 reiniciando em loop infinito exibindo Brownout detector was triggeredQueda abrupta da tensão de alimentação abaixo de 2,7 V DC durante os picos de corrente da transmissão de rádio Wi-Fi (+20 dBm).Conecte a placa diretamente a uma porta USB 3.0 ou use um hub USB energizado externamente. Evite portas USB frontais de gabinetes conectadas por cabos internos longos. Se necessário, insira um capacitor eletrolítico de 10 μF10\,\mu\text{F} a 100 μF100\,\mu\text{F} entre os pinos 3V3 e GND da protoboard para amortecer transientes.
Monitor Serial preso em Connecting to WiFi.. com pontos infinitosCredenciais de rede (SSID ou senha) digitadas incorretamente, ou tentativa de conexão a uma rede Wi-Fi exclusiva de 5,0 GHz.O rádio do chip ESP32 opera estritamente na faixa de frequência de 2,4 GHz. Certifique-se de que o roteador possui rede de 2,4 GHz ativada. Revise se o nome da rede e a senha no código não contêm espaços extras ou erros de digitação.
Sensor DHT11 retornando -- ou Falha na leitura do sensor DHT11!Conexão incorreta dos pinos, mau contato na protoboard ou ausência de resistor de pull-up na linha de dados.Verifique se o pino de dados está conectado no GPIO correto (GPIO 4 no Projeto 9). Caso utilize o sensor DHT11 discreto de 4 pinos (sem placa de suporte), adicione um resistor externo de 4,7 kΩ4{,}7\,\text{k}\Omega ou 10 kΩ10\,\text{k}\Omega entre a linha DATA e os 3,3 V.
Display OLED SSD1306 com tela totalmente preta sem acender pixelsInversão das linhas I2C (SDA e SCL), endereço hexadecimal incorreto ou falta da chamada display.display().Certifique-se de que o pino SDA do display está no GPIO 21 e o pino SCL no GPIO 22. Verifique se a inicialização no código utiliza o endereço 0x3C. Lembre-se de que comandos gráficos apenas alteram a RAM; a tela só atualiza fisicamente após executar display.display().
Módulo Relé com LED aceso, mas a armadura não atraca e a carga não comutaAlimentação insuficiente de corrente para a bobina eletromecânica de 5 V ou lógica de acionamento invertida.A bobina do relé consome entre 70 mA e 90 mA em 5 V e deve ser alimentada pelo pino Vin (5 V USB) do ESP32, e nunca pelo pino 3V3 (que não possui tensão nem corrente suficientes para chavear a mola). Verifique também se o jumper JD-VCC está devidamente inserido nos terminais da placa.
Leitura analógica no ADC retornando sempre 0 ou 4095 após ligar o Wi-FiConflito de hardware entre o conversor ADC2 e o amplificador de potência do rádio Wi-Fi.O bloco ADC2 (GPIOs 0, 2, 4, 12, 13, 14, 15, 25, 26 e 27) é desabilitado internamente pelo driver de rádio da Espressif quando a função WiFi.begin() é chamada. Para leituras analógicas com Wi-Fi ativo, utilize exclusivamente pinos do bloco ADC1 (GPIOs 32, 33, 34, 35, 36 ou 39).
Chave táctil registrando múltiplos acionamentos com um único toqueRepique mecânico das lâminas metálicas elásticas do botão (bouncing).Implemente o filtro de debounce por software com janela temporal de 50 milissegundos utilizando millis() (conforme ensinado na Lição 8), ou conecte um capacitor cerâmico de 100 nF100\,\text{nF} em paralelo com os terminais do botão.

Solução de problemas

Olá! Sou o assistente técnico da RoboBuilders. Descreva seu problema com o Kit Iniciante ESP32 Basic Starter Kit AE312 – Curso Completo e eu ajudarei a encontrar a solução.

O assistente usa IA e pode errar. Confirme informações críticas no datasheet oficial do fabricante.