| 
 | 
 
路线栈欢迎您!
您需要 登录 才可以下载或查看,没有帐号?立即注册 
 
 
 
x
 
 本帖最后由 一路上 于 2023-8-28 15:28 编辑  
 
前言 
 
什么是MQTT,物联网MQTT协议详解。在使用MQTT传输数据的时候,经常使用到JSON包,来进行数据的交互,本文讲一下该如何使用。 
 
 
一、JSON和cJSON 
 
JSON:全称 JavaScript Object Notation,轻量级的数据格式。 
 
cJSON:是一个用c语言编写的JSON数据解析器,超级轻便,可以移植,单文件MIT源协议。 
 
cJSON的源码文件只有两个: 
 
下载地址可以在github下载,地址如下: 
 
- https://github.com/DaveGamble/cJSON
 
  复制代码 
将这两个文件下载之后,添加到项目中,其它.C文件调用的时候,需要包含头文件cJSON.h即可,文件在MDK中的位置如下: 
 
 
二、cJSON是如何表示JSON数据的 
 
cJSON是用一个结构体来表示一个JSON数据,定义在cJSON.h中,查看如下源码: 
 
 
- /* The cJSON structure: */
 
 - typedef struct cJSON
 
 - {
 
 -     /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
 
 -     struct cJSON *next;
 
 -     struct cJSON *prev;
 
 -     /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
 
 -     struct cJSON *child;
 
  
-     /* The type of the item, as above. */
 
 -     int type;
 
  
-     /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
 
 -     char *valuestring;
 
 -     /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
 
 -     int valueint;
 
 -     /* The item's number, if type==cJSON_Number */
 
 -     double valuedouble;
 
  
-     /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
 
 -     char *string;
 
 - } cJSON;
 
  复制代码 
不是存贮整片的JSON数据,而是按照每条数据进行存储的。使用next指针和prev指针进行链表,存储整片的JSON数据。 
 
三、如何封装完整的JSON数据 
 
说了这么多,我们实际操作一下,找一块STM32F开发板,测试一下。 
 
 
先将串口打通,方便电脑查看log日志。 
 
 
增加cjson.c文件,已经在main.c中 
 
 
 
准备打包如下的JSON包 
- {
 
 -   "我的名字":  "老刘",
 
 -   "公众号":  "数独机",
 
 -   "年龄":  11,
 
 -   "性别":  "男",
 
 -   "电话":  186,
 
 -   "地址":  "一般人不告诉",
 
 -   "我是嵌套的cJSON":  {
 
 -     "号码":  9527,
 
 -     "传真":  5510,
 
 -     "淘宝店":  "This熏"
 
 -   },
 
 -   "我是嵌套的数组":  [{
 
 -       "我是奇数循环":  0
 
 -     }, {
 
 -       "我是偶数循环":  "12365"
 
 -     }, {
 
 -       "我是奇数循环":  2
 
 -     }, {
 
 -       "我是偶数循环":  "12365"
 
 -     }, {
 
 -       "我是奇数循环":  4
 
 -     }]
 
 - }
 
  复制代码 
代码部分,先将几个部分初始化指针 
 
 
-     cJSON* main_root = NULL;
 
 -     cJSON* main_m_root = NULL;
 
 -     cJSON* main_l_root = NULL;
 
 -     cJSON* obj=NULL;
 
 -     char* response_str = NULL;
 
  复制代码 
创建链表 
 
- main_root = cJSON_CreateObject();
 
  复制代码 
豪横的在链表中添加节点 
 
- cJSON_AddStringToObject(main_root, "我的名字", "老刘");
 
 -   cJSON_AddStringToObject(main_root, "公众号", "数独机");
 
 -   cJSON_AddNumberToObject(main_root, "年龄", 11);
 
 -   cJSON_AddStringToObject(main_root, "性别", "男");
 
 -   cJSON_AddNumberToObject(main_root, "电话", 186);
 
 -   cJSON_AddStringToObject(main_root, "地址", "一般人不告诉");
 
  
-   main_m_root = cJSON_CreateObject();
 
 -   cJSON_AddNumberToObject(main_m_root, "号码", 9527);  
 
 -   cJSON_AddNumberToObject(main_m_root, "传真", 5510);
 
 -   cJSON_AddStringToObject(main_m_root, "淘宝店", "This熏");
 
 -   cJSON_AddItemToObject(main_root, "我是嵌套的cJSON", main_m_root);
 
 -  
 
 -   main_l_root=cJSON_CreateArray();
 
 -   cJSON_AddItemToObject(main_root,"我是嵌套的数组",main_l_root);
 
 -   for(i=0;i<5;i++)
 
 -   {
 
 -     obj=cJSON_CreateObject();
 
 -     cJSON_AddItemToArray(main_l_root,obj);
 
 -     if(i%2 == 0) cJSON_AddNumberToObject(obj, "我是奇数循环", i);
 
 -     else cJSON_AddStringToObject(obj, "我是偶数循环", "12365");
 
 -   }
 
  复制代码 
我们查看添加的是否正确,可以将链表通过串口打印出来。 
 
- response_str = cJSON_Print(main_root);
 
 - printf("%s\n",response_str);
 
  复制代码 
效果如下: 
 
 
四、解包 
 
解包的函数只有一个: 
 
- CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
 
  复制代码 
还是用例子进行讲解: 
 
将串口的数据完全接收到一个大的缓冲区里面,当然这个数据也可以来自wifi或者网络。       
 
- if(GET_STOP_flag)
 
 - {
 
 -     for(i=0;i<(cJSON_pack_StopP-cJSON_pack_FistP)+1;i++)
 
 -     {
 
 -       MessageTmp[i] =WIFI_RC_buf[cJSON_pack_FistP-1+i];
 
 -     }
 
 - }
 
  复制代码- GET_STOP_flag      //为停止接收标志;
 
 -     cJSON_pack_StopP   //停止指针位置
 
 -     cJSON_pack_FistP   //开始指针位置
 
 -     MessageTmp         //临时的数组
 
  复制代码 
只需要对临时的数组进行操作即可。开辟内存空间,将数组转换为字符串。 
 
- MessageStrTmp = (char *)cJSON_malloc(sizeof(char) * (sizeof(MessageTmp) + 1));
 
 - strncpy(MessageStrTmp, MessageTmp, sizeof(MessageTmp));
 
  复制代码 
使用解包函数 
 
- //接收解包过程        
 
 - Thisxun_root      =   cJSON_Parse(MessageStrTmp);
 
 - Thisxun_root_type =   cJSON_GetObjectItem(hiss_root,"type")->valuestring;
 
 - if(strcmp(Thisxun_root_type,TYPE_USER_INFO_SYNC)==0)
 
 - {
 
 -   Thisxun_insDetail =   cJSON_GetObjectItem(Thisxun_root,"insDetail");
 
 -   userID            =   cJSON_GetObjectItem(Thisxun_insDetail,"userId")->valuestring;
 
 -   password          =   cJSON_GetObjectItem(Thisxun_insDetail,"password")->valuestring;
 
 - }
 
  复制代码 
五、结束 
 
每次封包和解包结束之后,都要及时释放内存: 
 
- cJSON_Delete(Thisxun_root);
 
 - cJSON_free(MessageStrTmp);
 
  复制代码 
对于单片机而言,需要修改Heap_Size。 
 
 |   
 
 
 
 |