Travou! E agora?
Um assunto que considero
bastante importante é o Watchdog, palavra que, traduzida para o português,
significa “cão de guarda”. Existe um problema que atinge muitos circuitos
microcontrolados que é o fato deles travarem, isso por inúmeros motivos. O
Watchdog, portanto, é um dispositivo independente do microcontrolador que, em
caso de “congelamento”, irá reiniciar o sistema. Neste vídeo vamos, então, implementar
um Watchdog no ESP32 utilizando interrupção por tempo e criar um exemplo para
simular um travamento e acionar o dispositivo.
Introdução
O que fazer se seu programa
travar no meio de uma execução e ficar “congelado”?
Como reiniciar o ESP32 sem precisar ir lá apertar o botão físico?
Como reiniciar o ESP32 sem precisar ir lá apertar o botão físico?
Para isso utilizamos o Watchdog,
um “cão de guarda” que fica vigiando para verificar se seu programa travou e,
caso isso ocorra, ele trata de reiniciá-lo automaticamente.
Mas, como funciona o Watchdog?
Imagine que você tem um
cachorro que precisa comer de tempos em tempos para não começar a latir. Então,
você passa a alimentá-lo com certa frequência para mantê-lo em estado normal.
É assim que o Watchdog
funciona, ele fica aguardando ser “alimentado” (um sinal de que está tudo OK). Caso
passe um tempo e nenhum sinal tenha sido recebido, ele reinicia o MCU.
Implementando um Watchdog
Implementaremos o Watchdog no
ESP32 utilizando uma interrupção por tempo. Para isso vamos configurar um
temporizador para disparar um sinal e acionar uma função callback (onde teremos
o comando para reiniciar o ESP32), no caso de seu contador extrapolar o limite
de tempo definido.
Não dá para você usar um
circuito profissional microcontrolado sem utilizar o Watchdog porque ele é que
impede que o sistema fiquei lá parado em caso de um travamento. Então, esse
procedimento é bastante importante em inúmeras situações.
Interrupção por tempo
Utilizaremos os seguintes
comandos para configurar e manipular nosso temporizador.
hw_timer_t *timer = NULL; //faz o controle do temporizador (interrupção por tempo)
//timerID 0, div 80 (clock do esp), contador progressivo timer = timerBegin(0, 80, true);
//instancia de timer, função callback, interrupção de borda timerAttachInterrupt(timer, &resetModule, true);
// instancia de timer, tempo (us),3.000.000 us = 3 segundos , repetição timerAlarmWrite(timer, 3000000, true);
timerAlarmEnable(timer); //habilita a interrupção
timerWrite(timer, 0); //reseta o temporizador (alimenta o watchdog) zera o contador
WiFi NodeMCU-32S ESP-WROOM-32
Montagem
Programa
Nosso programa funcionará da
seguinte forma: vamos configurar uma interrupção por tempo para 3 segundos. Na
função Loop, a cada iteração, vamos resetar nosso temporizador. Teremos um
botão para simular um travamento do programa. Enquanto ele estiver pressionado,
o temporizador não será resetado, fazendo, assim, com que, ao extrapolar o
limite de tempo pré-definido, a interrupção seja acionada e a função com o
comando para reiniciar o ESP seja executada.
Variáveis
Aqui determinamos um pino do
botão para simular um travamento. Um outro pino acenderá o Led vermelho. O mesmo ocorrerá com o Led verde toda
vez que o ESP32 reiniciar. O controle é feito por um temporizador.
const int pinButton = 2; //pino do botão para simular um travamento const int redLed = 23; //pino do led const int greenLed = 4; //esse led acenderá toda vez que o ESP32 reiniciar hw_timer_t *timer = NULL; //faz o controle do temporizador (interrupção por tempo)
Setup
Inicializamos os pinos e
configuramos os timers. Na sequência, habilitamos a interrupção e colocamos o
Led verde para piscar indicando que o programa reiniciou.
void setup() { Serial.begin(115200); Serial.println("running setup"); pinMode(pinButton, INPUT_PULLUP); pinMode(redLed , OUTPUT); pinMode(greenLed , OUTPUT); delay(500); //hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp) /* num: é a ordem do temporizador. Podemos ter quatro temporizadores, então a ordem pode ser [0,1,2,3]. divider: É um prescaler (reduz a frequencia por fator). Para fazer um agendador de um segundo, usaremos o divider como 80 (clock principal do ESP32 é 80MHz). Cada instante será T = 1/(80) = 1us countUp: True o contador será progressivo */ timer = timerBegin(0, 80, true); //timerID 0, div 80 //timer, callback, interrupção de borda timerAttachInterrupt(timer, &resetModule, true); //timer, tempo (us), repetição timerAlarmWrite(timer, 3000000, true); timerAlarmEnable(timer); //habilita a interrupção digitalWrite(greenLed, HIGH); delay(1000); digitalWrite(greenLed, LOW); }
Loop
void loop() { timerWrite(timer, 0); //reseta o temporizador (alimenta o watchdog) long tme = millis(); //tempo inicial do loop //fica preso no loop enquanto o botão estiver pressionado while(digitalRead(pinButton)) { Serial.println("botão pressionado: "+String(millis() - tme)); digitalWrite(redLed, HIGH); //acende o led vermelho delay(500); // timerWrite(timer, 0); //se fizer esse reset no temporizador, o watchdog não será acionado } delay(1000); Serial.print("tempo passado dentro do loop (ms) = "); tme = millis() - tme; //calcula o tempo (atual - inicial) Serial.println(tme); //desliga o led vermelho digitalWrite(redLed, LOW); }
resetModule
Temos aqui a função que o
temporizador irá chamar para reiniciar o ESP32. Imprimimos o log e executamos o
comando para reiniciar o chip.
//função que o temporizador irá chamar, para reiniciar o ESP32 void IRAM_ATTR resetModule(){ ets_printf("(watchdog) reiniciar\n"); //imprime no log esp_restart_noos(); //reinicia o chip }
Simulando
Segurando o botão por 3
segundos ou mais, o temporizador não foi resetado.
Logo, Watchdog entra em ação,
reiniciando o ESP.
Segurando o botão por menos de
3 segundos.
Logo, não chegou ao limite do
temporizador, e o Watchdog não será acionado.
Adicionando o Watchdog no ESP32 LoRa
É importante que vocês
assistam este vídeo e entendam o código fonte que utilizei nele. Isso porque, a
partir daí, você vai incluir a parte do Watchdog neste mesmo código.
Para implementarmos o Watchdog
nesse projeto faremos poucas alterações como veremos a seguir.
No arquivo
LoRaSendReceiveBME280.ino, adicione o seguinte trecho de código em qualquer
lugar do arquivo.
//faz o controle do temporizador (interrupção por tempo) hw_timer_t *timer = NULL; //função que o temporizador irá chamar, para reiniciar o ESP32 void IRAM_ATTR resetModule(){ ets_printf("(watchdog) reiniciar\n"); //imprime no log esp_restart_noos(); //reinicia o chip } //função que o configura o temporizador void configureWatchdog() { timer = timerBegin(0, 80, true); //timerID 0, div 80 //timer, callback, interrupção de borda timerAttachInterrupt(timer, &resetModule, true); //timer, tempo (us), repetição timerAlarmWrite(timer, 5000000, true); timerAlarmEnable(timer); //habilita a interrupção //enable interrupt }
Nos outros arquivos Master.ino e Slave.ino temos duas linhas para adicionar, uma no Setup e outra no Loop.
void setup(){ Serial.begin(115200); configureWatchdog(); ..... } void loop(){ //reseta o temporizador (alimenta o watchdog) timerWrite(timer, 0); ..... }
Obrigado mestre!
ResponderExcluirabraços de Portugal..
ResponderExcluirO seu canal é mesmo giro..
Parabens Fernando pelo seu canal..já aprendi bastante com ele..
esou fazendo osket no arduino 1.8.5 e esdta dfando erro hw_timer_t *timer = NULL; 'hw_timer_t' does not name a type
ResponderExcluirEstou com o mesmo problema
ExcluirBoa tarde. Como eu posso colocar num mesmo programa watchdog e webupdate do esp32? Separados funcionam numa boa, porém, juntos, ao acessar o browser para carregar o arquivo de atualização, esse timer deve estourar e impedir que eu faça isso. Aí eu não consigo fazer a atualização de jeito nenhum!
ResponderExcluirBoa Tarde Fernando, em primeiro lugar quero lhe dizer que sou profundo admirador de seu trabalho,
ResponderExcluirsuas aulas são TOP, e seu modo de ensino é muito bacana, faz com que a gente fique pregado na tela sem querer piscar um só instante, enfim
Parabéns.
Sou um curioso, tenho 56 anos, sou da area de transportes, não tenho conhecimento de eletronica e nem da area de programação, o pouco que aprendi foi assistindo suas aulas, e também as aulas do Prof. Flávio do canal Brincando com Idéias, inclusive consegui desenvolver alguns projetos interessantes, baseados em ESP8266 com (WebServer), (DHT11),(LM35),(ACS712),(HC-SR04), dentre outros pequenos projetos também, enfim.
Tenho um projeto com NodeMCU que está me dando uma dor de cabeça danada, (Projeto acender/apagar Lamp/Garagem com interruptor em paralelo com o relê e Sensor ACS712 para saber estado da lâmpada, e Abrir/Fechar Portão eletronico da Garagem com Sensor Fim de Curso, para saber se FECHADO ou ABERTO), tudo dentro do mesmo código WiFiServer com direcionamento de portas e DDNS para acessar remotamente fora da rede interna.
Na verdade o projeto está funcionando até que bem, tando no Browser do Windows quanto no Browser do Celular Android, na página HTML que está dentro do código existe um Refresh onde atualiza a página em tempos em tempos, para saber o estado tanto da Lampada como a do Portão, ficou bem interessante, é lógico que isto não saiu da minha cabeça, fui juntando um pouco das suas aulas e também do Flávio,
O Problema é o seguinte, estou fazendo um Aplicativo para Android no MIT APP INVENTOR, em que uso este código descrito, ficou legal também, porém ao usar o aplicativo, o ESP trava sempre nas mudanças de rede, tanto do WiFi para o 4G, quanto do 4G para WiFi, talvez seja motivado pelo GATILHO ou TRIGGER do Clock Timer do APP Inventor que tive que implantar para poder fazer Refresh no APP, enfim... trava que não te, jeito.
Tentei implantar o Watch Dog no código para tentar resetar o ESP, mas não está funcionando, acho que só funciona do ESP32, vc pode me ajudar nisto, se houver outra maneira de resetar o NodeMcu,
desde já agradeço.
DIFICIL DE TER UMA RESPOSTA...
Excluirnao consigo baixar
ResponderExcluirOlá! Como implementa o Watch Dog no ESP8266 NodeMcu ?
ResponderExcluiresp_restart_noos();
ResponderExcluirDA ERRO E PONTO FINAL NA CONVEVRSA !!!
Bom dia
ResponderExcluirFunciona no Nodemcu 12E?
Grato.
update: tive que trocar o esp_restart_noos() por esp_restart(). Somente assim ele compilou.
ResponderExcluirisso mesmo, aqui foi assim tb vlw
ExcluirNo esp8266 funciona?
ResponderExcluir