当前位置: 首页 > news >正文

cJSON在STM32单片机上使用遇到解析数据失败问题

        我们在单片机上解析JSON格式时(比如在用云平台物联网开发时),可以直接使用cJson库来完成自己的操作,而不需要单独实现,具体使用方法可以搜一下。

  • cJson:一个基于 C 语言的 Json 库,它是一个开源项目,github 下载地址:https://github.com/DaveGamble/cJSON
  • cJson库组成:主要的文件有两个,一个 cJSON.c 一个 cJSON.h。使用时,将头文件 include 进去即可

本次记录下在使用时遇到的一个问题:当json的数据多了之后,单片机在解析数据时就会出解析失败。

问题定位:通过调试器去追踪出问题的位置,发现在parse_object函数中出现错误


/* Build an object from the text. */
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
{cJSON *head = NULL; /* linked list head */cJSON *current_item = NULL;if (input_buffer->depth >= CJSON_NESTING_LIMIT){return false; /* to deeply nested */}input_buffer->depth++;if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')){goto fail; /* not an object */}input_buffer->offset++;buffer_skip_whitespace(input_buffer);if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')){goto success; /* empty object */}/* check if we skipped to the end of the buffer */if (cannot_access_at_index(input_buffer, 0)){input_buffer->offset--;goto fail;}/* step back to character in front of the first element */input_buffer->offset--;/* loop through the comma separated array elements */do{/* allocate next item */cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));if (new_item == NULL){goto fail; /* allocation failure */}/* attach next item to list */if (head == NULL){/* start the linked list */current_item = head = new_item;}else{/* add to the end and advance */current_item->next = new_item;new_item->prev = current_item;current_item = new_item;}if (cannot_access_at_index(input_buffer, 1)){goto fail; /* nothing comes after the comma */}/* parse the name of the child */input_buffer->offset++;buffer_skip_whitespace(input_buffer);if (!parse_string(current_item, input_buffer)){goto fail; /* failed to parse name */}buffer_skip_whitespace(input_buffer);/* swap valuestring and string, because we parsed the name */current_item->string = current_item->valuestring;current_item->valuestring = NULL;if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')){goto fail; /* invalid object */}/* parse the value */input_buffer->offset++;buffer_skip_whitespace(input_buffer);if (!parse_value(current_item, input_buffer)){goto fail; /* failed to parse value */}buffer_skip_whitespace(input_buffer);}while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')){goto fail; /* expected end of object */}success:input_buffer->depth--;if (head != NULL) {head->prev = current_item;}item->type = cJSON_Object;item->child = head;input_buffer->offset++;return true;fail:if (head != NULL){cJSON_Delete(head);}return false;
}

具体位置是在申请内存时出现错误

/* allocate next item */
cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
if (new_item == NULL)
{goto fail; /* allocation failure */
}

这个问题就就比较明确了

在 Keil MDK 环境中为 STM32F103C8T6 编程时遇到内存分配函数返回 NULL 的问题,这通常是由于堆(heap)空间不足或内存管理配置不当引起的。

问题原因分析:

  1. 堆空间不足(最常见原因):

    • STM32F103C8T6 仅有 20KB RAM

    • 默认堆大小只有 512 字节(0x200)

    • 动态内存分配超出可用堆空间

以下是解决方案:

增加堆空间大小(最有效方案)

修改启动文件 (startup_stm32f103xb.s):

assembly

; 查找 Heap_Size 定义
Heap_Size      EQU     0x00000200  ; 原始 512 字节; 修改为更大的值 (例如 4KB)
Heap_Size      EQU     0x00001000  ; 4KB (最大不要超过可用RAM)

计算建议值

  • 总 RAM:20KB (0x5000)

  • 推荐堆大小:2-4KB (0x800-0x1000)

  • 保留足够空间给栈(Stack)和静态变量

修改后重新编译调试,问题得到解决。

http://www.dtcms.com/a/301343.html

相关文章:

  • 计算柱状图中最大的矩形【单调栈】
  • Dify 本地化部署深度解析与实战指南
  • 蜣螂优化算法的华丽转身:基于Streamlit的MSIDBO算法可视化平台
  • 【ESP32设备通信】-W5500与ESP32 /ESP32 S3集成
  • MySQL - 性能优化
  • Java面试实战:电商高并发与分布式事务处理
  • maven optional 功能详解
  • Java进阶7:Junit单元测试
  • 数据结构基础内容(第九篇:最短路径)
  • OpenCv中的 KNN 算法实现手写数字的识别
  • 电子电路设计学习
  • git回退版本教程
  • Java validation
  • Java学习第八十部分——Freemarker
  • Linux c网络专栏第三章DPDK
  • Petalinux驱动开发
  • Linux驱动开发笔记(五)——设备树(下)——OF函数
  • 人社部物联网安装调试员的实训平台
  • RabbitMq 常用命令和REST API
  • 9.SpringBoot Web请求参数绑定方法
  • 盛最多水的容器-leetcode
  • 《Java 程序设计》第 7 章 - 继承与多态
  • 记录几个SystemVerilog的语法——时钟块和进程通信
  • maven聚合工程(多个mudule只编译、打包指定module)
  • JVM类加载机制全流程详解
  • 通过硬编码函数地址并转换为函数指针来调用函数
  • Java#包管理器来时的路
  • Leetcode-3427变长子数组求和
  • Mitk教程案例项目编译
  • 嵌入式——单片机的独立按键