You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何解析AT命令返回的C字符串以判断Quectel模块FOTA固件升级完成

解决思路与实现方案

我之前处理过不少Quectel模块的FOTA升级场景,这个需求其实很常见,核心就是处理AT命令的流式响应输出——模块会持续推送状态信息,直到升级完成(或失败)。咱们一步步拆解怎么实现你的需求:

核心逻辑步骤

  • 先建立并配置好与模块的通信连接(串口/虚拟串口,确保波特率、数据位、奇偶校验等参数和模块完全匹配)
  • 发送AT+QFOTADL="https://www.quectel.com:100/update.zip"命令后,立刻进入循环读取流程
  • 每次读取一段数据,将其追加到缓冲区(避免目标结束标识被拆分到两次读取中)
  • 持续检查缓冲区中是否出现目标字符串+QIND: "FOTA","END",0
    • 匹配到则退出循环,判定升级成功完成
    • 未匹配到就继续读取,同时要设置超时机制,防止升级异常时程序无限挂起

具体实现示例

1. Python脚本(适合PC端调试/自动化场景)

pyserial库操作串口是快速验证的首选方案:

import serial
import time

def wait_for_fota_complete(serial_port, timeout=3600):
    # 初始化缓冲区和超时计时
    recv_buffer = ""
    start_time = time.time()
    
    while time.time() - start_time < timeout:
        # 读取串口内所有可用数据
        if serial_port.in_waiting > 0:
            raw_data = serial_port.read(serial_port.in_waiting).decode('utf-8')
            recv_buffer += raw_data
            print(f"收到状态: {raw_data.strip()}")
            
            # 检查成功结束标识
            if '+QIND: "FOTA","END",0' in recv_buffer:
                print("✅ FOTA固件升级完成!")
                return True
            # 可选:处理升级失败的情况
            elif '+QIND: "FOTA","END",1' in recv_buffer:
                print("❌ FOTA固件升级失败!")
                return False
        
        time.sleep(0.1)  # 短暂延时,避免CPU占用过高
    
    print("⏰ 升级超时,请检查模块状态!")
    return False

# 配置串口参数(根据你的模块实际情况修改)
ser = serial.Serial(
    port='COM3',  # Windows端口,Linux为/dev/ttyUSB0这类路径
    baudrate=115200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_1,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

# 发送FOTA升级命令
ser.write(b'AT+QFOTADL="https://www.quectel.com:100/update.zip"\r\n')
time.sleep(0.5)

# 等待升级完成
wait_for_fota_complete(ser)

ser.close()

2. 嵌入式C语言(适合MCU对接模块的场景)

如果是在嵌入式设备上实现,核心是通过UART读取数据并维护缓冲区,示例如下:

#include <string.h>
#include "uart_driver.h"  // 替换为你的MCU UART驱动头文件

#define FOTA_SUCCESS_FLAG "+QIND: \"FOTA\",\"END\",0"
#define FOTA_FAILED_FLAG  "+QIND: \"FOTA\",\"END\",1"
#define BUFFER_MAX_SIZE   512

uint8_t uart_recv_buf[BUFFER_MAX_SIZE];
uint16_t buf_len = 0;

// 获取系统tick的函数,需根据你的MCU实现替换
uint32_t get_system_tick(void);
// 毫秒延时函数,需根据你的MCU实现替换
void delay_ms(uint16_t ms);

int check_fota_result(void) {
    uint32_t start_tick = get_system_tick();
    // 设置1小时超时(可根据固件大小调整)
    while (get_system_tick() - start_tick < 3600 * 1000) {
        uint8_t recv_byte;
        // 循环读取UART接收到的每一个字节
        while (uart_read_byte(&recv_byte)) {
            if (buf_len < BUFFER_MAX_SIZE - 1) {
                uart_recv_buf[buf_len++] = recv_byte;
                uart_recv_buf[buf_len] = '\0';  // 确保字符串以'\0'结尾
                
                // 检查成功标识
                if (strstr((char*)uart_recv_buf, FOTA_SUCCESS_FLAG) != NULL) {
                    return 1;  // 返回1表示升级成功
                }
                // 检查失败标识
                if (strstr((char*)uart_recv_buf, FOTA_FAILED_FLAG) != NULL) {
                    return -1; // 返回-1表示升级失败
                }
            } else {
                // 缓冲区满时重置,避免溢出
                buf_len = 0;
                memset(uart_recv_buf, 0, BUFFER_MAX_SIZE);
            }
        }
        delay_ms(10);
    }
    return 0;  // 返回0表示超时
}

// 使用示例
int main(void) {
    uart_init(115200);  // 初始化UART波特率
    
    // 发送FOTA升级命令
    uart_send_string("AT+QFOTADL=\"https://www.quectel.com:100/update.zip\"\r\n");
    
    int fota_result = check_fota_result();
    if (fota_result == 1) {
        // 升级成功后的处理逻辑
    } else if (fota_result == -1) {
        // 升级失败后的处理逻辑
    } else {
        // 超时后的处理逻辑
    }
    
    while(1);
}

关键注意事项

  • 缓冲区累积:一定要用缓冲区存储读取到的所有数据,因为目标结束标识可能被拆分成多次UART发送,单次读取可能只拿到一半内容。
  • 超时机制:必须设置合理的超时时间(FOTA升级耗时取决于固件大小,从几分钟到几十分钟都有可能),避免程序无限挂起。
  • 错误处理:别忘了处理+QIND: "FOTA","END",1的情况,这代表升级失败,需要做对应的错误排查或重试逻辑。

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

火山引擎 最新活动