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

如何向ESP8266/Arduino通过UART串口正确传输包含0值的JPEG文件

问题根因

你遇到的问题本质是把二进制JPEG数据当做C风格字符串处理导致的截断:C字符串默认以\0(即0值)作为终止标识,因此只要数据中出现0,所有字符串处理逻辑都会自动截断该位置之后的内容。另外你当前的收发逻辑设计也存在漏洞,不适合二进制数据传输场景。

发送端修改方案
  1. 完全删除替换0值为ASCII字符'0'的逻辑,原有代码中sprintf(Storage_ReadWrite_Buffer[i],"%c", Storage_ReadWrite_Buffer[i]);是错误写法,sprintf第一个参数需要传入字符数组地址,传入单字节字符会导致内存访问越界,必须删除。
  2. 不要使用\0作为传输结束标识,二进制内容中本身就可能存在\0,会导致提前截断。
  3. 推荐改用「起始标记 + 数据长度 + 原始二进制数据」的帧结构,避免特殊字符冲突,修改后的参考代码如下:
// 帧结构:1字节起始符< + 2字节数据长度 + N字节原始数据
uint16_t data_len = 244;
RS485_Send_CHAN_A("<",1);
RS485_Send_CHAN_A((uint8_t*)&data_len, 2); // 发送数据长度
RS485_Send_CHAN_A(Storage_ReadWrite_Buffer, data_len); // 直接传输原始二进制数据,不需要做任何转换

修改后不会篡改原始JPEG的任何字节,也不会出现0值截断问题。

接收端修改方案
  1. 不要对接收缓冲区做字符串终止符赋值,也不要用Serial.println()这类字符串处理函数操作二进制数据,这类函数遇到0值会自动截断。
  2. 配合发送端的帧结构修改接收逻辑,根据指定长度接收数据,完全不需要判断内容中的特殊字符,参考代码如下:
const int numChars = 6000;
uint8_t receivedChars[numChars];
boolean newData = false;
int expectedLen = 0;

void recvWithLengthMarker() {
    static boolean recvInProgress = false;
    static int ndx = 0;
    static int lenReceived = 0;
    char startMarker = '<';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();
        if (!recvInProgress) {
            if (rc == startMarker) {
                recvInProgress = true;
                ndx = 0;
                lenReceived = 0;
                expectedLen = 0;
                memset(receivedChars, 0, numChars);
            }
        } else {
            // 先接收2字节的长度信息
            if (lenReceived < 2) {
                ((uint8_t*)&expectedLen)[lenReceived] = rc;
                lenReceived++;
            } else {
                // 按长度接收payload
                receivedChars[ndx++] = rc;
                if (ndx >= expectedLen) {
                    // 接收完成
                    recvInProgress = false;
                    newData = true;
                }
            }
        }
    }
}

void showNewData() {
    if (newData == true) {
        // 不要用Serial.println打印二进制数据,需要逐字节处理或者写入文件/上传
        // 示例:逐字节打印十六进制
        Serial.print("Received ");
        Serial.print(expectedLen);
        Serial.println(" bytes:");
        for (int i=0; i<expectedLen; i++) {
            Serial.print(receivedChars[i], HEX);
            Serial.print(" ");
        }
        Serial.println();
        newData = false;
        publish_image();
    }
}

void loop() {
   recvWithLengthMarker();
   showNewData();
}

修改完成后收发的JPEG数据和原始文件完全一致,不会出现字节替换或者截断的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 07:36:04