Quer usar bateria com o ESP32?
Pois, trago informações técnicas importantes sobre esse assunto. Sabemos que
esse microcontrolador, quando está transmitindo informações, ele gasta bastante
energia, ou seja, ele consome perto de 190 miliampères. Neste vídeo, então,
quero te mostrar como economizar energia do ESP32 com o chamado “DEEP SLEEP”. Vamos
configurar o chip para entrar neste modo, conhecer as maneiras de sair deste
modo e criar um exemplo envolvendo três maneiras diferentes de despertar o
ESP32.
Vale lembrar, pessoal, que não
é processador dele que gasta muita energia, mas, sim, o radio. E a economia de
energia é muito importante. Isso, porque, não raro, os Endpoints, que são os
circuitos que ficam enviando informação, eles são alimentados por bateria e
precisam durar até cinco anos. Lembrando que tem alguns fabricantes que
prometem até dez anos de duração e isso é válido quando a bateria é de boa
qualidade e o Endpoint precisa trabalhar pouco. Do contrário, aconselho que
você use o Deep Sleep para economizar energia do seu circuito.
Introdução
O ESP32 possui, portanto, um
modo de economia de energia, chamado “Deep Sleep”. Nesse modo, as CPUs, a
maior parte da RAM e todos os periféricos digitais com clock estão
desligados. As únicas partes do chip que ainda podem ser ligadas são:
controlador RTC, periféricos RTC (incluindo o coprocessador ULP) e memórias
RTC.
Temos várias maneiras de
despertar o ESP32 quando está adormecido, sendo que as fontes de despertar
podem ser configuradas a qualquer momento antes de entrar no modo Deep Sleep.
Maneiras de despertar o ESP32
São cinco as maneiras de
despertar o ESP32:
·
Timer
·
External wakeup (ext0)
·
External wakeup (ext1)
·
ULP coprocessor wakeup
·
Touchpad
Timer
O controlador RTC possui um
cronômetro incorporado que pode ser usado para ativar o chip após um período de
tempo predefinido. O tempo é especificado com precisão de microssegundos.
esp_deep_sleep_enable_timer_wakeup( uint64_t time_in_us )
time_in_us > é o tempo em
microssegundos
External wakeup (ext0)
O módulo RTC IO contém lógica
para acionar o despertador quando um dos GPIOs RTC entra em um nível lógico
predefinido. O RTC IO faz parte do domínio de energia dos periféricos RTC,
portanto, os periféricos RTC serão mantidos ligados durante o Deep Sleep se
essa fonte de ativação for solicitada.
esp_deep_sleep_enable_ext0_wakeup( gpio_num_t gpio_num , int level)
gpio_num > número do GPIO
usado como fonte de ativação. Apenas os GPIOs com funcionalidade RTC podem ser
usados: 0,2,4,12-15,25-27,32-39.
level > nível de entrada
que acionará o despertador (0 = LOW, 1 = HIGH)
External wakeup (ext1)
O controlador RTC contém
lógica para acionar o despertador usando vários GPIOs RTC.
esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode)
mask > máscara de bits de
números GPIO que causará ativação. Apenas os GPIOs com funcionalidade RTC
podem ser usados neste mapa de bits: 0,2,4,12-15,25-27,32-39.
mode > selecione a função
lógica usada para determinar a condição de ativação:
·
ESP_EXT1_WAKEUP_ALL_LOW: desperta quando todos
os GPIOs selecionados estão em LOW
·
ESP_EXT1_WAKEUP_ANY_HIGH: desperta quando
qualquer um dos GPIOs selecionados está em HIGH
ULP coprocessor wakeup
O coprocessador ULP pode
funcionar enquanto o chip está em Deep Sleep e pode ser usado para pesquisar
sensores, monitorar ADC ou valores do sensor de toque capacitivo e ativar o
chip quando um evento específico for detectado.
O coprocessador ULP faz parte
do domínio de energia dos periféricos RTC e executa o programa armazenado em
memória lenta RTC. Portanto, os periféricos RTC e a memória lenta RTC
serão ativados durante o Deep Sleep se esse modo de ativação for solicitado.
Touchpad
O controlador RTC contém
lógica para acionar o despertador utilizando os sensores de toque capacitivo. A
definição do pino de toque, no entanto, é diferente. Devemos utilizar a
interrupção por toque (touchInterrupt) para cada um dos pinos desejados.
Após configurar as
interrupções, habilitamos o modo de despertar para utilizar os sensores.
//Configure Touchpad as wakeup source esp_sleep_enable_touchpad_wakeup();
Entrando no modo Deep Sleep
Após configurarmos algum modo
para despertar, basta um único comando para colocar o ESP32 em modo Deep Sleep,
gastando 2.5 µA ou menos. Destaco aqui que esse gasto é do chip do ESP e não da
placa, pois esta última gasta mais.
esp_deep_sleep_start();
A partir desse comando, o
ESP32 adormece e não executa as próximas linhas de código por exemplo.
Importante: Todas as
configurações de despertar devem ser feitas antes de executar o comando acima.
Mais algumas informações importantes:
A chamada abaixo retorna a
causa do despertar do ESP32.
1: EXT0 2: EXT1 3:
TIMER 4: TOUCHPAD 5: ULP
esp_sleep_get_wakeup_cause();
Caso configuremos o despertar
pelo touchpad, podemos recuperar qual o GPIO que ocorreu o toque, através do
comando:
esp_sleep_get_touchpad_wakeup_status();
Toda vez que o ESP32
despertar, ele passará no setup novamente. Sendo assim todas as variáveis que
não estão definidas na memória do RTC, voltarão ao seu estado de origem.
Para manter as variáveis em
memória mesmo após adormecer, utilize a declaração da variável como o exemplo
abaixo:
//RTC_DATA_ATTR aloca a variável na memória RTC RTC_DATA_ATTR int bootCount = 0;
Demonstração
No vídeo você vê o programa
funcionando, conforme a imagem.
WiFi NodeMCU-32S ESP-WROOM-32
Montagem
Deixo aqui o esquemático do
projeto.
Programa
Faremos agora um programa no
qual configuraremos o ESP32 para entrar em modo Deep Sleep. Este será
despertado de três maneiras diferentes: uma por External wakeup (ext0), outra
por Timer e outra por Touchpad. Elas não podem funcionar juntas, portanto,
utilizaremos uma variável que será um contador de quantas vezes o ESP32 deu Boot
para configurar a maneira de despertar.
Biblioteca Necessária
Para controlar o display oled
necessitamos de uma biblioteca externa. Para isso vamos fazer o download da
biblioteca U8g2.
Na Arduino IDE, acesse o menu
Sketch >> Incluir Biblioteca >> Gerenciar Bibliotecas....
Bibliotecas e Variáveis
Incluímos a biblioteca para
controle do display oled, bem como um construtor da instância do controlador do
display. Ainda, alocamos a variável na memória RTC. Definimos a sensibilidade
para aceitação do toque, o fator de conversão de microsegundos para segundos e o
tempo que o ESP32 ficará em modo sleep (em segundos).
#include <U8x8lib.h> //biblioteca para controle do display oled //construtor da instancia do controlador do display //SDA = 21 e SCL = 22 U8X8_SSD1306_128X64_NONAME_SW_I2C display(SCL, SDA, U8X8_PIN_NONE); //RTC_DATA_ATTR aloca a variável na memoria RTC RTC_DATA_ATTR int bootCount = 0; //sensibilidade para aceitação do toque #define Threshold 40 //fator de conversão de microsegundos para segundos #define uS_TO_S_FACTOR 1000000 //tempo que o ESP32 ficará em modo sleep (em segundos) #define TIME_TO_SLEEP 3
Setup
No Setup, incrementamos o número
de vezes que o Boot ocorreu. Chamamos a função para imprimir o motivo do Boot.
Se o número de Boot for PAR, configuramos o ESP32 para despertar através do
botão (EXT0). Já se for múltiplo de 3, configuramos o ESP32 para despertar
depois de um tempo definido. Caso contrário, configuramos os pinos de touch
capacitivo para despertar o ESP32. Por fim, configuramos o Touchpad como wakeup
source e forçamos o ESP32 entrar em modo Sleep.
void setup() { Serial.begin(115200); delay(1000); //incrementa o numero de vezes que o BOOT ocorreu ++bootCount; configureDisplay(); //chama a função para imprimir o motivo do BOOT print_wakeup_reason(); //se o numero de boot for PAR configuramos o ESP32 para despertar através do botão (EXT0) if(bootCount % 2 == 0) { esp_sleep_enable_ext0_wakeup(GPIO_NUM_39,1); //1 = High, 0 = Low } //se for multiplo de 3 configuramos o ESP32 para despertar depois de um tempo definido else if(bootCount % 3 == 0) { esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); } //caso contrario configuramos os pinos de touch capacitivo para despertar o ESP32 else { //Setup interrupt on Touch Pad 5 (GPIO12) touchAttachInterrupt(T5, callback, Threshold); //Configure Touchpad as wakeup source esp_sleep_enable_touchpad_wakeup(); } Serial.println(“entrando em modo sleep"); esp_deep_sleep_start(); //força o ESP32 entrar em modo SLEEP }
Loop, callback & configureDisplay
No Loop não temos nada a
fazer. Seguimos, então, para o callback das interrupções caso tenhamos algo a
fazer quando ocorrer a interrupção. Quanto ao configureDisplay, inicializamos o
display e configuramos alguns parâmetros. Imprimimos na tela o número de vezes
que aconteceu o Boot.
//nada a se fazer no loop void loop() { } //callback das interrupções void callback(){ //caso queira fazer algo ao ocorrer a interrupção } void configureDisplay() { //inicializa o display e configura alguns parametros display.begin(); display.setPowerSave(0); //modo powerSave (0-Off ? 1-On) display.setFont(u8x8_font_torussansbold8_u); //fonte utilizada //imprime no display os numero de vezes que aconteceu o BOOT display.drawString(0,0, "BOOT NUM:"); display.drawString(0,2,String(bootCount).c_str()); display.drawString(0,4, "MOTIVO:"); }
print_wakeup_reason (conhecer a causa do despertar)
Temos aqui a função para
imprimir a causa do ESP32 despertar. Verificamos o pino e imprimimos no display.
//função para imprimir a causa do ESP32 despertar void print_wakeup_reason( ){ esp_sleep_wakeup_cause_t wakeup_reason; String reason = ""; wakeup_reason = esp_sleep_get_wakeup_cause(); //recupera a causa do despertar switch(wakeup_reason) { case 1 :reason = "EXT0 RTC_IO BTN"; break; case 2 :reason = "EXT1 RTC_CNTL"; break; case 3 :reason = "TIMER"; break; case 4 :reason = "TOUCHPAD"; break; case 5 :reason = "ULP PROGRAM"; break; default :reason = "NO DS CAUSE"; break; } Serial.println(reason); display.clearLine(6); //apaga a linha 6 do display display.drawString(0,6, reason.c_str()); //imprime a causa do despertar no display //se despertou por TOUCHPAD, então vamos verificar em qual dos pinos ocorreu if(wakeup_reason == 4) { print_wakeup_touchpad(); //verifica o pino e imprime no display } }
print_wakeup_touchpad (conhecer o GPIO do toque)
Já, nesta etapa, temos a função
para imprimir o pino que foi tocado. Recuperamos o GPIO que despertou o ESP32 e
o imprimimos no display.
//função para imprimir o pino que foi tocado void print_wakeup_touchpad() { touch_pad_t touchPin; touchPin = esp_sleep_get_touchpad_wakeup_status(); //recupera o GPIO que despertou o ESP32 String GPIO = ""; switch(touchPin) { case 0 : GPIO = "4"; break; case 1 : GPIO = "0"; break; case 2 : GPIO = "2"; break; case 3 : GPIO = "15"; break; case 4 : GPIO = "13"; break; case 5 : GPIO = "12"; break; case 6 : GPIO = "14"; break; case 7 : GPIO = "27"; break; case 8 : GPIO = "33"; break; case 9 : GPIO = "32"; break; default : Serial.println("Wakeup not by touchpad"); break; } Serial.println("GPIO: "+GPIO); display.clearLine(7);//apaga a linha 7 do display display.drawString(0,7, "GPIO: "); display.drawString(6,7, GPIO.c_str()); //imprime o GPIO }
6 Comentários
Boa tarde. Estava tudo indo muito bem com o ESP32, porém, ao conectar o WiFi, ele passou a exibir a mensagem "Brownout detector was triggered". Nem sei mais o que fazer. Já troquei o cabo USB, a fonte, coloquei capacitor na alimentação... Nada funciona.
ResponderExcluirOlá,
ExcluirQueda de tensão!
Até hj não sei se o motivo disso é software ou hardware. Digo isso pq alterei algumas funções no código e esse erro sumiu. Após um tempo voltou a aparecer. Substituindo a alimentação USB por uma fonte de 5V, pareceu ter resolvido o problema, mas dps tornou a aparecer. Enfim, não sei. Por enquanto eu utilizo apenas a fonte de 5V e programo via OTA.
ExcluirOlá Fernando, parabéns pela aula! Gostei bastante, era exatamente isso que vinha tentando fazer, minha dúvida é se no NodeMCU 12-e também vai funcionar estas funções de deep sleep. Uma outra dúvida é na pinagem e no software, você colocou o botão na GPIO04 e no código configurou o wakeup do ext0 no pino 39, o que significa este 39? você teria uma tabela de conversão a GPIO04 corresponde ao pino 39? Não seria ao RTCIO10 como mostra no pinout do ESP32? Desde já agradeço muito pela sua atenção e seu trabalho.
ResponderExcluirOlá Fernando Parabéns pelo seu trabalho, gostaria de tirar uma duvida é possivel fazer o LORA ativar o STM32 pelo pino 26 IRQ ou outro pino, é algo muito util e não consegui encontrar em lugar nenhum, se puder me dar pelo menos uma dica já agradeço
ResponderExcluirBoa tarde, Fernando.
ResponderExcluirConsigo alocar variaveis também no Nodemcu?