UART多文件传输异常:Windows到BeagleBone未生成独立文件求助
解决UART多文件传输合并存储问题
问题根源
当前协议逻辑存在两处关键错误:
- 发送端在文件内容之前发送0x03标记,但接收端把0x03当作文件结束标记,导致刚进入数据接收状态就触发文件关闭,后续文件内容无法写入对应文件。
- 接收端的
filenameBuffer在拼接路径后未保留原文件名,后续文件会复用被修改后的路径,导致内容混乱存储。
修复方案
1. 发送端Python代码修改
调整协议逻辑:将0x03作为文件内容结束标记,放在文件数据之后发送,而非之前。
import serial import time def send_file(serial_port, file_name): try: # 发送文件开始标记 serial_port.write(bytes([0x01])) # 发送文件名 serial_port.write(file_name.encode()) # 发送文件名结束标记 serial_port.write(bytes([0x02])) # 打开文件并发送内容 with open(f"C:/Users/HP/OneDrive/Desktop/DRS_Database/{file_name}", "rb") as file: file_data = file.read() serial_port.write(file_data) # 发送文件内容结束标记(放在数据之后) serial_port.write(bytes([0x03])) print(f"{file_name} 发送成功") except FileNotFoundError: print(f"未找到文件 {file_name}") def send_files(serial_port, filenames): for file_name in filenames: send_file(serial_port, file_name) time.sleep(1) # 给接收端留处理时间 # 发送全部传输完成标记 serial_port.write(bytes([0x04])) # 初始化串口 ser = serial.Serial('COM11', 9600) file_names = ["DIA_ID.TXT", "OP_REC.TXT", "DIA_REC.TXT", "PAT_REC.TXT", "JAR_REC.TXT", "PRO_REC.TXT"] send_files(ser, file_names) ser.close()
2. 接收端C代码修改
- 修正DATA状态下0x03的逻辑:收到0x03时关闭当前文件,回到IDLE状态准备接收下一个文件。
- 新增独立变量存储完整文件路径,避免修改原文件名缓冲区。
- 每次进入FILENAME状态时重置文件指针,避免残留状态影响下一个文件。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <termios.h> #include <unistd.h> #define UART_PORT "/dev/ttyS1" #define BAUD_RATE B9600 #define UART_BUFFER_SIZE 8192 enum State { IDLE, FILENAME, DATA }; char readByte(int uart_fd) { char byte; ssize_t bytesRead = read(uart_fd, &byte, 1); if (bytesRead < 0) { perror("读取UART失败"); exit(EXIT_FAILURE); } return byte; } void receiveAndStoreFilesOverUART(const char *folderPath) { int uart_fd = open(UART_PORT, O_RDWR | O_NOCTTY); struct termios uart_config; if (uart_fd < 0) { perror("打开UART端口失败"); exit(EXIT_FAILURE); } // 配置UART参数 if (tcgetattr(uart_fd, &uart_config) < 0) { perror("获取UART配置失败"); close(uart_fd); exit(EXIT_FAILURE); } cfsetispeed(&uart_config, BAUD_RATE); cfsetospeed(&uart_config, BAUD_RATE); uart_config.c_cflag &= ~PARENB; uart_config.c_cflag &= ~CSTOPB; uart_config.c_cflag &= ~CSIZE; uart_config.c_cflag |= CS8; uart_config.c_cflag &= ~CRTSCTS; uart_config.c_cflag |= CREAD | CLOCAL; uart_config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); uart_config.c_cc[VMIN] = 1; uart_config.c_cc[VTIME] = 0; if (tcsetattr(uart_fd, TCSANOW, &uart_config) < 0) { perror("设置UART配置失败"); close(uart_fd); exit(EXIT_FAILURE); } enum State state = IDLE; int finished = 0; char filenameBuffer[256]; char fullFilePath[256]; // 独立存储完整路径,不修改原文件名缓冲区 FILE *file = NULL; while (!finished) { char byte = readByte(uart_fd); switch (state) { case IDLE: if (byte == 0x01) { state = FILENAME; filenameBuffer[0] = '\0'; file = NULL; // 重置文件指针 printf("进入文件名接收状态\n"); } else if (byte == 0x04) { finished = 1; printf("传输结束,回到空闲状态\n"); } break; case FILENAME: if (byte == 0x02) { // 拼接完整文件路径,保留原filenameBuffer snprintf(fullFilePath, sizeof(fullFilePath), "%s/%s", folderPath, filenameBuffer); state = DATA; printf("进入数据接收状态,目标文件:%s\n", fullFilePath); } else if (byte == 0x04) { finished = 1; printf("传输终止,回到空闲状态\n"); } else { // 防止缓冲区溢出 if (strlen(filenameBuffer) < sizeof(filenameBuffer)-1) { strncat(filenameBuffer, &byte, 1); } } break; case DATA: if (byte == 0x03) { // 收到文件结束标记,关闭文件 if (file != NULL) { fclose(file); file = NULL; printf("文件写入完成并关闭\n"); } state = IDLE; } else if (byte == 0x04) { // 收到终止信号,清理资源 if (file != NULL) { fclose(file); file = NULL; printf("关闭当前文件\n"); } finished = 1; } else { // 仅第一次写入时打开文件 if (file == NULL) { file = fopen(fullFilePath, "wb"); if (file == NULL) { perror("打开文件失败"); finished = 1; } } if (file != NULL) { fwrite(&byte, 1, 1, file); } } break; } } close(uart_fd); } int main(void) { const char *storageFolderPath = "/home/debian/NEW"; receiveAndStoreFilesOverUART(storageFolderPath); printf("接收完成\n"); return 0; }
验证步骤
- 重新编译BeagleBone端C代码并运行。
- 运行Windows端Python脚本。
- 查看
/home/debian/NEW目录,确认6个文件均独立生成且内容与原文件一致。
内容的提问来源于stack exchange,提问作者Avinash
相关产品推荐
相关产品推荐

