Guias · 23 min de leitura

ESP32 “Brownout detector was triggered” e Guru Meditation: como resolver

ESP32 com erro brownout detector was triggered e reinícios sem fim: corrija fonte, cabo e capacitor, leia os códigos rst, Guru Meditation, Task WDT e o backtrace.

A mensagem ESP32 brownout detector was triggered significa que a tensão de alimentação da placa caiu por um instante abaixo de um limite seguro e o chip se reiniciou para se proteger. O problema quase nunca está no seu código, e sim na alimentação: uma porta USB fraca, um cabo fino e comprido, um regulador subdimensionado ou servos e fitas de LED alimentados pela mesma linha do ESP32. O segundo grande motivo para um ESP32 ficar reiniciando é um travamento de software; nesse caso, o Monitor Serial mostra linhas como Guru Meditation Error, task_wdt ou Stack canary.

A boa notícia: o ESP32 diz por que reiniciou, desde que você saiba ler as mensagens dele. Neste guia, você vai primeiro aprender a reconhecer os códigos rst nas linhas de boot e as mensagens de erro, e depois resolver o brownout de vez com a fonte, o cabo e o capacitor certos. Em seguida, veremos erros Guru Meditation como LoadProhibited e StoreProhibited, estouros de pilha, ponteiros nulos e timeouts do watchdog, e você vai rastrear um travamento até a linha exata do código com o ESP Exception Decoder. Por fim, veremos os pinos de strapping (GPIO0, 2, 12 e 15) que podem atrapalhar o processo de boot.

Placa de desenvolvimento ESP32 DevKit
Placa de desenvolvimento ESP32: os 5 V da USB são reduzidos para 3,3 V pelo regulador da placa. A maioria dos problemas de brownout vem de quedas curtas nessa linha de 3,3 V.

Por que o ESP32 fica reiniciando? Leia a mensagem primeiro

Antes de começar a procurar o defeito, abra o Monitor Serial em 115200 baud e pressione o botão EN da placa. A cada boot, o bootloader da ROM do ESP32 imprime primeiro uma linha de data como “ets Jun 8 2016 00:22:57”, seguida de uma linha como rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT). A parte rst diz por que a placa reiniciou; a parte boot mostra em que modo ela iniciou. Se a placa estiver presa num loop, você encontra a mensagem de erro, as últimas palavras da execução anterior, logo acima dessas linhas. A tabela abaixo resume as mensagens que você vai ver e por onde começar:

O que aparece no Monitor SerialSignificadoOnde procurar
Brownout detector was triggered (detector de brownout acionado)A tensão de alimentação caiu abaixo do limiteFonte, cabo, capacitor
Guru Meditation Error: Core 1 panic'ed (LoadProhibited) (leitura proibida)O código tentou ler de um endereço inválidoPonteiro nulo, limites de array
Guru Meditation Error: Core 1 panic'ed (StoreProhibited) (escrita proibida)O código tentou escrever em um endereço inválidoPonteiro nulo, estouro de buffer
Stack canary watchpoint triggered (loopTask) (pilha cheia)A pilha de uma tarefa encheuArrays locais grandes, recursão
task_wdt: Task watchdog got triggered (watchdog de tarefa acionado)Uma tarefa não liberou a CPU por mais de 5 segundosLaços sem pausas, tarefas travadas
Interrupt wdt timeout on CPU0 / CPU1 (timeout do watchdog de interrupção)Uma rotina de interrupção, ou as interrupções desativadas, levou mais de 300 msISR longa, Serial dentro de uma ISR
boot:0x3 (DOWNLOAD_BOOT...) waiting for download (aguardando gravação)A placa iniciou no modo de programaçãoGPIO0 em LOW no boot
invalid header ou flash read err (erro de leitura da flash)Não foi possível ler a memória flashGPIO12 em HIGH no boot, carregamento interrompido

O que é “Brownout detector was triggered” e por que acontece?

Brownout é uma queda curta de tensão sem perda total da alimentação. O ESP32 tem um detector de brownout que vigia o tempo todo a linha de alimentação, e no core do Arduino o limite dele fica no nível mais baixo, cerca de 2,43 V. No instante em que a tensão cai abaixo desse valor, o chip protege o rádio e a memória flash, imprime “Brownout detector was triggered” no Monitor Serial e se reinicia. O motivo é simples: com tensão baixa, a flash pode ser lida errado, dados gravados podem se corromper e a CPU pode executar instruções aleatórias. O detector faz a placa dar um reset limpo em vez de se comportar de forma imprevisível. O módulo ESP32-WROOM-32 foi projetado para funcionar entre 3,0 e 3,6 V, então, quando a linha chega a 2,43 V, ela já está bem fora da zona segura.

Depois de uma mensagem de brownout, a linha de boot mostra rst:0xc (SW_CPU_RESET) ou rst:0x3 (SW_RESET), conforme a versão do core do Arduino, porque a interrupção do detector imprime a mensagem e depois reinicia o chip por software. Não se deixe enganar: esse mesmo código anota na memória do chip que a causa foi um brownout, e esp_reset_reason() retorna ESP_RST_BROWNOUT. Quando é o próprio reset de brownout do hardware que atua, a linha mostra rst:0xf (RTCWDT_BROWN_OUT_RESET). Nos cores 3.x, baseados no ESP-IDF 5, essa linha virou um log de nível informativo (I BOD: Brownout detector was triggered). Como as bibliotecas pré-compiladas do Arduino só imprimem logs de nível de erro, a mensagem geralmente nem aparece e a placa reinicia em silêncio; se você vir um rst:0x3 ou rst:0xc sem explicação no boot, confira o motivo do reset com o sketch de diagnóstico mais abaixo. Para entender por que a tensão cai, veja quanta corrente o ESP32 consome:

Estado de operaçãoCorrente típica (chip ESP32)
Deep sleep (timer do RTC ligado)Cerca de 10 µA
Light sleep (sono leve)Cerca de 0,8 mA
Wi-Fi desligado, CPU a 240 MHz30–68 mA
Wi-Fi recebendo (RX)95–100 mA
Wi-Fi transmitindo, 802.11b, 19,5 dBmCerca de 240 mA
Calibração do rádio no boot e no momento da conexãoPode passar de 400 mA em picos de microssegundos

A diferença nesta tabela é o coração do problema de brownout: até o seu código ligar o Wi-Fi, a placa fica em torno de 50 mA, mas na linha WiFi.begin() a corrente salta cinco ou seis vezes em poucos microssegundos. Se a fonte, o cabo e o regulador não acompanharem essa demanda repentina, a tensão desaba. Por isso a Espressif recomenda uma fonte capaz de fornecer pelo menos 500 mA para o ESP32. O sintoma é bem conhecido: a placa liga, imprime algumas linhas no Monitor Serial, reinicia no momento em que o Wi-Fi ou o Bluetooth começa e isso vira um loop sem fim. O mesmo pode acontecer quando um servo se move, um relé comuta ou uma fita de LED fica branca.

As causas mais comuns de brownout

  • Cabo USB fino ou comprido: os fios de alimentação finos de cabos baratos podem somar até 0,5 Ω na ida e na volta. Pela lei de Ohm, um pico de 400 mA perde 0,2 V num cabo desses.
  • Porta USB ou hub fraco: portas de teclados e monitores, hubs sem alimentação própria e as portas frontais de alguns notebooks deixam a tensão cair no pico de corrente.
  • Dropout do regulador: o AMS1117 presente na maioria das placas precisa de uma diferença de 1,0–1,3 V entre entrada e saída. Se a tensão no pino 5V cair abaixo de uns 4,3 V, a saída não consegue manter 3,3 V.
  • Ligar uma bateria direto: conectar uma célula Li-ion de 3,7 V ao pino 5V faz a saída cair abaixo de 3 V por causa do dropout do regulador; duas pilhas AA logo caem abaixo do mínimo do ESP32 sob carga.
  • O pino 3.3V do Arduino Uno: o recomendado nesse pino é só uns 50 mA, nem de longe o suficiente para um ESP32 com Wi-Fi ligado.
  • Cargas na mesma linha: se servos, relés, buzzers, motores CC ou uma fita WS2812B funcionam com os mesmos 5 V do ESP32, cada movimento puxa a tensão para baixo.
  • Protoboards e jumpers: contatos frouxos e jumpers finos somam um pouco de resistência em cada conexão; passar a alimentação pela protoboard piora as coisas.
  • ESP32-CAM: quando a câmera, o Wi-Fi e o LED de flash funcionam ao mesmo tempo, a corrente fica muito alta; essa placa gosta de 5 V e pelo menos 2 A. Veja os detalhes no guia do ESP32-CAM.
Ver 3,3 V no multímetro não significa que a alimentação está firme. O multímetro faz só algumas leituras por segundo e mostra algo próximo de uma média, enquanto as quedas que causam brownout duram de microssegundos a poucos milissegundos e nunca aparecem no display. Só um osciloscópio consegue mostrá-las. Se você não tem um, aplique as correções abaixo na ordem e confira depois de cada passo se o erro sumiu. O básico de medição está em Como usar o multímetro.

Correção 1: melhore a fonte e o cabo

O primeiro passo, e o mais eficaz, é uma fonte mais forte. Ligue a placa com um cabo de dados curto e grosso que você sabe que é bom, direto numa porta USB traseira do computador ou num adaptador de 5 V de pelo menos 1 A. Portas USB 2.0 são projetadas para fornecer 500 mA, e portas USB 3.0, 900 mA; os 500 mA que a Espressif recomenda estão bem no limite de uma porta USB 2.0, então, somadas as perdas do cabo, os problemas começam. Se só trocar o cabo já resolve o erro, a resistência do cabo provavelmente era a culpada. Você pode calcular quanta tensão um cabo perde com V = I × R na ferramenta Lei de Ohm.

Regulador de tensão AMS1117 de 3,3 V
AMS1117-3.3: o regulador da maioria das placas ESP32. Ele precisa de uma diferença de 1,0–1,3 V entre entrada e saída; se o pino 5V cair abaixo de uns 4,3 V, a saída não consegue manter 3,3 V.
Montagem da alimentaçãoRisco de brownoutObservação
Cabo curto e grosso e porta USB traseiraBaixoA correção mais fácil durante o desenvolvimento
Cabo longo e fino, porta frontal ou hubAltoA resistência do cabo puxa a tensão para baixo no pico de corrente
Adaptador de 5 V de pelo menos 1 A, no pino 5V ou VINBaixoRecomendado para projetos permanentes
Fonte pronta de 3,3 V direto no pino 3V3Depende da fontePrecisa fornecer pelo menos 500 mA e nunca passar de 3,6 V
Célula Li-ion de 3,7 V pelo AMS1117AltoAbaixo de uns 4 V na célula, a saída cai para menos de 3 V
Célula Li-ion com regulador de 3,3 V de baixa queda (LDO) ou um buck-boostBaixoEntrega 3,3 V estáveis mesmo enquanto a célula descarrega
Duas pilhas AA direto no pino 3V3Muito altoSob carga, a tensão cai rapidamente abaixo do mínimo do ESP32

Projetos a bateria pedem cuidado extra. Uma célula Li-ion como a 18650 dá 4,2 V quando cheia e cerca de 3,0 V quando vazia. Essa faixa não serve nem para ligar direto no pino 3V3 (4,2 V passa do limite de 3,6 V) nem para o pino 5V com o AMS1117. A solução certa é alimentar o pino 5V pela célula através de um módulo elevador de 5 V, ou alimentar a linha 3V3 direto por um regulador de baixa queda de pelo menos 500 mA (por exemplo, um ME6211 ou HT7833) mais um capacitor. Você pode estimar quanto tempo seu projeto vai funcionar com uma bateria na ferramenta Autonomia da bateria e conhecer o circuito de carga no guia do módulo de carga TP4056.

Correção 2: coloque um capacitor entre 3V3 e GND

Um capacitor funciona como um pequeno reservatório que fornece energia por conta própria durante um pico de corrente, até o regulador e o cabo darem conta. Coloque um capacitor eletrolítico de 100–470 µF entre os pinos 3V3 e GND da placa, o mais perto possível dela, mais um capacitor cerâmico de 100 nF ao lado. O eletrolítico cuida das quedas de milissegundos; o cerâmico, da ondulação muito curta e de alta frequência. Dá para ver o efeito por alto com ΔV = I × Δt / C: mesmo que um capacitor de 470 µF forneça sozinho 200 mA extras por 200 µs, a tensão cai só 0,085 V. A marcação 104 num capacitor cerâmico significa 100 nF; você pode decifrar outras marcações com a ferramenta Código do capacitor.

Tipos de capacitores
Nos capacitores eletrolíticos, a perna longa é o positivo (+) e vai no 3V3; a perna do lado da faixa no corpo vai no GND. Para a linha de 3,3 V, basta um capacitor de 6,3 V ou 10 V.
Nunca monte um capacitor eletrolítico invertido: ele esquenta, estufa e pode estourar. Se ligar o capacitor na linha de 5 V, escolha um de pelo menos 10 V. Capacitores muito grandes (1000 µF ou mais) puxam uma corrente de carga alta ao ligar, o que pode sobrecarregar a porta USB por um instante e atrasar a subida da linha de 3,3 V; 470 µF na linha 3V3 bastam para a maioria dos projetos. Você entende como os capacitores funcionam em O que é um capacitor?

Correção 3: alimente servos, motores e fitas de LED separadamente

Mesmo que o próprio ESP32 esteja bem alimentado, cargas na mesma linha podem puxar a tensão para baixo. Até um servo pequeno como o SG90 consome algumas centenas de mA quando começa a se mover; um LED WS2812B usa cerca de 60 mA no branco total, então uma fita de 30 LEDs pode chegar a 1,8 A. Alimente essas cargas não pelo pino 5V ou 3V3 do ESP32, mas por uma fonte de 5 V separada; por exemplo, você pode reduzir um adaptador de 12 V para 5 V com um módulo buck LM2596. A regra mais importante é ligar o GND das duas fontes entre si; sem GND comum, a linha de sinal fica sem referência e o servo ou a fita se comporta de forma aleatória. Explicamos isso em detalhes em Arduino reiniciando sozinho? e GND e terra comum.

Módulo abaixador (buck) LM2596
Módulo buck LM2596: reduz 12 V para 5 V com eficiência e é ideal para alimentar cargas como servos, relés ou fitas de LED separadamente do ESP32. A saída é ajustada num trimpot; regule para 5 V com um multímetro antes de ligar qualquer coisa.
Você também pode suavizar os picos de corrente no software. Ligue o Wi-Fi antes de mover servos ou acender a fita de LED; limite o brilho da fita com setBrightness(); acione servos e relés com algumas centenas de milissegundos de intervalo, e não todos de uma vez. Reduzir a potência de transmissão do Wi-Fi com WiFi.setTxPower() também diminui o pico de corrente; detalhes em ESP32 não conecta ao Wi-Fi.

Desativar o detector de brownout resolve?

A “solução” mais comum na internet é desligar o detector com uma única linha. O código abaixo desativa o detector zerando o registrador de brownout do ESP32, e a mensagem de erro some. Mas as quedas de tensão continuam; só não tem mais ninguém avisando. Use este código apenas para diagnóstico: se a placa funciona bem com o detector desligado, você confirmou que o problema é mesmo a alimentação. Depois, apague a linha e corrija a fonte.

C++ (Arduino IDE)
1#include "soc/soc.h"
2#include "soc/rtc_cntl_reg.h"
3
4void setup() {
5  // YALNIZ TEŞHİS İÇİN: brownout dedektörünü kapat / DIAGNOSIS ONLY: disable the brownout detector
6  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
7
8  Serial.begin(115200);
9  Serial.println("Brownout dedektoru kapali / brownout detector disabled");
10}
11
12void loop() {
13}
Não deixe o detector desativado de forma permanente. WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) não só cala o aviso: ela também desativa o reset de hardware do detector e a função dele de desligar a flash e o rádio com tensão baixa, então o chip continua funcionando sem proteção muito abaixo do mínimo de 3,0 V. Quando a tensão cai abaixo de 2,4 V, dados gravados na flash (Preferences, EEPROM, LittleFS), ou até o próprio programa durante uma atualização OTA, podem se corromper, o Wi-Fi pode cair sem motivo aparente e a placa pode passar a travar com erros Guru Meditation ou congelar de vez. A configuração não é permanente: o chip reativa o detector a cada boot, então a linha precisa ser a primeira do setup(), e, quando você a apaga, a proteção volta. Esse registrador existe no ESP32 clássico, no S2, no S3 e no C3; modelos mais novos como o ESP32-C6 não o têm, e o código não compila. A correção de verdade é sempre consertar a alimentação.

Códigos de causa rst: o ESP32 diz por que reiniciou

O valor rst: que a ROM imprime a cada boot mostra como terminou a execução anterior. Num boot normal, o valor de boot é 0x13 (SPI_FAST_FLASH_BOOT), ou seja, a placa inicia o programa a partir da flash. A tabela abaixo lista os códigos que você vai ver com mais frequência. Os códigos da ROM nem sempre bastam sozinhos: ESP.restart() e um reinício depois de um Guru Meditation aparecem os dois como 0xc, enquanto um brownout aparece como 0xc ou 0x3, conforme a versão do core. Para diferenciá-los, use o sketch com esp_reset_reason() da próxima seção.

Código rstNomeO que significa
0x1POWERON_RESETA alimentação foi ligada pela primeira vez ou o botão EN foi pressionado
0x3SW_RESETReset por software de todo o sistema digital; versões mais novas do core também o mostram depois de um brownout
0x5DEEPSLEEP_RESETA placa acordou do deep sleep (normal)
0x7 / 0x8TG0WDT_SYS_RESET / TG1WDT_SYS_RESETUm watchdog de grupo de timers resetou o sistema por hardware; as interrupções ficaram desativadas por tempo demais ou nem o tratador de pânico conseguiu rodar
0x9RTCWDT_SYS_RESETO watchdog do RTC resetou o núcleo digital
0xcSW_CPU_RESETReinício por software: ESP.restart(), depois de um Guru Meditation ou depois de um brownout no core do Arduino
0xfRTCWDT_BROWN_OUT_RESETReset de brownout por hardware: tensão de alimentação instável
0x10RTCWDT_RTC_RESETO watchdog do RTC resetou o chip inteiro, incluindo o RTC; aparece mais em placas que travam durante o boot

Sketch de diagnóstico: imprima o motivo do reset, a memória e a pilha

Carregue o código abaixo como um sketch separado ou acrescente as linhas dele ao setup() e ao loop() do seu projeto com problema. Sempre que a placa iniciar, ela imprime no Monitor Serial o motivo do reset em texto legível, quantas vezes já deu boot e o estado da memória. O contador marcado com RTC_DATA_ATTR fica na memória do RTC, então sobrevive a resets por software e ao deep sleep e só é zerado quando a alimentação é cortada por completo. Se o contador sobe a cada poucos segundos, você sabe na hora que a placa está num loop de resets.

C++ (Arduino IDE)
1#include <esp_system.h>
2
3RTC_DATA_ATTR uint32_t bootCount = 0;   // yazılım resetinde korunur / survives software resets
4
5// Reset nedenini okunabilir yazıya çevir / turn the reset reason into readable text
6const char* reasonText(esp_reset_reason_t r) {
7  switch (r) {
8    case ESP_RST_POWERON:   return "POWERON: guc acilisi ya da EN / power-on or EN button";
9    case ESP_RST_SW:        return "SW: ESP.restart()";
10    case ESP_RST_PANIC:     return "PANIC: Guru Meditation";
11    case ESP_RST_INT_WDT:   return "INT_WDT: kesme watchdog'u / interrupt watchdog";
12    case ESP_RST_TASK_WDT:  return "TASK_WDT: gorev watchdog'u / task watchdog";
13    case ESP_RST_WDT:       return "WDT: diger watchdog / other watchdog";
14    case ESP_RST_DEEPSLEEP: return "DEEPSLEEP: derin uykudan uyanma / deep sleep wake-up";
15    case ESP_RST_BROWNOUT:  return "BROWNOUT: gerilim dusmesi / supply voltage dropped";
16    default:                return "UNKNOWN: bilinmiyor / unknown";
17  }
18}
19
20void setup() {
21  Serial.begin(115200);
22  delay(1000);                          // Seri Monitör'ün açılmasını bekle / wait for the Serial Monitor
23  bootCount++;
24  Serial.printf("Acilis sayisi / boot count: %u\n", (unsigned)bootCount);
25  Serial.printf("Reset nedeni / reset reason: %s\n", reasonText(esp_reset_reason()));
26}
27
28void loop() {
29  // Bellek durumu / memory status
30  Serial.printf("Bos heap / free heap: %u B, en dusuk / minimum: %u B, en buyuk blok / largest block: %u B\n",
31                (unsigned)ESP.getFreeHeap(), (unsigned)ESP.getMinFreeHeap(), (unsigned)ESP.getMaxAllocHeap());
32  // loopTask yığınında hiç kullanılmamış en küçük alan / smallest unused space on the loopTask stack
33  Serial.printf("loopTask bos yigin / free stack: %u B\n", (unsigned)uxTaskGetStackHighWaterMark(NULL));
34  delay(5000);
35}

Os valores impressos no loop também revelam problemas silenciosos. Se o heap livre cai um pouco a cada passagem, seu programa tem um vazamento de memória e a placa vai travar mais cedo ou mais tarde. Se o maior bloco é bem menor que o heap livre, a memória está fragmentada; isso costuma vir de objetos String que crescem e encolhem o tempo todo dentro do loop. Se a pilha livre da loopTask cai abaixo de algumas centenas de bytes, um estouro de pilha está logo ali. Se o motivo do reset for BROWNOUT, concentre-se nas seções de alimentação; se for PANIC, TASK_WDT ou INT_WDT, nas seções de software abaixo.

O que é um Guru Meditation Error? Leia a saída do travamento linha por linha

Um Guru Meditation Error é o relatório de travamento que o tratador de pânico imprime quando a CPU do ESP32 encontra um erro do qual não consegue se recuperar; o nome vem da tela de erro dos antigos computadores Amiga. O relatório assusta à primeira vista, mas só algumas linhas importam. Core 1 diz em qual núcleo o erro aconteceu: no Arduino, setup() e loop() rodam no núcleo 1, enquanto a pilha do Wi-Fi roda no núcleo 0. O nome entre parênteses é o tipo de exceção. Quando o relatório termina, a placa imprime “Rebooting...” e reinicia; você vai ver rst:0xc na linha de boot.

LinhaSignificado
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. (exceção não tratada)O código no núcleo 1 tentou ler de um endereço inválido e o erro não foi tratado
PC : 0x400d1a2cEndereço da instrução que travou; se começa com 0x400d, era o seu código ou uma biblioteca rodando a partir da flash
EXCCAUSE: 0x0000001cCódigo da exceção; 0x1c, ou seja, 28, significa LoadProhibited
EXCVADDR: 0x00000000O endereço acessado; 0 ou um número muito pequeno aponta para um ponteiro nulo
Backtrace: 0x400d1a29:0x3ffb2270 0x400d0f6e:0x3ffb2290 ...Cadeia de chamadas; cada par é PC:SP e pode ser convertido numa linha de código com o decodificador
ELF file SHA256: ... (impressão digital do arquivo ELF)Impressão digital do programa que travou; o decodificador precisa exatamente da mesma compilação
Rebooting... (reiniciando)O tratador de pânico reinicia o chip por software

LoadProhibited, StoreProhibited e outros tipos de exceção

ExceçãoEXCCAUSEO que aconteceu?Causa comum
LoadProhibited28 (0x1c)Leitura de um endereço inválidoPonteiro nulo ou não inicializado, objeto já excluído
StoreProhibited29 (0x1d)Escrita num endereço inválidoEscrita por um ponteiro nulo, buffer que ultrapassa o fim de um array
InstrFetchProhibited20 (0x14)Busca de instrução num endereço inválidoPonteiro de função ou callback não atribuído
IllegalInstruction0 (0x0)Instrução inválidaPilha corrompida, return faltando numa função que precisa retornar um valor
LoadStoreAlignment9 (0x9)Acesso à memória desalinhadoConverter um array de bytes para um tipo como uint32_t*
IntegerDivideByZero6 (0x6)Divisão inteira por zeroDividir por um contador que pode ser zero
Unhandled debug exception (exceção de depuração não tratada)-Exceção de depuraçãoStack canary watchpoint triggered: estouro de pilha
Interrupt wdt timeout on CPU0/CPU1 (timeout do watchdog de interrupção)-O watchdog de interrupção expirouISR longa, Serial ou delay dentro de uma ISR
Cache disabled but cached memory region accessed (cache desativado, mas região em cache acessada)-Código na flash acessado enquanto a flash estava ocupadaRotina de interrupção sem IRAM_ATTR

O mais comum desses erros é usar um ponteiro nulo. NULL é o endereço 0, e no ESP32 não há memória legível perto do endereço 0, então ler de onde um ponteiro vazio aponta dá LoadProhibited e escrever ali dá StoreProhibited. Nesse caso, o EXCVADDR é uma pista perfeita: 0x00000000 aponta para o próprio ponteiro, enquanto valores pequenos como 0x00000004 ou 0x00000010 apontam para um campo dentro de um ponteiro vazio (NULL mais o deslocamento do campo). Em projetos Arduino, a causa mais comum é uma função que retorna NULL para dizer “não encontrado” e esse valor ser usado sem verificação. No exemplo abaixo, strstr() retorna NULL se não encontra o texto; sem verificação, a placa trava com EXCVADDR 0x00000005.

C++ (Arduino IDE)
1const char* response = "temp=23.5;hum=40";   // sunucudan gelen yanıt / reply from a server
2
3void setup() {
4  Serial.begin(115200);
5  delay(500);
6
7  // YANLIŞ: "pres=" yoksa strstr NULL döner ve kart çöker (EXCVADDR 0x00000005)
8  // WRONG: if "pres=" is missing strstr returns NULL and the board crashes (EXCVADDR 0x00000005)
9  // float pressure = atof(strstr(response, "pres=") + 5);
10
11  // DOĞRU: işaretçiyi kullanmadan önce NULL kontrolü yap / RIGHT: check for NULL before using the pointer
12  const char* found = strstr(response, "pres=");
13  if (found != nullptr) {
14    float pressure = atof(found + 5);
15    Serial.println(pressure);
16  } else {
17    Serial.println("pres alani bulunamadi / pres field not found");
18  }
19}
20
21void loop() {
22}
Crie alguns hábitos contra ponteiros nulos: inicialize ponteiros com nullptr ao declará-los, verifique o valor de retorno das funções begin() das bibliotecas, defina o ponteiro como nullptr depois de excluir um objeto e garanta que o índice seja menor que o tamanho do array ao escrever em arrays. Se você colocar os avisos do compilador em Todos em Arquivo > Preferências no Arduino IDE, vai ver um return faltando e bugs parecidos já na compilação.

Estouro de pilha: o erro “Stack canary watchpoint triggered”

No ESP32, cada tarefa tem uma pilha de tamanho fixo, onde ficam as variáveis locais, as chamadas de função e os endereços de retorno. No Arduino, a loopTask, que roda setup() e loop(), tem uma pilha de 8192 bytes. Declarar um array local de 10.000 bytes dentro do loop(), uma função que chama a si mesma (recursão) ou uma função de biblioteca com muitas variáveis locais vai passar desse limite. No fim da pilha existe uma área de guarda (canary); quando a pilha chega nela, a placa imprime Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception) e, logo abaixo, Debug exception reason: Stack canary watchpoint triggered (loopTask). O nome entre parênteses é a tarefa cuja pilha estourou. O mesmo problema às vezes aparece como ***ERROR*** A stack overflow in task loopTask has been detected. Veja como corrigir:

  • Tire os arrays grandes da pilha: declare o array como global ou coloque static na frente; assim ele fica na RAM permanente, e não na pilha.
  • Aumente a pilha da loopTask: coloque SET_LOOP_TASK_STACK_SIZE(16 * 1024); no topo do sketch para levar a pilha do loop() a 16 KB.
  • Dê espaço suficiente às suas próprias tarefas: no ESP32, o tamanho de pilha passado para xTaskCreate e xTaskCreatePinnedToCore é em bytes, e não em palavras como no FreeRTOS de outras plataformas. 1024 bytes é pouco até para uma tarefa que usa Serial.printf; comece com 4096.
  • Meça: uxTaskGetStackHighWaterMark(NULL) retorna, em bytes, a menor quantidade de pilha que a tarefa nunca usou até agora; se cair abaixo de algumas centenas de bytes, aumente a pilha.
  • Evite recursão: transforme funções que chamam a si mesmas em laços ou limite a profundidade delas.

Watchdog de tarefa: o erro “task_wdt: Task watchdog got triggered”

Um watchdog é um timer que percebe um programa travado e salva a placa. O Task Watchdog (Task WDT) do ESP32 espera que as tarefas registradas nele avisem “estou vivo” em intervalos regulares. No core do Arduino, ele vigia por padrão a tarefa ociosa (IDLE) do núcleo 0, com um tempo limite de 5 segundos. Se uma tarefa rodando no núcleo 0 não libera a CPU por 5 segundos, a tarefa IDLE não consegue rodar e o Monitor Serial mostra uma mensagem que começa com E (10257) task_wdt: Task watchdog got triggered. Em seguida vem a lista das tarefas que não resetaram o watchdog a tempo (geralmente - IDLE (CPU 0)) e, em Tasks currently running:, as tarefas que estavam rodando naquele momento. No core do Arduino, isso dispara um pânico com a linha task_wdt: Aborting. e a placa reinicia.

As causas mais comuns são: um laço fixado no núcleo 0 com xTaskCreatePinnedToCore que nunca chama vTaskDelay(), um laço while esperando a resposta de um sensor sem tempo limite, ou delay() e operações longas dentro dos callbacks de bibliotecas como a AsyncWebServer. No último caso, você vê a tarefa async_tcp na lista em vez da IDLE. A correção é dividir trabalhos longos em pedaços pequenos e colocar esperas curtas como vTaskDelay(1) nos seus laços. A própria função loop() não é vigiada por padrão; se quiser, chame enableLoopWDT() no setup() para que a placa também reinicie quando o loop() travar por mais de 5 segundos. Desligar o watchdog com disableCore0WDT() esconde o erro, mas não conserta o código travado. Para saber mais sobre tarefas e núcleos, veja ESP32: FreeRTOS e dois núcleos. O código abaixo mostra tanto uma estrutura de tarefa correta quanto as precauções contra estouro de pilha:

C++ (Arduino IDE)
1SET_LOOP_TASK_STACK_SIZE(16 * 1024);   // loop() yığını 8 KB yerine 16 KB / loop() stack 16 KB instead of 8 KB
2
3volatile uint32_t sampleCount = 0;
4
5// 0. çekirdekte çalışan görev / task running on core 0
6void sensorTask(void* parameter) {
7  for (;;) {
8    sampleCount = sampleCount + 1;       // sensörünü burada oku / read your sensor here
9    vTaskDelay(pdMS_TO_TICKS(10));       // IDLE görevine sıra ver, task_wdt tetiklenmez / let IDLE run, no task_wdt
10  }
11}
12
13void setup() {
14  Serial.begin(115200);
15  // Yığın boyutu bayt cinsindendir: 4096 bayt / stack size is in bytes: 4096 bytes
16  xTaskCreatePinnedToCore(sensorTask, "sensorTask", 4096, NULL, 1, NULL, 0);
17}
18
19void loop() {
20  static uint8_t buffer[10000];          // static: yığında değil kalıcı RAM'de / static: in RAM, not on the stack
21  memset(buffer, 0, sizeof(buffer));
22
23  Serial.printf("Ornek / samples: %u, loopTask bos yigin / free stack: %u B\n",
24                (unsigned)sampleCount, (unsigned)uxTaskGetStackHighWaterMark(NULL));
25  delay(1000);
26}

Interrupt wdt timeout e IRAM_ATTR: travamentos em interrupções

O Interrupt Watchdog (Interrupt WDT) é bem menos paciente: se uma rotina de interrupção (ISR) ou um trecho de código com as interrupções desativadas leva mais de 300 ms, a placa trava com Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1). Usar Serial.print, delay(), I2C ou Wi-Fi dentro de uma ISR é a causa mais comum. A memória flash é outra armadilha: enquanto Preferences, EEPROM ou LittleFS gravam na flash, o cache da flash fica desativado por um instante. Se uma interrupção chega nesse momento e a rotina dela está na flash, a placa informa Cache disabled but cached memory region accessed. A correção é marcar as ISRs com IRAM_ATTR para que fiquem na RAM e só levantar uma flag dentro delas; o loop() faz o trabalho de verdade. Variáveis compartilhadas entre uma ISR e o loop() precisam ser volatile.

C++ (Arduino IDE)
1const int BUTTON_PIN = 27;              // buton GPIO 27 ile GND arasında / button between GPIO 27 and GND
2volatile bool buttonPressed = false;    // ISR ile loop arasında paylaşılan bayrak / flag shared by the ISR and loop
3uint32_t pressCount = 0;
4
5void IRAM_ATTR onButton() {             // IRAM_ATTR: fonksiyon flaşta değil RAM'de durur / the function lives in RAM, not flash
6  buttonPressed = true;                 // yalnızca bayrak kaldır, Serial yok / only set a flag, no Serial
7}
8
9void setup() {
10  Serial.begin(115200);
11  pinMode(BUTTON_PIN, INPUT_PULLUP);
12  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), onButton, FALLING);
13}
14
15void loop() {
16  if (buttonPressed) {
17    buttonPressed = false;
18    pressCount++;
19    Serial.printf("Butona basildi / button pressed: %u\n", (unsigned)pressCount);   // yavaş iş burada / slow work here
20  }
21}

Transformando o Backtrace em linha de código com o ESP Exception Decoder

Os endereços da linha Backtrace não dizem nada sozinhos; a ferramenta que os converte no arquivo, na função e no número da linha do seu código-fonte se chama ESP Exception Decoder. No antigo Arduino IDE 1.8, era um plugin adicionado ao menu Ferramentas. No Arduino IDE 2, você usa uma extensão de mesmo nome feita pela comunidade:

  1. Baixe o arquivo .vsix na seção Releases do projeto dankeboy36/esp-exception-decoder no GitHub. Para o Arduino IDE 2, escolha uma versão 1.x; as versões 2.x mais novas são feitas para o VS Code.
  2. Feche o Arduino IDE e copie o arquivo para %UserProfile%\.arduinoIDE\plugins no Windows ou ~/.arduinoIDE/plugins no macOS e no Linux; crie a pasta se ela não existir.
  3. Abra o IDE, abra o sketch que trava, compile com Verificar e carregue na placa.
  4. Abra o Monitor Serial e espere o travamento acontecer de novo.
  5. Abra a paleta de comandos com Ctrl+Shift+P (Cmd+Shift+P no macOS) e execute ESP Exception Decoder: Show Decoder Terminal.
  6. Copie o bloco do Guru Meditation no Monitor Serial, incluindo a linha Backtrace, e cole no terminal que se abre; a ferramenta mostra cada endereço com o nome do arquivo, a função e o número da linha.

Se não conseguir instalar a extensão, você pode fazer o mesmo trabalho à mão. O menu Sketch > Exportar binário compilado deixa um arquivo com extensão .elf na pasta build dentro da pasta do sketch. O comando xtensa-esp32-elf-addr2line -pfiaC -e sketch.ino.elf 0x400d1a29 0x400d0f6e, da toolchain do ESP32, converte esses endereços em nomes de função e números de linha. Se você usa o PlatformIO, basta acrescentar a linha monitor_filters = esp32_exception_decoder ao platformio.ini; a saída do travamento passa a ser decodificada automaticamente no monitor serial.

O decodificador só dá resultados corretos com o arquivo .elf exatamente da mesma compilação que travou. Se você muda uma única linha e compila de novo, os endereços se deslocam e a saída aponta para as linhas erradas. Se a linha Backtrace termina com CORRUPTED, a pilha está danificada; isso costuma ser sinal de estouro de pilha ou de um buffer que ultrapassou seus limites.

Pinos de strapping: como GPIO0, GPIO2, GPIO12 e GPIO15 podem atrapalhar o boot

Quando o ESP32 inicia, ele olha o nível de certos pinos para decidir como dar boot. Eles se chamam pinos de strapping, e só o nível deles no momento do reset importa; depois do boot, podem ser usados como GPIOs normais. O problema aparece quando um sensor, botão ou módulo ligado a um deles puxa o pino para o nível errado no boot. Aí a placa nem inicia o programa, entra no modo de programação ou não consegue ler a flash; de fora, isso também parece “o ESP32 não liga” ou “fica reiniciando”. Você pode ver o mapa completo de pinos da sua placa na ferramenta Pinagem.

PinoResistor internoFunção no bootO que acontece no nível errado?
GPIO0Pull-upLOW seleciona o modo de programação (download); HIGH, o boot normalboot:0x3 (DOWNLOAD_BOOT) e aguardando gravação; o programa não roda
GPIO2Pull-downPrecisa estar em LOW ou flutuando para entrar no modo de programação; não importa no boot normalUm circuito que o puxa para HIGH impede o carregamento
GPIO12 (MTDI)Pull-downSeleciona a tensão de alimentação da flash: LOW 3,3 V, HIGH 1,8 VSe estiver em HIGH, uma flash de 3,3 V não é alimentada direito; a placa não dá boot ou entra num loop de resets
GPIO15 (MTDO)Pull-upLOW silencia as mensagens de boot da ROMAs linhas de boot não aparecem no Monitor Serial, o que dificulta o diagnóstico
GPIO5Pull-upDefine a temporização do SDIORaramente causa problemas em placas de desenvolvimento
Um resistor de pull-up, relé ou módulo de sensor no GPIO12 que puxa o pino para HIGH no boot é o motivo mais escondido de um ESP32 nem iniciar. Se você precisar usar esse pino, garanta que o módulo o deixe em LOW no momento do boot. Outra opção é o comando espefuse.py set_flash_voltage 3.3V, que vem com o esptool: ele grava a tensão da flash de forma permanente num eFuse e elimina o efeito do GPIO12 no boot; porém, isso não pode ser desfeito e só deve ser feito em módulos com flash de 3,3 V (como o ESP32-WROOM-32).

Placas mais novas têm outros pinos de strapping: no ESP32-S3 são GPIO0, GPIO3, GPIO45 e GPIO46, e no ESP32-C3 GPIO2, GPIO8 e GPIO9 afetam o boot. O ESP32-S3 usa os mesmos nomes de exceção Xtensa do ESP32 clássico. Já no ESP32-C3, baseado em RISC-V, você vê Load access fault em vez de LoadProhibited e Store access fault em vez de StoreProhibited, e o registrador MTVAL assume o papel do EXCVADDR. A mensagem de brownout é a mesma em todos os modelos.

ESP32 e Raspberry Pi Pico em MicroPython

Se você programa o ESP32 em MicroPython, o brownout acontece exatamente do mesmo jeito, porque o problema está no hardware, não no software. Já os erros no código Python aparecem como um Traceback legível em vez de um Guru Meditation, e a placa raramente trava. Você pode ler o motivo do reset com machine.reset_cause(), mas atenção: o port do MicroPython para ESP32 não retorna o brownout como um valor separado, e sim como PWRON_RESET, junto com o power-on. Se a placa fica iniciando com PWRON_RESET sem você ter mexido nela, desconfie de novo da alimentação. O código abaixo é para o ESP32; no Raspberry Pi Pico, o módulo machine conhece menos tipos de reset. No Pico, o regulador buck-boost da entrada VSYS funciona com qualquer tensão de 1,8 a 5,5 V, então problemas de brownout são bem mais raros; para conhecer a placa, veja O que é o Raspberry Pi Pico?

MicroPython
1import machine, gc, time
2
3# Reset nedenleri (ESP32 için) / reset causes (for ESP32)
4causes = {
5    machine.PWRON_RESET: "PWRON: guc acilisi ya da brownout / power-on or brownout",
6    machine.HARD_RESET: "HARD: cokme ya da machine.reset() / crash or machine.reset()",
7    machine.WDT_RESET: "WDT: watchdog",
8    machine.DEEPSLEEP_RESET: "DEEPSLEEP: derin uykudan uyanma / deep sleep wake-up",
9    machine.SOFT_RESET: "SOFT: Ctrl+D ile yazilim reseti / soft reset with Ctrl+D",
10}
11print("Reset nedeni / reset cause:", causes.get(machine.reset_cause(), "bilinmiyor / unknown"))
12
13while True:
14    gc.collect()                                     # çöp toplayıcıyı çalıştır / run the garbage collector
15    print("Bos RAM / free RAM:", gc.mem_free(), "bayt / bytes")
16    time.sleep(5)

Erros comuns e soluções

SintomaCausa provávelSolução
Brownout detector was triggered quando o Wi-Fi iniciaCabo, porta ou regulador não acompanham o pico de correnteCabo curto e grosso, adaptador de 1 A, 470 µF + 100 nF entre 3V3 e GND
Reset quando um servo gira ou um relé comutaA carga divide a linha de alimentação do ESP32Alimente a carga com uma fonte de 5 V separada e una os GNDs
Os resets começam quando a bateria descarrega um poucoDropout do AMS1117Use um LDO ou um conversor buck-boost
Guru Meditation, EXCVADDR 0x00000000Ponteiro nuloVerifique o ponteiro antes de usá-lo
Stack canary watchpoint triggered (loopTask) (pilha cheia)A pilha do loop() está cheiaTorne os arrays grandes static ou use SET_LOOP_TASK_STACK_SIZE
task_wdt: - IDLE (CPU 0)Laço sem esperas no núcleo 0Coloque vTaskDelay no laço
Interrupt wdt timeout on CPU1 (timeout do watchdog de interrupção)A ISR demora demaisSó levante uma flag na ISR, use IRAM_ATTR
Placa em silêncio, boot:0x3 e aguardando gravaçãoGPIO0 em LOW no bootRetire o circuito do GPIO0 e pressione EN
A placa nem dá boot, erro de leitura da flashGPIO12 em HIGH no bootPasse o pull-up ou o módulo do GPIO12 para outro pino
Failed to connect to ESP32 ao carregarGPIO2 em HIGH ou a placa não consegue entrar no modo de programaçãoLibere o GPIO2 e segure BOOT quando o carregamento começar
Siga a ordem ao procurar o defeito: primeiro troque o cabo e a fonte, depois coloque o capacitor e então alimente servos e LEDs separadamente. Se os resets continuarem depois que a mensagem de brownout sumir, confira o motivo do reset no sketch de diagnóstico e passe para as seções de software. Se você colocar Ferramentas > Core Debug Level em Verbose, o core do ESP32 imprime mensagens bem mais detalhadas sobre o Wi-Fi e os eventos do sistema. Para problemas de carregamento, veja também Erro ao carregar código no Arduino.

Sua placa está estável: e agora?

  • Dispositivo que poupa bateria: com o deep sleep do ESP32, ponha a placa para dormir entre as medições e consuma corrente na faixa dos microampères.
  • Atualizações sem fio: carregue código sem cabo USB com o OTA no ESP32.
  • Painel em tempo real: acompanhe os dados dos sensores ao vivo no navegador com WebSocket no ESP32.
  • Envie notificações: com um bot do Telegram com ESP32, receba no celular o motivo do reset toda vez que a placa reiniciar.
  • Show de luzes: controle uma fita WS2812B NeoPixel com segurança usando uma fonte separada.

A maioria dos problemas de reinício do ESP32 é ou de alimentação ou de algumas linhas de código com bug; quando você lê a mensagem do jeito certo, os dois se resolvem rápido. Para revisar o básico da placa, dê uma olhada em O que é o ESP32? No app BlueGrays, você encontra projetos com ESP32 usando LEDs, servos, fitas NeoPixel, conexão Wi-Fi, servidor web, atualizações OTA e deep sleep, cada um com esquema do circuito e código passo a passo, para testar em projetos reais as técnicas de alimentação e diagnóstico que aprendeu aqui.

Perguntas frequentes

Como resolver o erro ESP32 brownout detector was triggered?

Esse erro significa que a tensão de alimentação do ESP32 caiu por um instante abaixo de cerca de 2,43 V. Primeiro, use um cabo USB curto e grosso com uma fonte de 5 V de pelo menos 1 A; depois, coloque um capacitor eletrolítico de 100–470 µF e um cerâmico de 100 nF entre 3V3 e GND. Alimente cargas como servos, relés e fitas de LED com uma fonte separada e ligue os GNDs entre si.

Por que meu ESP32 fica reiniciando?

As causas mais comuns são alimentação insuficiente (brownout), travamentos de software (Guru Meditation), timeouts do watchdog e pinos de strapping presos no nível errado no boot. Abra o Monitor Serial em 115200 baud e pressione EN; a última mensagem antes do reset e o código rst no boot mostram a causa. A função esp_reset_reason() também permite ler isso pelo código.

O que significa Guru Meditation Error LoadProhibited?

Significa que um código no ESP32 tentou ler de um endereço de memória inválido. Se o EXCVADDR for 0 ou um número muito pequeno, quase com certeza foi usado um ponteiro nulo. Cole a linha Backtrace no ESP Exception Decoder para achar o arquivo e a linha onde o erro aconteceu.

Posso desativar o detector de brownout do ESP32?

Sim, a linha WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) o desativa, mas isso só cala o aviso. Como as quedas de tensão continuam, os dados na flash podem se corromper e a placa pode travar com outros erros. Use isso só por pouco tempo, para confirmar que o problema vem da alimentação.

Como resolver o erro ESP32 Task watchdog got triggered?

Essa mensagem significa que uma tarefa vigiada não liberou a CPU por 5 segundos; no Arduino, a lista geralmente mostra a tarefa IDLE do núcleo 0. Coloque vTaskDelay() nos laços das suas próprias tarefas, use tempos limite ao esperar sensores e evite delay() ou operações longas nos callbacks do servidor web. Desligar o watchdog esconde o erro, mas não conserta a causa.

De que fonte de alimentação o ESP32 precisa?

A Espressif recomenda uma fonte capaz de fornecer pelo menos 500 mA para o ESP32; na prática, um adaptador de 5 V e 1 A deixa uma margem segura. Se você usa um ESP32-CAM ou acrescenta cargas como servos ou fitas de LED, escolha uma fonte de 2 A ou mais e, se possível, alimente essas cargas por uma linha separada.

Ver todos os projetos
LED piscando com ESP32
#103Iniciante

LED piscando com ESP32

Ensina o uso básico de uma saída GPIO no ESP32. Fazemos um LED piscar ligando e desligando um pino digital. É a versão para ESP32 do clássico projeto blink do Arduino UNO: os comandos básicos de blink no ambiente Arduino são os mesmos, mas a disposição dos pinos e os níveis de 3,3 V dos GPIOs do ESP32 diferem dos do Arduino UNO.

4.7(37)
99
Conexão Wi-Fi STA com ESP32 e display LCD
#127Avançado

Conexão Wi-Fi STA com ESP32 e display LCD

Neste projeto, conectamos o ESP32 à rede Wi-Fi de casa no modo estação (STA), de forma segura e tolerante a falhas. Guardamos o SSID e a senha em um arquivo secrets.h separado para evitar que sejam expostos no Git, configuramos um mecanismo de reconexão automática e exibimos o nível de sinal RSSI e o endereço IP em um display LCD I2C. O LED integrado funciona como indicador de status. É um gerenciador de conexão pronto para uso em produção.

4.4(21)
34
Servo motor com ESP32 (controle por potenciômetro)
#118Intermediário
Premium

Servo motor com ESP32 (controle por potenciômetro)

Neste projeto, controlamos um servo motor SG90 com um potenciômetro. Ajustamos o ângulo do servo mapeando o valor analógico lido do potenciômetro para a faixa de 0 a 180 graus. A biblioteca ESP32Servo gera sinais para o servo nos GPIOs do ESP32 adequados e capazes de operar como saída; este projeto usa o GPIO 18. Esse é um método básico de controle para braços robóticos, estabilizadores de câmera e mecanismos de portas automáticas.

4.3(29)
42
Controle de fita WS2812B NeoPixel com ESP32
#126Intermediário
Premium

Controle de fita WS2812B NeoPixel com ESP32

Os LEDs endereçáveis WS2812B (NeoPixel) são LEDs RGB inteligentes que podem ser controlados em cadeia por um único pino de dados. Neste projeto, vamos controlar uma fita WS2812B de 8 LEDs com a biblioteca Adafruit_NeoPixel para criar uma animação suave de arco-íris. Embora o nível lógico de 3,3V do ESP32 funcione sem problemas na maioria dos lotes de WS2812B, vamos mostrar uma solução com um resistor de 470Ω em série e um capacitor de 1.000µF para casos de instabilidade.

4.9(19)
30
Servidor web assíncrono com ESP32 (IP no LCD)
#129Avançado

Servidor web assíncrono com ESP32 (IP no LCD)

Neste projeto, transformamos o ESP32 em um servidor web assíncrono que você pode controlar pelo celular ou computador na mesma rede Wi-Fi. Com a biblioteca ESPAsyncWebServer, o servidor processa várias requisições ao mesmo tempo (ao contrário do WebServer.h tradicional, que bloqueia a execução ao processar uma requisição). Você poderá abrir o endereço IP do ESP32 no navegador e clicar nos botões ON/OFF (as rotas /on e /off) para ligar e desligar o LED conectado ao GPIO 5.

4.8(16)
26
ESP32 em sono profundo — Economia de bateria (OLED + contador na RAM RTC)
#135Avançado
Premium

ESP32 em sono profundo — Economia de bateria (OLED + contador na RAM RTC)

O modo de sono profundo do ESP32 reduz o consumo de corrente para ~10 µA ao desligar a CPU e a maioria dos periféricos, sendo essencial para dispositivos IoT alimentados por bateria. Neste projeto, usamos três fontes de despertar: um temporizador (15 segundos), um pino externo (EXT0 — botão no GPIO 33) e toque (T0/GPIO 4). As variáveis marcadas com RTC_DATA_ATTR são preservadas durante o sono profundo, mantendo os contadores de inicializações e de despertares por temporizador e botão.

4.3(10)
16
Atualização OTA no ESP32 — firmware sem fio (com display LCD)
#132Avançado
Premium

Atualização OTA no ESP32 — firmware sem fio (com display LCD)

Neste projeto, você aprende a carregar um novo firmware no ESP32 por Wi-Fi, sem cabo USB. Com a biblioteca ArduinoOTA, o ESP32 fica visível na rede e aparece automaticamente como bluegrays-ota na aba "Porta de rede" do Arduino IDE. A primeira carga é feita por USB, e todas as atualizações seguintes são sem fio — um recurso essencial para dispositivos em campo. O LCD I2C mostra o estado do Wi-Fi, o IP, o nome do host, a porcentagem de envio por OTA e as mensagens de erro em turco e inglês.

4.6(14)
22
Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)
#145Avançado
Premium

Alarme de movimento com ESP32 (PIR + buzzer + LED + Telegram)

Um sistema de alarme de segurança inteligente que aciona o buzzer e o LED quando o sensor PIR detecta movimento e, ao mesmo tempo, envia uma notificação instantânea ao proprietário pelo Telegram. Inclui um intervalo de espera de 30 segundos para limitar a frequência dos alarmes repetidos; esse mecanismo não valida as detecções do PIR nem elimina disparos falsos. Pode ser usado na segurança de casas, no monitoramento de garagens, depósitos ou salas de trabalho.

0.0(0)
9