ESP32抽离PubSubClient连接AWS IoT Core工具函数后崩溃排查
问题
我需要实现一个基于PubSubClient和WiFiClientSecure连接AWS MQTT代理的函数,并将其定义在独立文件中以实现复用,但ESP32每次运行代码时都会崩溃。原教程中的函数在主文件定义时运行正常,但抽离到iot_utils.cpp后出现崩溃。
原教程工作代码(主文件中)
WiFiClientSecure net = WiFiClientSecure(); PubSubClient client(net); void connectAWS() { WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.println("Connecting to Wi-Fi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Configure WiFiClientSecure to use the AWS IoT device credentials net.setCACert(AWS_CERT_CA); net.setCertificate(AWS_CERT_CRT); net.setPrivateKey(AWS_CERT_PRIVATE); // Connect to the MQTT broker on the AWS endpoint we defined earlier client.setServer(AWS_IOT_ENDPOINT, 8883); // Create a message handler client.setCallback(messageHandler); Serial.println("Connecting to AWS IOT"); while (!client.connect(THINGNAME)) { Serial.print("."); delay(100); } if (!client.connected()) { Serial.println("AWS IoT Timeout!"); return; } // Subscribe to a topic client.subscribe(AWS_IOT_SUBSCRIBE_TOPIC); Serial.println("AWS IoT Connected!"); }
抽离后的代码
iot_utils.cpp中的函数:
void connectAWS(WiFiClientSecure& net, PubSubClient& client, const char* topic) { // 此处为原函数逻辑代码 }
主文件调用:
WiFiClientSecure net = WiFiClientSecure(); PubSubClient client(net); void setup() { connectAWS(net, client, "esp32/pub"); }
崩溃信息
ets Jun 8 2016 00:22:57 rst:0xc (SW_CPU_RESET),boot:0x13 (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 mode:DIO, clock div:2 load:0x3fff0030,len:1184 load:0x40078000,len:13132 load:0x40080400,len:3036 entry 0x400805e4 Connecting to Wi-Fi .Connecting to AWS IOT Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled. Core 1 register dump: PC : 0x4015b50c PS : 0x00060f30 A0 : 0x800d3bba A1 : 0x3ffb26f0 A2 : 0x3ffc2c74 A3 : 0x3f4050f9 A4 : 0x00000015 A5 : 0x0000ff00 A6 : 0x00ff0000 A7 : 0xff000000 A8 : 0x800d78a6 A9 : 0x3ffb2700 A10 : 0x000003e8 A11 : 0x3f4050f9 A12 : 0x00000002 A13 : 0x0000ff00 A14 : 0x00ff0000 A15 : 0xff000000 SAR : 0x00000017 EXCCAUSE: 0x0000001c EXCVADDR: 0x000003e8 LBEG : 0x40089729 LEND : 0x40089739 LCOUNT : 0xfffffffa Backtrace:0x4015b509:0x3ffb26f00x400d3bb7:0x3ffb2710 0x400d3de2:0x3ffb2750 0x400d3915:0x3ffb2780 0x400d3819:0x3ffb27a0 0x400d877e:0x3ffb2820
解决方案
崩溃核心原因是:抽离后的connectAWS函数依赖原主文件中的全局常量(如证书、端点地址)和回调函数,但独立文件iot_utils.cpp无法访问这些未声明的外部符号,导致非法内存访问(LoadProhibited错误通常对应访问无效内存地址)。
修正步骤
- 创建头文件
iot_utils.h,规范函数声明并引入必要依赖:
#ifndef IOT_UTILS_H #define IOT_UTILS_H #include <WiFiClientSecure.h> #include <PubSubClient.h> void connectAWS(WiFiClientSecure& net, PubSubClient& client, const char* thingName, const char* awsEndpoint, const char* caCert, const char* clientCert, const char* privateKey, const char* subscribeTopic, const char* wifiSsid, const char* wifiPassword, MQTT_CALLBACK_SIGNATURE); #endif // IOT_UTILS_H
- 修改
iot_utils.cpp,完全使用传入参数替代全局依赖:
#include "iot_utils.h" #include <WiFi.h> #include <HardwareSerial.h> void connectAWS(WiFiClientSecure& net, PubSubClient& client, const char* thingName, const char* awsEndpoint, const char* caCert, const char* clientCert, const char* privateKey, const char* subscribeTopic, const char* wifiSsid, const char* wifiPassword, MQTT_CALLBACK_SIGNATURE) { WiFi.mode(WIFI_STA); WiFi.begin(wifiSsid, wifiPassword); Serial.println("Connecting to Wi-Fi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // 使用传入的证书配置TLS net.setCACert(caCert); net.setCertificate(clientCert); net.setPrivateKey(privateKey); client.setServer(awsEndpoint, 8883); client.setCallback(callback); // 绑定传入的回调函数 Serial.println("\nConnecting to AWS IOT"); while (!client.connect(thingName)) { Serial.print("."); delay(100); } if (!client.connected()) { Serial.println("\nAWS IoT Timeout!"); return; } client.subscribe(subscribeTopic); Serial.println("\nAWS IoT Connected!"); }
- 主文件中调用时传递所有必要参数:
#include "iot_utils.h" // 定义你的设备常量和回调函数 const char* WIFI_SSID = "your_wifi_ssid"; const char* WIFI_PASSWORD = "your_wifi_password"; const char* THINGNAME = "your_thing_name"; const char* AWS_IOT_ENDPOINT = "your_aws_endpoint"; const char AWS_CERT_CA[] = "..."; // 你的CA证书内容 const char AWS_CERT_CRT[] = "..."; // 客户端证书内容 const char AWS_CERT_PRIVATE[] = "..."; // 私钥内容 const char* SUBSCRIBE_TOPIC = "esp32/pub"; // MQTT消息回调函数 void messageHandler(char* topic, byte* payload, unsigned int length) { // 处理收到的消息逻辑 Serial.print("Received message on topic: "); Serial.println(topic); } WiFiClientSecure net; PubSubClient client(net); void setup() { Serial.begin(115200); connectAWS(net, client, THINGNAME, AWS_IOT_ENDPOINT, AWS_CERT_CA, AWS_CERT_CRT, AWS_CERT_PRIVATE, SUBSCRIBE_TOPIC, WIFI_SSID, WIFI_PASSWORD, messageHandler); } void loop() { if (!client.connected()) { // 可选:添加重连逻辑 } client.loop(); }
额外注意事项
- 证书需以
const char[]形式定义,避免使用const char*,确保多行字符串能被正确存储。 - 主文件中的
WiFiClientSecure和PubSubClient对象需定义为全局变量,保证生命周期覆盖整个程序运行过程。 - 如果需要进一步封装,可以把相关参数封装成结构体,减少函数参数数量。
内容的提问来源于stack exchange,提问作者Krapp
相关产品推荐
相关产品推荐

