首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >任务看门狗被触发-任务没有及时重置看门狗。

任务看门狗被触发-任务没有及时重置看门狗。
EN

Stack Overflow用户
提问于 2021-02-19 13:16:33
回答 2查看 14.9K关注 0票数 6

我正在尝试编写一个小小的异步WebServer。让我简单地描述一下情况:

我的ESP32也是一个路由器。因此,如果我将手机连接到WiFi中,ESP32正在传播并调用ip地址和带有浏览器的特殊路径,则会发送WebSite。这里显示了一个按钮。在此之前,它运行得很好。现在,如果我单击该按钮,一个HTTPS请求(方法: GET)将被发送到一台特殊的机器。这台机器回答并返回一个JSON。这可能会持续几秒钟。从JSON字符串中提取值后,将显示该值。

为此,我使用以下库:

我(通过另一个草图)知道,最后的三个没有任何问题。

不幸的是,当我单击该按钮时,以下输出将显示在我的串行监视器上:

开始连接到服务器..。 HTTPS开始..。路径:引脚 哈茨..。 E (137906) task_wdt:任务看门狗被触发。下列任务未能及时重置看门狗: E (137906) task_wdt:- async_tcp (CPU 0/1) E (137906) task_wdt:当前正在运行的任务: E (137906) task_wdt: CPU 0: IDLE0 E (137906) task_wdt: CPU 1: loopTask E (137906) task_wdt:中止。 在PC 0x400e08af上,在核心0回溯:0x4008cc18:0x3ffb 170 0x4008ce49:0x3ffbe190 0x400e08af:0x3ffbe1b0 0x40084f21:0x3ffbe1d0 x4016581b:0x3ffb120 0x400e1c66:0x3ffb140 0x4008ab21:0x3ffb160 0x4008932 d:0x3ffbc180. 2016年6月8日00:22:57 rst:0xc (SW_CPU_RESET)引导:0x17 (SPI_FAST_FLASH_BOOT) configsip: 0,SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 模式:DIO,时钟div:1 负载:0x3fff 0018,len:4 负载:0x3fff001c,len:1044 负载:0x40078000,len:8896 负载:0x40080400,len:5816 条目0x400806ac 串行初始完成

有谁知道发生了什么事以及如何解决这个问题吗?以便正确发送GET请求/接收答案?

我正在使用Heltec WiFi工具包32

对每一个答案都会很高兴,谢谢。

诚挚的问候

请允许我最后添加我的代码:

代码语言:javascript
复制
#include <heltec.h>
#include "WiFi.h"
#include "ESPAsyncWebServer.h"

#include <WiFiClientSecure.h>
#include <HTTPClient.h>
 
const char* ssid = "MyWiFiSSID";
const char* password =  "MyWiFiPW";
 
AsyncWebServer server(80);

void setup() {

  Heltec.begin(true, false, true, true, 470E6);

  WiFi.softAP(ssid, password);
  
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AccessPoint IP address: ");
  Serial.println(IP);
  
  server.on("/hello", HTTP_GET, [](AsyncWebServerRequest *request){
    
    request->send(200, "text/html", "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" charset=\"UTF-8\"><link rel=\"icon\" href=\"data:,\"><style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}.button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}</style></head><body><h1>Welcome to the Landing Page of the Web Server</h1><p><a href=\"/get_unlock_pin\"><button class=\"button\">Click Me</button></a></p></body></html>");
  });

  server.on("/get_unlock_pin", HTTP_GET, [](AsyncWebServerRequest *request){

    String firstpartofrawhtmlcode = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" charset=\"UTF-8\"><link rel=\"icon\" href=\"data:,\"><style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}.button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}</style></head><body><h2>Received Pin: </h2><h2 style=\"color: #FF0000\">";
    String receivedPin = getPin("192.168.4.101");
    String secondpartofrawhtmlcode = "</h2></body></html>";
    String fullrawhtmlcode;
    firstpartofrawhtmlcode = firstpartofrawhtmlcode.concat(receivedPin);
    fullrawhtmlcode = firstpartofrawhtmlcode.concat(secondpartofrawhtmlcode);
    request->send(200, "text/html", fullrawhtmlcode);
  });
 
  server.begin();
}

void loop() {

}

String getPin(String ip){
    Serial.println("\nStarting connection to server...");  
    WiFiClientSecure *wificlient = new WiFiClientSecure;

    HTTPClient https;
    https.setAuthorization("MyUserName", "MyPassword");

    String path = "https://" + ip + "/api/unlock/generate_pin";
      
    Serial.print("[HTTPS] begin... Path: " + path + "\n");
    if (https.begin(*wificlient, path)) { 
        Serial.print("[HTTPS] GET...\n");
        int httpCode = https.GET();
        if (httpCode > 0) {
          Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
  
          if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
            String payload = https.getString();
            Serial.println(payload);
            //Extract Pin from JSON
            String tmp = payload.substring(payload.indexOf(':'), payload.indexOf('}'));
            String tmp2 = tmp.substring(tmp.indexOf('"')+1,tmp.lastIndexOf('"')); 
            if(tmp2.substring(0,1) == "-"){
               return "-";
            }else{
               return tmp2;
            }              
          }
        } else {
               Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
        }  
        https.end();
    } else {
        Serial.printf("[HTTPS] Unable to connect\n");
    }
}
EN

回答 2

Stack Overflow用户

发布于 2021-09-05 17:19:55

按照这个问题的表述方式,我想你不知道什么是看门狗,也不知道它为什么会触发。因此:

ESP的Arduino是建立在ESP-国防军的基础上的,而这反过来又是围绕着FreeRTOS建立的.FreeRTOS为每个核心创建一个空闲任务。它还为这些任务设置了看门狗定时器。这意味着,如果这些任务缺乏执行时间,那么在超时期间之后,会触发看门狗并重置芯片。空闲的任务在后台做一些重要的FreeRTOS“家庭”工作,所以你必须给他们时间。它们也具有尽可能低的优先次序。因此,如果任何任务以更高的优先级运行(例如回调),这些任务将始终首先运行,而空闲任务将不得不等待。因此,所有高优先级的任务都必须足够短,以避免触发看门狗。如果这不可行,则必须以足够的间隔插入暂停,例如调用vTaskDelay(.)或者通过执行一些IO函数来阻止足够长的时间。在这两种情况下,当前任务将进入休眠状态,FreeRTOS将启动另一个任务,如果没有其他更高优先级的任务等待,它将最终允许空闲任务执行。所有这一切意味着,通常情况下,您编写的任何代码都不应该占用CPU时间的100%,在任何一段时间都超过看门狗超时时间。而且,你不能在Arduino把它关掉。它只能在ESP-以色列国防军中配置,这意味着你必须在这个框架内编码,或者自己重新编译Arduino。而且,无论如何关掉它也是个坏主意。

在调用vTaskDelay(.)时,必须使用至少1的值。由于整数运算和作为参数传递的各种表达式,它最终可能达到0,即一点也不延迟。

如果确实需要不间断地运行任务,则必须自己创建任务,并将其作为tskIDLE_PRIORITY的优先级,例如:

xTaskCreate(someFunction, "HumanReadableNameofTask", 4096, NULL, tskIDLE_PRIORITY, NULL);

其中您的函数具有以下签名:

void someFunction(void* arg) {...}

你也可以在Arduino做这个。因此,要么保持在回调中运行的代码最小化,要么将繁重的任务转移到单独的任务,并让回调简单地将任何相关信息转发到该任务(例如使用易失性变量和信号量,即并行处理中通常的同步方法)。这超出了这个答案的范围)。

注意:我不确定是否呼叫延迟(.)在Arduino中,它具有与vTaskDelay相同的效果,但它可能有(一些微妙之处)。另外,对于一个任务来说,有一种“屈服”于另一个较低任务的官方方法,但我不确定细节。

重要事项:使用延迟(如vTaskDelay(.))在回调中,特别是计时器回调是个坏主意,因为它们阻止其他回调(在同一任务内)执行。因此,最好的选择是将信息传递给以空闲优先级运行的单独任务(即优先级0)。以0优先级运行的任务不触发监视狗的原因,是因为空闲任务也具有该优先级,而FreeRTOS循环使所有这些任务具有相同的优先级(给它们交错的时间以“并行”方式执行)。但是,当您有两个具有不同优先级的任务时,较高的任务总是执行到完成或暂停/休眠为止,只有这样,低优先级才会运行,要么直到它本身完成,要么直到高优先级任务再次醒来并要求执行时间。

更新:

保持Arduino循环()为空,肯定会触发wdt,因为它并不是真正的“空”,因为循环()函数在内部封装在一个无限循环中,因此CPU消耗实际上将达到100%,而没有做任何有用的事情。这就是触发看门狗的原因。GET进程似乎是异步发生的,因此它不会阻止循环()的执行。

票数 15
EN

Stack Overflow用户

发布于 2021-02-19 14:21:53

ESPAsyncWebServer回调防止在运行时重置看门狗计时器。这意味着它们不是用来进行任何实际处理的。注册请求并将处理推迟到主循环(或其他线程)。有关详细信息,请查看这个问题

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66278271

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档