描述: 我当前的项目使用 ESP32 WROOM 32U 的两个内核并行运行两个任务:一个用于 LoRa 通信,我在其中接收文本字符串,另一个用于通过 SIMCOM 调制解调器连接到 MQTT 服务器,该调制解调器使用 AT 命令连接到 4G。我面临两个主要问题:
- 看门狗定时器重启问题: 我遇到过由于看门狗定时器而导致 ESP32 重启的情况,尤其是在与服务器、互联网断开连接或首次启动 ESP32 时。
问题详情:
问题详细描述: 主要问题在于使用双核时出现故障:看门狗重启。
采取的步骤: 我在几天内广泛审查了我的代码,以确保它正确适应硬件和网络配置。此外,我还验证了 MQTT 服务器上的物理硬件连接和网络设置。我尝试了论坛上建议的几种解决方案,例如使用“vTaskDelay”之类的计时器,但都没有有效解决问题。
错误日志:
09:52:24.052 -> E (38279) task_wdt: CPU 1: loopTask
09:52:24.052 -> E (38279) task_wdt: Aborting.
09:52:24.052 -> E (38279) task_wdt: Print CPU 0 (current core) backtrace
09:52:24.052 ->
09:52:24.052 ->
09:52:24.052 ->
09:52:24.052 ->
09:52:24.052 -> Backtrace: 0x40082d29:0x3ffb47f0 0x40089a22:0x3ffb4810 0x400d5ce9:0x3ffb4830 0x400d1c92:0x3ffb4850 0x400d1e82:0x3ffb4880 0x400d1ed1:0x3ffb48e0 0x400d27e8:0x3ffb4910 0x400d2829:0x3ffb4930 0x400d2d21:0x3ffb4950 0x400d2d75:0x3ffb4970 0x400d2e63:0x3ffb49b0
09:52:24.087 ->
09:52:24.087 ->
09:52:24.087 ->
09:52:24.087 ->
09:52:24.087 -> ELF file SHA256: 717e4228e872b1c6
09:52:24.087 ->
09:52:24.087 -> Rebooting...
09:52:24.087 -> ets Jul 29 2019 12:21:46
09:52:24.087 ->
09:52:24.087 -> rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
代码
//Sistema
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <string.h>
//EEPROM
#include <EEPROM.h>
//Lora
#include <SPI.h>
#include <LoRa.h>
//Simcom ~ mqtt
#define TINY_GSM_MODEM_SIM7600 //a7670xx
#define TINY_GSM_RX_BUFFER 1024
#define SerialAT Serial1
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false
#include <TinyGsmClient.h>
#include <PubSubClient.h>
//Pin Lora
#define ss 4
#define rst 25
#define dio0 27
//config EEPROM -- Registros Date
#define ARRAY_SIZE 80 // Tamaño del array para las fechas
#define EEPROM_START_ADDRESS 0 // Dirección de inicio en la EEPROM
struct DataStruct {
char data[21];
};
DataStruct dateTimeRegistrerMaster[ARRAY_SIZE];
#define DATOS_SIZE sizeof(dateTimeRegistrerMaster[0].data)
#define EEPROM_SIZE (ARRAY_SIZE * sizeof(DataStruct))
int counterRecived = 0;
// Configuración EEPROM -- Registros Order
#define ARRAY_SIZE_NEW 10 // Tamaño del array para los nuevos registros
#define EEPROM_START_ADDRESS_NEW (EEPROM_START_ADDRESS + EEPROM_SIZE) // Nueva dirección de inicio en la EEPROM para los nuevos registros
struct OrderDataStruct {
char data[8]; // Nueva estructura para los nuevos registros
};
OrderDataStruct orderMqttStorage[ARRAY_SIZE_NEW];
#define NEW_DATOS_SIZE sizeof(orderMqttStorage[0].data)
#define NEW_EEPROM_SIZE (ARRAY_SIZE_NEW * sizeof(OrderDataStruct))
int counterRecivedMqtt = 0;
//Sistena
const int ledPin = 2;
//Lora identificación dispositivo
byte localAddress = 0xFF; // Dirección de este dispositivo
const char* customDeviceID = "aa01";
char completeLocalAddress[7];
// byte destination = 0xBB; // Dirección a la que enviar mensajes
//Config Simcom - mqtt
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
PubSubClient mqttClient(client);
const char* mqtt_server = "Myserver mqtt";
const int mqtt_port = 7010;//for example 1884
const char* mqtt_sub_topic = "TopicNa";
const char* mqtt_pub_topic = "Topic2";
//Config APN
const char apn[] = "Apncfg";
const char gprsUser[] = "user";
const char gprsPass[] = "pass";
//Config perdurancia internet
bool networkConnected = false;
bool gprsConnected = false;
//Creamos 2 tareas
TaskHandle_t simComMqtt;
TaskHandle_t loraProtocol;
void setup() {
Serial.begin(115200);
SerialAT.begin(115200, SERIAL_8N1, 16, 17); // RX y TX -- Comunicación SimCom
delay(3000); // Espera para que el módem se inicialice correctamente
//Desactivar pines bornOut
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
// SetUp pines
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
//Memoria EEPROM
EEPROM.begin(EEPROM_SIZE + NEW_EEPROM_SIZE);
initializeEEPROMData<DataStruct>(ARRAY_SIZE, EEPROM_START_ADDRESS); //Registros
initializeEEPROMData<OrderDataStruct>(ARRAY_SIZE_NEW, EEPROM_START_ADDRESS_NEW); //Ordenes
//SetUp Lora
while (!Serial);
Serial.println("LoRa Duplex");
LoRa.setPins(ss, rst, dio0);
while (!LoRa.begin(433E6)) {
Serial.println(".");
delay(500);
}
// Ajusta el nivel de potencia de salida (en dBm)
LoRa.setTxPower(0); // Prueba con diferentes valores, 20 dBm es el máximo para SX1278
// Establece el factor de esparcimiento en 10
LoRa.setSpreadingFactor(10);
// Ancho de banda de 125 kHz
LoRa.setSignalBandwidth(125E3);
// Tasa de codificación de 4/5
LoRa.setCodingRate4(5);
// Longitud del preámbulo de 8 símbolos
LoRa.setPreambleLength(8);
LoRa.setSyncWord(0xF3);
Serial.println("LoRa Initializing OK!");
// Setup SimCom
String name = modem.getModemName();
Serial.print("Modem Name: ");
Serial.println(name);
String ccid = modem.getSimCCID();
Serial.println("CCID: " + ccid);
String imei = modem.getIMEI();
Serial.println("IMEI: " + imei);
String cop = modem.getOperator();
Serial.println("Operator: " + cop);
IPAddress local = modem.localIP();
Serial.println("Local IP: " + String(local));
int csq = modem.getSignalQuality();
Serial.println("Signal quality: " + String(csq));
Serial.print("Esperando a la red...");
// reconnectNetwork(); // Asegura la conexión de red en el setup
Serial.print(F("Conectando a "));
Serial.print(apn);
//SetUp Mqtt
mqttClient.setServer(mqtt_server, mqtt_port);
mqttClient.setCallback(callback);
//Tarea para Wifi & Mqtt
xTaskCreatePinnedToCore(
simComMqttcode, /* Task function. */
"simComMqtt", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&simComMqtt, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//Tarea para solo lora
xTaskCreatePinnedToCore(
loraProtocolcode, /* Task function. */
"loraProtocol", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&loraProtocol, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
}
//~ Funcion SimCom Conexion 4G
void reconnectNetwork() {
if (!modem.isNetworkConnected()) {
Serial.println("Red 4G desconectada");
while (!modem.isNetworkConnected()) {
if (!modem.waitForNetwork(10000L, true)) { // 10 segundos de espera
Serial.println("Fallo en conexion a red 4G");
delay(5000); // Espera 10 segundos antes de intentar de nuevo
}
}
Serial.println("Red reconectada");
networkConnected = true;
}
if (!modem.isGprsConnected()) {
Serial.println("GPRS desconectado!");
while (!modem.isGprsConnected()) {
Serial.println("Conectando a GPRS");
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) { // Añadido: Llama a gprsConnect() con los argumentos apropiados
Serial.println("Fallo en conexion");
delay(5000); // Espera 10 segundos antes de intentar de nuevo
}
}
Serial.println("GPRS reconectado");
gprsConnected = true;
}
}
// ~ Funciones Mqtt
void reconnectMQTT() {
reconnectNetwork();
while (!mqttClient.connected()) {
Serial.println("Conectando al broker MQTT...");
mqttClient.setServer(mqtt_server, mqtt_port);
mqttClient.setCallback(callback); // Establecer la función de callback
if (mqttClient.connect("ESP32Client")) {
Serial.println("Conectado al broker MQTT");
mqttClient.subscribe(mqtt_sub_topic);
} else {
Serial.print("Error de conexión al broker MQTT, rc=");
Serial.print(mqttClient.state());
Serial.println(" Intentando de nuevo en 2 segundos");
delay(2000); // Espera 15 segundos antes de intentar de nuevo
}
}
}
//CallBack de topico mqtt
void callback(char* topic, byte* payload, unsigned int length) {
// Convertir el payload a una cadena de caracteres
char payloadStr[length + 1];
for (int i = 0; i < length; i++) {
payloadStr[i] = (char)payload[i];
}
payloadStr[length] = '\0'; // Añadir el carácter nulo al final de la cadena
String payloadString = String(payloadStr); //Casteo a String
Serial.println("Esta es la trama que recibo del mqtt: ");
Serial.println(payloadString);
//Extraer los primeros cuatro caracteres como una subcad
String mqttMasterAdress = payloadString.substring(0, 6); //Direccion maestro
String mqttSlaveOrder = payloadString.substring(6,10); //esclavo y orden
//Obtener la dirección completa del dispositivo
sprintf(completeLocalAddress, "%02X%s", localAddress, customDeviceID);
String completeLocalAddressString = String(completeLocalAddress);
if (mqttMasterAdress == completeLocalAddressString){
Serial.println("Coincide");
Serial.println("Almacenando orden MQTT en EEPROM...");
strcpy(orderMqttStorage[counterRecivedMqtt].data, mqttSlaveOrder.c_str());
storeDataInEEPROM<OrderDataStruct>(counterRecivedMqtt, orderMqttStorage[counterRecivedMqtt], EEPROM_START_ADDRESS_NEW);
counterRecivedMqtt++;
if (counterRecivedMqtt >= ARRAY_SIZE_NEW) {
counterRecivedMqtt=0;
}
}else{
Serial.println("La orden enviada no coincide con la dirección del maestro");
readDataFromEEPROM<OrderDataStruct>(ARRAY_SIZE_NEW, EEPROM_START_ADDRESS_NEW);
}
}
//Enviar EEPROM mqtt
void sendDataEepromMqtt() {
for (int i = 0; i < ARRAY_SIZE; i++) {
int address = EEPROM_START_ADDRESS + (i * sizeof(DataStruct));
DataStruct data;
EEPROM.get(address, data);
if(strlen(data.data) == 0){
continue;
}else {
//Enviar datos al mqtt
Serial.println(data.data);
mqttClient.publish("AlertaETB",data.data);
delay(200);
// Borrar el dato de la EEPROM
DataStruct emptyData;
memset(emptyData.data, 0, sizeof(emptyData.data)); // Inicializar los datos con 0
EEPROM.put(address, emptyData); // Escribir datos vacíos en la EEPROM
EEPROM.commit(); // Guardar los cambios en la EEPROM
}
}
}
//Funciones Lora
void onReceive(int packetSize) {
if (packetSize == 0) return; // Salir si no hay datos
byte recipient = LoRa.read(); // Leer la dirección del destinatario
byte sender = LoRa.read(); // Leer la dirección del remitente
// Leer la fecha y hora como una cadena de caracteres
char dateTime[18]; // Tamaño suficiente para almacenar la fecha y hora en formato YYYYMMDDHHMMSS
for (int i = 0; i < 12; i++) {
dateTime[i] = LoRa.read();
}
dateTime[12] = '\0'; // Añadir un carácter nulo al final para indicar el final de la cadena
// Leer el valor adicional
uint8_t value = LoRa.read();
// Imprimir la información recibida
Serial.print("Received from: 0x");
Serial.println(sender, HEX);
Serial.print("Date and Time: ");
Serial.println(dateTime);
Serial.print("Additional Value: ");
Serial.println(value);
Serial.print("RSSI: ");
Serial.println(LoRa.packetRssi());
Serial.println();
//Envio mqtt & confirmación a esclavo Alerta
if (value == 1) {
digitalWrite(ledPin, HIGH); // Enciende el LED si el mensaje recibido es 1
//Guardar datos en la memoria ~~ Se envian cuando haya conexion mqtt
String datosApertura = String(localAddress, HEX) + String(customDeviceID) + String(sender, HEX) + String(dateTime);
//Enviar confirmación & orden SOTA a Slave especifico
sendOrderSlave(sender);
int dataToSend=1;
sendMessage(sender, dataToSend);//Envio de confrimacion
delay(200);
digitalWrite(ledPin, LOW);
Serial.println("Almacenar datos en EEPROM");
strcpy(dateTimeRegistrerMaster[counterRecived].data, datosApertura.c_str());
storeDataInEEPROM<DataStruct>(counterRecived, dateTimeRegistrerMaster[counterRecived], EEPROM_START_ADDRESS);
// Incrementar el contador
counterRecived++;
if (counterRecived >= ARRAY_SIZE) {
counterRecived=0;
}
}
}
void sendMessage(byte destination,int outgoing) {
LoRa.beginPacket();
LoRa.write(destination);
LoRa.write(localAddress);
LoRa.write(sizeof(outgoing)); // Enviar el tamaño del entero
LoRa.write((uint8_t*)&outgoing, sizeof(outgoing)); // Enviar el entero
delay(500); // Puedes ajustar el tiempo según tus necesidades
LoRa.endPacket();
Serial.println("Se envio confirmación");
}
//~ Tareas
//simComMqttcode: Intenta conectarse a wifi & mqtt - Envia los datos de almacenados
void simComMqttcode(void *pvParameters) {
while (true) {
// Manejar reconexión si se pierde la conexión MQTT
if (!mqttClient.connected()) {
// reconnectNetwork();
reconnectMQTT();
// readDataFromEEPROM<DataStruct>(ARRAY_SIZE, EEPROM_START_ADDRESS);
// readDataFromEEPROM<OrderDataStruct>(ARRAY_SIZE_NEW, EEPROM_START_ADDRESS_NEW);
} else {
// Envía datos al servidor si está conectado a MQTT
sendDataEepromMqtt();
}
mqttClient.loop();
delay(10); // Pequeña pausa para permitir que otras tareas se ejecuten
}
}
//loraProtocolcode: Escucha entradas Lora
void loraProtocolcode( void * pvParameters ){
while (true) {
int packetSize = LoRa.parsePacket();
if (packetSize) {
onReceive(packetSize);
}
delay(10); // Pequeña pausa para permitir que otros hilos se ejecuten
}
}
//DEBE ESTAR VACIO
void loop() {
}
代码说明:为了更好的可读性,我没有上传代码的某些部分,这些部分与从Lora协议获取的信息在EEPROM存储器中的存储有关
发帖目的:
我正在寻求社区的帮助,以找到解决此问题的方法。
我感谢任何解决这些问题的帮助或建议!