ESP32 WROOM 32U、SIMCOM A7670 和 LoRa 内核的问题

问题描述 投票:0回答:1

描述: 我当前的项目使用 ESP32 WROOM 32U 的两个内核并行运行两个任务:一个用于 LoRa 通信,我在其中接收文本字符串,另一个用于通过 SIMCOM 调制解调器连接到 MQTT 服务器,该调制解调器使用 AT 命令连接到 4G。我面临两个主要问题:

- 看门狗定时器重启问题: 我遇到过由于看门狗定时器而导致 ESP32 重启的情况,尤其是在与服务器、互联网断开连接或首次启动 ESP32 时。

问题详情:

  • 使用的硬件:ESP32 WROOM 32U和SIMCOM A7670。
  • 使用的库:我使用TinyGsmClient.h和PubSubClient.h。
  • IDE:Arduino。

问题详细描述: 主要问题在于使用双核时出现故障:看门狗重启。

采取的步骤: 我在几天内广泛审查了我的代码,以确保它正确适应硬件和网络配置。此外,我还验证了 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存储器中的存储有关

发帖目的:

我正在寻求社区的帮助,以找到解决此问题的方法。

我感谢任何解决这些问题的帮助或建议!

arduino esp32 arduino-esp32
1个回答
0
投票

onReceive(数据包大小);

  1. onReceive()
    函数是一个回调设置函数,仅调用一次(即在设置期间),而不是像在
    loraProtocolcode
    任务中那样在任务中无限调用。
  2. onReceive()
    API 需要一个指向回调函数的指针作为参数
    onReceive(callback_func)
    。请参阅示例
  3. 如果您想在任务循环中进行“轮询”,同样可以使用 example
© www.soinside.com 2019 - 2024. All rights reserved.