You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP8266解析RGB十六进制字符串时B值非零崩溃问题求助

ESP8266解析RGB十六进制码时B值非零崩溃的修复

问题描述

开发ESP8266项目时,设备接收格式如$3#FF00FF的RGB十六进制码控制LED灯带。当前代码在B值非零时(如$3#FF00FF、$3#FF0012)会崩溃,B值为0时(如$3#FF0000)运行正常,且崩溃时自动看门狗未触发,推测是内存相关问题。

核心问题分析

崩溃根源在于b1 = strtol(data.substring(7, 9).c_str(), NULL, 16);这行代码:

  • Arduino的String.substring()会返回一个临时String对象,调用.c_str()后得到的是该临时对象内部的字符指针。
  • 当这条语句执行完毕,临时String对象会被立即销毁,其内部的字符数组内存也会被释放,此时strtol可能还在使用这个已经失效的野指针。
  • 当B值为0时,释放的内存恰好还保留着00的残留数据,strtol能解析出正确结果,不会触发明显错误;但B值非零时,后续内存操作会覆盖这段区域,导致strtol访问无效内存,引发崩溃。

另外,代码中dataLen变量未定义,需要确保它是data.length()的正确取值,否则可能导致错误进入解析分支。

修复方案

方案1:延长临时字符串生命周期

将substring的结果存入临时String变量,确保在strtol解析完成前内存不被释放:

void loop() {
  String data = // 从服务器获取数据,格式如"$3#FF0000"
  int dataLen = data.length(); // 补充dataLen的定义

  if (data.charAt(0) == '$' && dataLen == 9) {
    char ledStrip = data.charAt(1);
    char buffer[10];
    data.toCharArray(buffer, sizeof(buffer));

    r1 = strtol(data.substring(3, 5).c_str(), NULL, 16);
    g1 = strtol(data.substring(5, 7).c_str(), NULL, 16);

    // 先将子串存入临时变量,避免野指针
    String bSub = data.substring(7, 9);
    b1 = strtol(bSub.c_str(), NULL, 16);

    Serial.print("Received RGB values for Strip 1 & 2: R=");
    Serial.print(r1);
    Serial.print(", G=");
    Serial.print(g1);
    Serial.print(", B=");
    Serial.println(b1);
  }
}

方案2:直接操作字符计算数值(更高效)

跳过substring和strtol,直接通过字符转换计算RGB值,避免临时对象和内存分配:

// 新增十六进制字符转整数的辅助函数
int hexCharToInt(char c) {
  if (c >= '0' && c <= '9') return c - '0';
  if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
  if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
  return 0; // 非法字符返回0
}

void loop() {
  String data = // 从服务器获取数据,格式如"$3#FF0000"
  int dataLen = data.length();

  if (data.charAt(0) == '$' && dataLen == 9) {
    char ledStrip = data.charAt(1);

    // 直接通过字符计算RGB值
    r1 = (hexCharToInt(data.charAt(3)) << 4) | hexCharToInt(data.charAt(4));
    g1 = (hexCharToInt(data.charAt(5)) << 4) | hexCharToInt(data.charAt(6));
    b1 = (hexCharToInt(data.charAt(7)) << 4) | hexCharToInt(data.charAt(8));

    Serial.print("Received RGB values for Strip 1 & 2: R=");
    Serial.print(r1);
    Serial.print(", G=");
    Serial.print(g1);
    Serial.print(", B=");
    Serial.println(b1);
  }
}

方案3:利用已有的char数组解析

代码中已经将data转成了char数组buffer,直接用该数组解析更安全:

void loop() {
  String data = // 从服务器获取数据,格式如"$3#FF0000"
  int dataLen = data.length();

  if (data.charAt(0) == '$' && dataLen == 9) {
    char ledStrip = data.charAt(1);
    char buffer[10];
    data.toCharArray(buffer, sizeof(buffer));

    // 构造两位的十六进制字符串解析
    char rBuf[3] = {buffer[3], buffer[4], '\0'};
    r1 = strtol(rBuf, NULL, 16);
    
    char gBuf[3] = {buffer[5], buffer[6], '\0'};
    g1 = strtol(gBuf, NULL, 16);
    
    char bBuf[3] = {buffer[7], buffer[8], '\0'};
    b1 = strtol(bBuf, NULL, 16);

    Serial.print("Received RGB values for Strip 1 & 2: R=");
    Serial.print(r1);
    Serial.print(", G=");
    Serial.print(g1);
    Serial.print(", B=");
    Serial.println(b1);
  }
}

内容的提问来源于stack exchange,提问作者kazar4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:38:18