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

发布于:2025-07-28 ⋅ 阅读:(12) ⋅ 点赞:(0)

        我们在单片机上解析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)和静态变量

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


网站公告

今日签到

点亮在社区的每一天
去签到