我们在单片机上解析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)和静态变量
修改后重新编译调试,问题得到解决。