STM32F03C8T6通过AT指令获取天气API

这里写目录标题

  • STM32F03C8T6通过AT指令获取天气API
  • [STM32 天气API接口调试总结](#STM32 天气API接口调试总结)
    • 问题现象
    • 失败原因分析
      • [1. **过度复杂的 JSON 解析逻辑**](#1. 过度复杂的 JSON 解析逻辑)
      • [2. **cJSON 库的内存和字符串处理问题**](#2. cJSON 库的内存和字符串处理问题)
      • [3. **字符串截断问题**](#3. 字符串截断问题)
      • [4. **过多的调试输出干扰**](#4. 过多的调试输出干扰)
    • 成功的关键改进
      • [✅ 1. **简化 JSON 解析逻辑**](#✅ 1. 简化 JSON 解析逻辑)
      • [✅ 2. **使用简单的字符串查找函数**](#✅ 2. 使用简单的字符串查找函数)
      • [✅ 3. **移除 cJSON 依赖**](#✅ 3. 移除 cJSON 依赖)
      • [✅ 4. **优化等待机制**](#✅ 4. 优化等待机制)
      • [✅ 5. **精简调试输出**](#✅ 5. 精简调试输出)
    • 核心经验教训
      • [🎯 1. **简单就是美**](#🎯 1. 简单就是美)
      • [🎯 2. **参考成功案例**](#🎯 2. 参考成功案例)
      • [🎯 3. **嵌入式环境的特殊性**](#🎯 3. 嵌入式环境的特殊性)
      • [🎯 4. **调试要适度**](#🎯 4. 调试要适度)
    • 最终成功的代码特点
    • 成功输出示例
    • 总结

STM32F03C8T6通过AT指令获取天气API

浏览器控制台输出strlen

js 复制代码
function calcHttpLength(apiKey, location) {
    const req = `GET /v3/weather/now.json?key=${apiKey}&location=${location}&language=en&unit=c HTTP/1.1\r\nHost: api.seniverse.com\r\nConnection: close\r\n\r\n`;
    console.log("Length:", req.length, "bytes");
    console.log("AT Command: AT+CIPSEND=" + req.length);
    return req.length;
}

STM32 天气API接口调试总结

问题现象

连续多次尝试获取天气数据失败,表现为:

  • JSON 解析失败
  • 数据被截断
  • cJSON_Parse 返回错误

失败原因分析

1. 过度复杂的 JSON 解析逻辑

问题:

  • 使用了复杂的嵌套查找逻辑
  • 尝试从 "results" 往前查找 {
  • 多层指针操作容易出错

表现:

复制代码
'now' not found
JSON parse failed

2. cJSON 库的内存和字符串处理问题

问题:

  • cJSON 对输入字符串要求严格,必须完整且格式正确
  • 接收缓冲区中可能存在 \0 字符导致字符串提前终止
  • HTTP 响应头和 JSON 数据混在一起

表现:

复制代码
cJSON_Parse failed
Error before: path":"Beijing...
JSON length: 260 (实际应该更长)

3. 字符串截断问题

问题:

  • 使用 strlen() 计算长度,遇到 \0 就停止
  • HTTP 响应中可能包含二进制数据或控制字符
  • JSON 数据被截断到 260-270 字节

表现:

复制代码
Received 720 bytes
JSON length: 260 bytes  // 不匹配!

4. 过多的调试输出干扰

问题:

  • 大量的 printf 调试信息
  • 打印完整的 JSON 数据(可能很长)
  • 影响程序执行时序

成功的关键改进

✅ 1. 简化 JSON 解析逻辑

改进:

c 复制代码
// 之前:复杂的嵌套查找
p_results = strstr(json, "\"results\"");
p_location = strstr(p_results, "\"location\"");
p_now = strstr(p_results, "\"now\"");
// 然后从各个位置解析...

// 现在:直接在整个缓冲区中查找
if(strstr(ESP8266_RxBuffer, "\"results\""))
{
    Weather_ParseJSON(ESP8266_RxBuffer);
}

优势:

  • 不需要精确定位 JSON 起始位置
  • 直接在整个缓冲区中搜索关键字
  • 容错性更强

✅ 2. 使用简单的字符串查找函数

改进:

c 复制代码
// 自定义的 GetStringBetween 函数
static uint8_t GetStringBetween(char *src, char *start, char *end, 
                                 char *output, uint16_t maxLen)
{
    char *p_start = strstr(src, start);
    if(p_start == NULL) return 0;
    
    p_start += strlen(start);
    char *p_end = strstr(p_start, end);
    if(p_end == NULL) return 0;
    
    // 复制数据
    uint16_t len = p_end - p_start;
    if(len >= maxLen) len = maxLen - 1;
    strncpy(output, p_start, len);
    output[len] = '\0';
    
    return 1;
}

// 使用示例
GetStringBetween(json, "\"name\":\"", "\"", temp, sizeof(temp));
GetStringBetween(json, "\"text\":\"", "\"", temp, sizeof(temp));
GetStringBetween(json, "\"temperature\":\"", "\"", temp, sizeof(temp));

优势:

  • 不依赖第三方库(cJSON)
  • 直接处理原始字符串,不受 \0 影响
  • 代码简单易懂
  • 参考了成功示例的实现方式

✅ 3. 移除 cJSON 依赖

原因:

  • cJSON 对输入要求严格
  • 需要完整、格式正确的 JSON 字符串
  • 在嵌入式环境中可能有内存碎片问题

改进:

  • 使用简单的字符串查找
  • 只提取需要的字段
  • 不需要解析完整的 JSON 结构

✅ 4. 优化等待机制

改进:

c 复制代码
// 之前:固定延时
Delay_ms(3000);

// 现在:超时循环等待
uint16_t TimeOut = 0;
while(TimeOut < 100 && !strstr(ESP8266_RxBuffer, "OK"))
{
    Delay_ms(10);
    TimeOut++;
}

优势:

  • 响应更快(收到数据立即处理)
  • 有超时保护
  • 参考了成功示例的实现

✅ 5. 精简调试输出

改进:

c 复制代码
// 之前:大量详细的调试信息
DEBUG_PRINTF("========== 开始获取天气信息 ==========\r\n");
DEBUG_PRINTF("城市: %s\r\n", city);
DEBUG_PRINTF("API Key: %s\r\n", api_key);
DEBUG_PRINTF("关闭旧连接...\r\n");
// ... 还有很多

// 现在:简洁的关键信息
printf("[Weather] Getting weather for %s...\r\n", city);
printf("[Weather] Connecting to server...\r\n");
printf("[Weather] Request sent, waiting response...\r\n");
printf("[Weather] Success!\r\n");

优势:

  • 减少串口输出时间
  • 不影响程序时序
  • 信息更清晰易读

核心经验教训

🎯 1. 简单就是美

  • 不要过度设计
  • 能用简单方法解决的,不要用复杂方案
  • 字符串查找比完整 JSON 解析更适合嵌入式环境

🎯 2. 参考成功案例

  • 看到别人成功的代码,直接参考其实现方式
  • 不要重复造轮子
  • 成功的示例已经验证过可行性

🎯 3. 嵌入式环境的特殊性

  • 内存有限,避免使用复杂的库
  • 字符串处理要小心 \0 字符
  • HTTP 响应包含头部和数据,需要容错处理

🎯 4. 调试要适度

  • 过多的调试输出反而影响程序运行
  • 关键节点输出即可
  • 成功后可以进一步精简

最终成功的代码特点

简洁 :150 行代码(之前 300+ 行)

可靠 :基于成功示例的实现

高效 :超时等待机制,响应快

易维护 :逻辑清晰,易于理解

无依赖:不需要 cJSON 等第三方库

成功输出示例

复制代码
[Weather] Getting weather for beijing...
[Weather] Connecting to server...
[Weather] Request sent, waiting response...
[Weather] Received 720 bytes
[Weather] Parsing JSON...

========================================
         Weather Information
========================================
City:        Beijing
Weather:     Clear
Temperature: -1 C
Temp Range:  -4 ~ 4 C
========================================

[Weather] Success!

总结

失败的根本原因: 过度复杂化,使用了不适合嵌入式环境的方案(cJSON + 复杂解析逻辑)

成功的关键: 回归简单,参考成功示例,使用基础的字符串查找函数

教训: 在嵌入式开发中,简单、可靠、易维护比功能强大更重要!

相关推荐
zhengxianyi5152 小时前
vue-cli build, vite build 生产部署刷新或弹窗404,页面空白修复方法
前端·javascript·vue.js·nginx·生产部署
Filotimo_2 小时前
前端项目打包部署完整流程
前端
Savvy..2 小时前
Day15 Talis 前端
前端
恋爱绝缘体12 小时前
Vue.js 组件 - 自定义事件【1】
前端·javascript·vue.js
梦6502 小时前
JavaScript ES5 + ES6+ 字符串 (String) 所有方法大全
前端·javascript·es6
梦6502 小时前
JavaScript (ES5)+ES6+jQuery 核心对象方法大全
javascript·es6·jquery
馨谙2 小时前
面试题----用户,组,su,su-,sudo,sudo-,nologin shell
java·前端·数据库
王同学 学出来3 小时前
React案例实操(二)
前端·react.js·前端框架
向前V3 小时前
Flutter for OpenHarmony 二维码扫描App实战 - 关于实现
开发语言·javascript·flutter