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

ESP32经UART向Telit LE910C1发送at#httpsnd指令异常问题

问题背景

定制板卡牌载Telit LE910C1-EUX模块,模块通过UART连接ESP32处理器,ESP32基于ESP-IDF v4.3.2框架开发。

现有实现代码

指令发送函数

esp_err_t TelitSerialCommand(const char* command) {

    // Send command over UART
    uart_write_bytes(UART_NUM_1, command, strlen(command));
    if(uart_wait_tx_done(UART_NUM_1, 100) != ESP_OK) {
        ESP_LOGE(TAG, "Could not send Telit command");
        return ESP_ERR_TIMEOUT;
    }

    // Wait for two seconds
    vTaskDelay(2000/portTICK_RATE_MS);
    return ESP_OK;
}

响应读取函数

esp_err_t TelitSerialRead(char* RxBuf, size_t length) {

    // First, clean current string holding past message
    strncpy(RxBuf, "", length);

    // Check how many data bytes are present in UART buffer
    esp_err_t status = uart_get_buffered_data_len(UART_NUM_1, &length);
    if (status != ESP_OK) {
        ESP_LOGE(TAG, "Could not get UART rx buffer size");
        return status;
    }

    // Read those bytes
    length = uart_read_bytes(UART_NUM_1, RxBuf, length, 100);

    // Clean UART buffer
    uart_flush(UART_NUM_1);
    return ESP_OK;
}
故障现象

上述两个函数可完成常规AT指令收发,但执行at#httpsnd POST操作时指令异常。
使用的AT指令序列如下:

at+cmee=2\r
at#sgact=1,1\r
at#httpcfg=0,"www.httpbin.org",80,0,,,0\r
at#httpsnd=0,0,"/post",15,"application/json"\r
  • 预期表现:最后一条指令发送后,Telit模块返回>>>提示符,标识已准备好接收POST载荷数据
  • 实际表现:发送后仅收到指令回显,模块无>>>响应,状态与指令未携带\r结束符、持续等待回车输入完全一致;只有发送下一条AT指令后,才会收到延后的>>>响应。已确认at#httpsnd指令末尾确实添加了回车符,无法定位根因。
已完成验证项
  • 绕过ESP32,通过USB转串口接minicom直接和Telit模块通信,所有指令均可正常执行
  • 模块网络连接正常,可ping通8.8.8.8
  • GET类指令AT#HTTPQRY=0,0,"/get"\r可正常执行,无异常
排查思路与解决方案

根因是现有UART交互逻辑和AT#HTTPSND的响应时序不匹配,和指令是否带回车无关,具体问题点:

  • 固定2秒延时的逻辑完全不可靠:普通AT指令响应快,2秒延时足够等到完整返回,但AT#HTTPSND触发后模块需要内部完成HTTP连接建立、接收缓冲区准备等操作,处理时长波动很大。固定2秒到期时,模块往往还没输出>>>提示符,此时调用读函数只能读到缓冲区里存的指令回显,后续到达的>>>会被读函数末尾的uart_flush直接清空。等发送下一条AT指令时,模块刚好把之前积压的>>>输出,就出现了响应延后到下一条指令发送后才收到的假象。
  • 读函数存在逻辑硬伤:uart_get_buffered_data_len会修改传入的长度参数为当前缓冲区已就绪的字节数,直接用这个值作为uart_read_bytes的读取长度,再加100ms超时,只能读到调用读函数那一刻已经存在缓冲区里的数据,后续陆续到达的响应根本读不到,最后还被flush操作丢弃。
  • 不用排查指令行结束符:minicom直连测试全流程正常,说明模块配置的\r指令结束符是匹配的,这部分不用浪费时间。

具体修复方案:

  1. 删掉收发流程里所有固定时长的vTaskDelay等响应逻辑,改成基于响应标志位的轮询读取:普通AT指令以OK/ERROR作为读取结束标志,AT#HTTPSND单独判断,读到>>>就停止读取进入载荷发送流程,等待超时可以设为10秒,给模块留足网络操作的时间。
  2. 立刻去掉读函数里无条件执行的uart_flush,这个操作会直接丢弃硬件缓冲区里未被应用读取的所有数据,是丢响应的核心诱因。
  3. 修正读函数的长度处理逻辑:单独定义变量存储UART缓冲区当前可读字节数,不要用这个值覆盖传入的接收缓冲区总长度,避免内存越界。
  4. 发送POST载荷时,严格按照指令里声明的长度发送对应字节数的JSON数据,不要额外加回车换行,发完后继续轮询等待模块返回最终的OK/ERROR和HTTP状态码即可。

核心参考实现:

// 等待指定响应串的工具函数
esp_err_t TelitWaitForResponse(const char* expected_resp, char* rxBuf, size_t buf_len, uint32_t timeout_ms) {
    size_t recv_len = 0;
    memset(rxBuf, 0, buf_len);
    uint32_t start_tick = xTaskGetTickCount();
    while ((xTaskGetTickCount() - start_tick) * portTICK_RATE_MS < timeout_ms) {
        size_t available = 0;
        uart_get_buffered_data_len(UART_NUM_1, &available);
        if (available > 0) {
            size_t read_to_len = available;
            if (recv_len + available >= buf_len) {
                read_to_len = buf_len - recv_len - 1;
            }
            int readn = uart_read_bytes(UART_NUM_1, rxBuf + recv_len, read_to_len, pdMS_TO_TICKS(20));
            if (readn > 0) {
                recv_len += readn;
                rxBuf[recv_len] = '\0';
                if (strstr(rxBuf, expected_resp) != NULL) {
                    return ESP_OK;
                }
            }
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
    return ESP_ERR_TIMEOUT;
}

AT#HTTPSND调用流程:

  • 发送指令at#httpsnd=0,0,"/post",15,"application/json"\r
  • 调用上述工具函数等待>>>,超时设为10000ms
  • 收到>>>后,直接发送15字节的JSON载荷,不要附加回车换行
  • 再次调用工具函数等待OK响应,获取POST请求结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:42:15