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)空间不足或内存管理配置不当引起的。
问题原因分析:
堆空间不足(最常见原因):
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)和静态变量
修改后重新编译调试,问题得到解决。