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

ESP32蓝牙接收转义字符串转可识别Hex格式并通过RS232发送问题

问题分析

你遇到的核心问题是:蓝牙接收到的是包含转义序列的文本字符串,而非编译器解析后的实际字节流。

  • 当你在代码中直接写Serial2.write("\e\x34\x54\x45\x53\x54\r")时,C++编译器会自动把转义序列(比如\e、\x34、\r)转换成对应的ASCII字节:0x1B(ESC)、0x34、0x54、0x45、0x53、0x54、0x0D(CR),这正是接收器需要的命令格式。
  • 但蓝牙接收到的"\e\x34\x54\x45\x53\x54\r"是一串普通字符:\、e、\、x、3、4、\、x、5、4...,直接用message.c_str()发送的是这些字符本身,接收器自然无法识别。
解决方案

需要实现一个转义序列解析函数,把蓝牙收到的文本字符串转换成实际的字节数组,再通过Serial2发送。以下是完整的实现代码:

// 解析转义字符串为字节数组
size_t parseEscapedString(const String& input, uint8_t* output, size_t maxOutputSize) {
    size_t outputIndex = 0;
    size_t inputLength = input.length();
    
    for (size_t i = 0; i < inputLength; i++) {
        if (input[i] == '\\' && i + 1 < inputLength) {
            // 识别转义字符
            switch (input[i+1]) {
                case 'e': // ESC字符,对应0x1B
                    if (outputIndex < maxOutputSize) {
                        output[outputIndex++] = 0x1B;
                    }
                    i++; // 跳过下一个字符
                    break;
                case 'r': // 回车符,对应0x0D
                    if (outputIndex < maxOutputSize) {
                        output[outputIndex++] = 0x0D;
                    }
                    i++;
                    break;
                case 'n': // 换行符,对应0x0A(如果需要的话)
                    if (outputIndex < maxOutputSize) {
                        output[outputIndex++] = 0x0A;
                    }
                    i++;
                    break;
                case 'x': // 十六进制字节,格式\xXX
                    if (i + 3 <= inputLength) {
                        // 提取两位十六进制字符
                        String hexStr = input.substring(i+2, i+4);
                        uint8_t byteVal = strtol(hexStr.c_str(), nullptr, 16);
                        if (outputIndex < maxOutputSize) {
                            output[outputIndex++] = byteVal;
                        }
                        i += 3; // 跳过\xXX的三个字符
                    }
                    break;
                default:
                    // 未知转义,直接保留原字符
                    if (outputIndex < maxOutputSize) {
                        output[outputIndex++] = input[i];
                    }
                    break;
            }
        } else {
            // 普通字符,直接复制
            if (outputIndex < maxOutputSize) {
                output[outputIndex++] = input[i];
            }
        }
    }
    return outputIndex;
}

// 蓝牙消息处理代码
void handleBTMessage() {
    if (SerialBT.available()) {
        String message = SerialBT.readStringUntil('\n');
        // 去掉字符串末尾可能的换行符或空格
        message.trim();
        
        uint8_t commandBuffer[64]; // 足够存储你的命令,可按需调整大小
        size_t commandLength = parseEscapedString(message, commandBuffer, sizeof(commandBuffer));
        
        // 发送解析后的字节到RS232
        Serial2.write(commandBuffer, commandLength);
        
        // 调试输出(可选)
        Serial.print("BT Message received: ");
        Serial.println(message);
        Serial.print("Parsed command length: ");
        Serial.println(commandLength);
        Serial.print("Parsed bytes (hex): ");
        for (size_t i = 0; i < commandLength; i++) {
            Serial.printf("%02X ", commandBuffer[i]);
        }
        Serial.println();
    }
}

// 在loop函数中调用
void loop() {
    handleBTMessage();
    // 其他代码...
}
使用说明
  1. 把上述代码加入你的ESP32项目中,替换原有的蓝牙消息处理逻辑。
  2. parseEscapedString函数会处理常见的转义序列:
    • \e → 0x1B(ESC)
    • \r → 0x0D(回车)
    • \xXX → 两位十六进制对应的字节(比如\x34→0x34)
    • 如果需要支持其他转义序列(比如\n、\t),可以在switch中添加对应的case。
  3. 解析后的字节会存入commandBuffer,然后通过Serial2.write(commandBuffer, commandLength)发送,这和你直接在代码中写硬编码命令的效果完全一致。
验证

使用上述代码后,蓝牙收到的"\e\x34\x54\x45\x53\x54\r"会被解析成:
0x1B 0x34 0x54 0x45 0x53 0x54 0x0D,和你硬编码发送的字节完全相同,接收器应该会返回Test4的正确响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:00:28