banner

Ir para o Forum

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?
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); 
    .....
}



Faça o download dos arquivos:

INO

PDF


11 comentários:

  1. abraços de Portugal..
    O seu canal é mesmo giro..
    Parabens Fernando pelo seu canal..já aprendi bastante com ele..

    ResponderExcluir
  2. 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

    ResponderExcluir
  3. Boa 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!

    ResponderExcluir
  4. Boa Tarde Fernando, em primeiro lugar quero lhe dizer que sou profundo admirador de seu trabalho,
    suas 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.

    ResponderExcluir
  5. Olá! Como implementa o Watch Dog no ESP8266 NodeMcu ?

    ResponderExcluir
  6. esp_restart_noos();

    DA ERRO E PONTO FINAL NA CONVEVRSA !!!

    ResponderExcluir
  7. Bom dia
    Funciona no Nodemcu 12E?
    Grato.

    ResponderExcluir

Tecnologia do Blogger.