• 注册 / 登录
  • 切换到窄版
  • 查看: 1914|回复: 0

    单片机如何实现JSON解析

    [复制链接]

    676

    主题

    690

    帖子

    6810

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    6810
    发表于 2023-8-28 15:27:15 | 显示全部楼层 |阅读模式

    路线栈欢迎您!

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 一路上 于 2023-8-28 15:28 编辑

    前言

    什么是MQTT,物联网MQTT协议详解。在使用MQTT传输数据的时候,经常使用到JSON包,来进行数据的交互,本文讲一下该如何使用。

    1.png

    一、JSON和cJSON

    JSON:全称 JavaScript Object Notation,轻量级的数据格式。

    cJSON:是一个用c语言编写的JSON数据解析器,超级轻便,可以移植,单文件MIT源协议。

    cJSON的源码文件只有两个:
    1. cJSON.c
    2. cJSON.h
    复制代码

    下载地址可以在github下载,地址如下:

    1. https://github.com/DaveGamble/cJSON
    复制代码

    将这两个文件下载之后,添加到项目中,其它.C文件调用的时候,需要包含头文件cJSON.h即可,文件在MDK中的位置如下:

    2.png

    二、cJSON是如何表示JSON数据的

    cJSON是用一个结构体来表示一个JSON数据,定义在cJSON.h中,查看如下源码:

    3.png

    1. /* The cJSON structure: */
    2. typedef struct cJSON
    3. {
    4.     /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    5.     struct cJSON *next;
    6.     struct cJSON *prev;
    7.     /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
    8.     struct cJSON *child;

    9.     /* The type of the item, as above. */
    10.     int type;

    11.     /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
    12.     char *valuestring;
    13.     /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    14.     int valueint;
    15.     /* The item's number, if type==cJSON_Number */
    16.     double valuedouble;

    17.     /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
    18.     char *string;
    19. } cJSON;
    复制代码

    不是存贮整片的JSON数据,而是按照每条数据进行存储的。使用next指针和prev指针进行链表,存储整片的JSON数据。

    三、如何封装完整的JSON数据

    说了这么多,我们实际操作一下,找一块STM32F开发板,测试一下。

    4.png

    先将串口打通,方便电脑查看log日志。

    1. uart_init(115200);
    复制代码

    增加cjson.c文件,已经在main.c中

    1. #include "cJSON.h"
    复制代码

    5.png

    准备打包如下的JSON包
    1. {
    2.   "我的名字":  "老刘",
    3.   "公众号":  "数独机",
    4.   "年龄":  11,
    5.   "性别":  "男",
    6.   "电话":  186,
    7.   "地址":  "一般人不告诉",
    8.   "我是嵌套的cJSON":  {
    9.     "号码":  9527,
    10.     "传真":  5510,
    11.     "淘宝店":  "This熏"
    12.   },
    13.   "我是嵌套的数组":  [{
    14.       "我是奇数循环":  0
    15.     }, {
    16.       "我是偶数循环":  "12365"
    17.     }, {
    18.       "我是奇数循环":  2
    19.     }, {
    20.       "我是偶数循环":  "12365"
    21.     }, {
    22.       "我是奇数循环":  4
    23.     }]
    24. }
    复制代码

    代码部分,先将几个部分初始化指针


    1.     cJSON* main_root = NULL;
    2.     cJSON* main_m_root = NULL;
    3.     cJSON* main_l_root = NULL;
    4.     cJSON* obj=NULL;
    5.     char* response_str = NULL;
    复制代码

    创建链表

    1. main_root = cJSON_CreateObject();
    复制代码

    豪横的在链表中添加节点

    1. cJSON_AddStringToObject(main_root, "我的名字", "老刘");
    2.   cJSON_AddStringToObject(main_root, "公众号", "数独机");
    3.   cJSON_AddNumberToObject(main_root, "年龄", 11);
    4.   cJSON_AddStringToObject(main_root, "性别", "男");
    5.   cJSON_AddNumberToObject(main_root, "电话", 186);
    6.   cJSON_AddStringToObject(main_root, "地址", "一般人不告诉");

    7.   main_m_root = cJSON_CreateObject();
    8.   cJSON_AddNumberToObject(main_m_root, "号码", 9527);  
    9.   cJSON_AddNumberToObject(main_m_root, "传真", 5510);
    10.   cJSON_AddStringToObject(main_m_root, "淘宝店", "This熏");
    11.   cJSON_AddItemToObject(main_root, "我是嵌套的cJSON", main_m_root);

    12.   main_l_root=cJSON_CreateArray();
    13.   cJSON_AddItemToObject(main_root,"我是嵌套的数组",main_l_root);
    14.   for(i=0;i<5;i++)
    15.   {
    16.     obj=cJSON_CreateObject();
    17.     cJSON_AddItemToArray(main_l_root,obj);
    18.     if(i%2 == 0) cJSON_AddNumberToObject(obj, "我是奇数循环", i);
    19.     else cJSON_AddStringToObject(obj, "我是偶数循环", "12365");
    20.   }
    复制代码

    我们查看添加的是否正确,可以将链表通过串口打印出来。

    1. response_str = cJSON_Print(main_root);
    2. printf("%s\n",response_str);
    复制代码

    效果如下:

    6.png

    四、解包

    解包的函数只有一个:

    1. CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
    复制代码

    还是用例子进行讲解:

    将串口的数据完全接收到一个大的缓冲区里面,当然这个数据也可以来自wifi或者网络。      

    1. if(GET_STOP_flag)
    2. {
    3.     for(i=0;i<(cJSON_pack_StopP-cJSON_pack_FistP)+1;i++)
    4.     {
    5.       MessageTmp[i] =WIFI_RC_buf[cJSON_pack_FistP-1+i];
    6.     }
    7. }
    复制代码
    1. GET_STOP_flag      //为停止接收标志;
    2.     cJSON_pack_StopP   //停止指针位置
    3.     cJSON_pack_FistP   //开始指针位置
    4.     MessageTmp         //临时的数组
    复制代码

    只需要对临时的数组进行操作即可。开辟内存空间,将数组转换为字符串。

    1. MessageStrTmp = (char *)cJSON_malloc(sizeof(char) * (sizeof(MessageTmp) + 1));
    2. strncpy(MessageStrTmp, MessageTmp, sizeof(MessageTmp));
    复制代码

    使用解包函数

    1. //接收解包过程        
    2. Thisxun_root      =   cJSON_Parse(MessageStrTmp);
    3. Thisxun_root_type =   cJSON_GetObjectItem(hiss_root,"type")->valuestring;
    4. if(strcmp(Thisxun_root_type,TYPE_USER_INFO_SYNC)==0)
    5. {
    6.   Thisxun_insDetail =   cJSON_GetObjectItem(Thisxun_root,"insDetail");
    7.   userID            =   cJSON_GetObjectItem(Thisxun_insDetail,"userId")->valuestring;
    8.   password          =   cJSON_GetObjectItem(Thisxun_insDetail,"password")->valuestring;
    9. }
    复制代码

    五、结束

    每次封包和解包结束之后,都要及时释放内存:

    1. cJSON_Delete(Thisxun_root);
    2. cJSON_free(MessageStrTmp);
    复制代码

    对于单片机而言,需要修改Heap_Size。

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|路丝栈 ( 粤ICP备2021053448号 )

    GMT+8, 2024-12-22 20:12 , Processed in 0.046370 second(s), 21 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表