草庐IT

Arduino学习笔记:JSON报文的解析与构建

哈哈浩丶 2023-04-09 原文

Arduino学习笔记:JSON报文的解析与构建

背景:由于最近博主在忙于完成毕业设计,毕业设计用到了MQTT协议去传递消息,在消息的传递过程中呢,采用的是JSON报文的格式,因此在学习的过程中写下此篇建议的Demo,用于给更多萌新或者小白指明道路。

首先我们需要下载Arduino进行JSON解析需要的库文件,博主将库文件直接放到百度网盘中了,需要的可以下载,下载完成后放在自己的libraries库中即可。

链接:https://pan.baidu.com/s/1YvsHvjFvVrmrXI-lW7geJA?pwd=1234
提取码:1234

Arduino解析JSON

本项目中定义的JSON报文格式如下,包含了不仅简单的JSON格式:“Key”:“Value”;还包含了JSON数组和嵌套格式。该报文中的字符串内容可在JSON可视化网站上进行格式化。
JSON可视化网址:JSON可视化网站

{
  "NameString": "ZhanSan",
  "InfoArray": [
    180,
    70
  ],
  "Birthday": {
    "Year": 2000,
    "Mother": 10,
    "Day": {
      "Hour": 12,
      "Min": 45,
      "Sec": 32.5
    }
  }
}

在该网站上能够对自己的JSON报文进行格式化并显示对应关系的视图,来检验层级关系是否正确。

在Arduino中使用的时候需要在该网址中进行删除空格并转义的操作得到如下报文。

我们将该段报文复制下来放在我们的Arduino代码中,得到如下字符串:

String JSON_Value ="{\"NameString\":\"ZhanSan\",\"InfoArray\":[180,70],\"Birthday\":{\"Year\":2000,\"Mother\":10,\"Day\":{\"Hour\":12,\"Min\":45,\"Sec\":32.5}}}";

从这段报文中我们能够看出,有字符串类型的数据,有数组类型的数据,有整型的数据还有浮点型的数据,嵌套层数也能够达到3级,其实只要是大于2级,解析的方式都是一样的,为了方便大家类比,在此我创建了3层。

下面给出源码:

#include <ArduinoJson.h>                              /* 引入JSON解析需要用的库文件 */

//StaticJsonDocument<1024> doc;                       /* 声明一个大小为1K的StaticJsonDocument对象doc,用于存储构建的JSON报文,以StaticJsonDocument方式声明的对象将存储在栈内存中,推荐size不大于1K时使用该方式 */
DynamicJsonDocument  JSON_Buffer(2*1024);             /* 申明一个大小为2K的DynamicJsonDocument对象JSON_Buffer,用于存储反序列化后的(即由字符串转换成JSON格式的)JSON报文,方式声明的对象将存储在堆内存中,推荐size大于1K时使用该方式 */
const char *Name = NULL;                              /* 用于接收解析后的JSON报文中的NameString的值 */
int InfoOne = 0;                                      /* 用于接收解析后的JSON报文中的InfoArray数组中下表为0的值 */
int InfoTwo = 0;                                      /* 用于接收解析后的JSON报文中的InfoArray数组中下表为1的值 */
int Year = 0;                                         /* 用于接收解析后的JSON报文中的Year的值 */
int Mother = 0;                                       /* 用于接收解析后的JSON报文中的Mother的值 */
int Hour = 0;                                         /* 用于接收解析后的JSON报文中的Hour的值 */
int Min = 0;                                          /* 用于接收解析后的JSON报文中的Min的值 */
float Sec = 0.0;                                      /* 用于接收解析后的JSON报文中的Sec的值 */
JsonObject root;                                      /* 定义一个JSON对象的根节点root 用于获取将JSON字符串经过显示类型转换为JSON对象的报文主体 */
void setup() {  
   Serial.begin(115200);   
   /* 首先定义一个JSON 字符串用于解析使用 */
   char JSON_Value[] ="{\"NameString\":\"ZhanSan\",\"InfoArray\":[180,70],\"Birthday\":{\"Year\":2000,\"Mother\":10,\"Day\":{\"Hour\":12,\"Min\":45,\"Sec\":32.5}}}";
   
   /* 反序列化转换前,先输出一遍JSON字符串,用于对比反序列化后的报文 */
    Serial.println("====================Before================================");
   Serial.println(JSON_Value);
   
   DeserializationError error = deserializeJson(JSON_Buffer, JSON_Value);   /* 将JSON_Value字符串反序列化为JSON报文的格式,存入JSON_Buffer中 */
   if(error)/* 若反序列化返回错误,则打印错误信息,然后中止程序 */
   {
      Serial.println("deserializeJson JSON_Buffer is ERROR!!!");
      return ;
   }
   else 
   {
      root = JSON_Buffer.as<JsonObject>();                              /*  获取将JSON字符串经过显示类型转换为JSON对象的报文主体 */

      Serial.println("====================After================================");
      serializeJsonPretty(JSON_Buffer, Serial);                         /* 反序列化成功则,打印格式化后的JSON报文 */
          
      Name = JSON_Buffer["NameString"];                                 /* 对于获取第一层级的值来说只要解析该值的键名就行 */
      InfoOne = JSON_Buffer["InfoArray"][0];                            /* 解析数组元素的时候,要先解析该数组的键名,再通过数组下标0解析第一个元素 */
      InfoTwo = JSON_Buffer["InfoArray"][1];                            /* 解析数组元素的时候,要先解析该数组的键名,再通过数组下标1解析第二个具体元素 */
      Year = JSON_Buffer["Birthday"]["Year"];                           /* 对于获取第二层级的值来说,只要先解析第一层级的值,再解析第二层级的值就行,表现在代码中就是二维数组 */
      Mother = JSON_Buffer["Birthday"]["Mother"];
      Hour = JSON_Buffer["Birthday"]["Day"]["Hour"];                    /* 对于获取第三层级的值来说,类比第二层级,只要先解析第一层级的值,再解析第二层级的值,最后解析第三层级的值就行,表现在代码中就是三维数组 */
      Sec = JSON_Buffer["Birthday"]["Day"]["Sec"];                      /* 对于浮点数来说步骤一样 */
      /* 所有元素解析完成后我们依次打印出来看看值对不对 */
      Serial.println("================Start===========================");
      Serial.println(Name);
      Serial.println(InfoOne);
      Serial.println(InfoTwo);
      Serial.println(Year);
      Serial.println(Hour);
      Serial.println(Sec);
      Serial.println("=================END==========================");
   }
}
 
void loop() { 
}

运行结果:

Arduino 构建JSON报文

上面我们完成了一个JSON字符串转换为JSON报文的格式再进行解析的过程,下面我们来构建一个完整的JSON报文。

源码部分:

#include <ArduinoJson.h>                              /* 引入JSON解析需要用的库文件 */
DynamicJsonDocument  JSON_Buffer(2*1024);             /* 申明一个大小为2K的DynamicJsonDocument对象JSON_Buffer,用于存储反序列化后的(即由字符串转换成JSON格式的)JSON报文,方式声明的对象将存储在堆内存中,推荐size大于1K时使用该方式 */
JsonArray InfoArray;                                  /* 创建一个JSON数组对象 */
JsonObject BirthedayObj;                              /* 创建一个JSON节点对象,第二层级的主节点 */
JsonObject DayObj;                                    /* 创建一个JSON节点对象,第三层级的主节点 */
void setup() {  
   Serial.begin(115200);   
   
   JSON_Buffer["NameString"] = "ZhangSan";                              /* 创建第一层级的一个键名为NameString,值为ZhangSan的属性 */
   InfoArray = JSON_Buffer.createNestedArray("InfoArray");              /* 创建一个数组节点 */
   InfoArray.add(180);                                                  /* 添加数组第一个元素为180*/
   InfoArray.add(70);                                                   /* 添加数组第二个元素为70*/
   JSON_Buffer["InfoArray"][0];                                         /* 创建完成后将其加入JSON报文中 */
   JSON_Buffer["InfoArray"][1];
   
   BirthedayObj = JSON_Buffer.createNestedObject("Birthday");           /* 创建第二层级的主节点,键名为Birthday */
   JSON_Buffer["Birthday"]["Year"] = 2000;                              /* 在第二层级中,创建一个键名为Year,值为2000的属性 */
   JSON_Buffer["Birthday"]["Mother"] = 10;                              /* 在第二层级中,创建一个键名为Mother,值为10的属性 */

   JSON_Buffer["Birthday"]["Day"]["Hour"] = 12;                         /* 在第三层级中,创建一个键名为Hour,值为12的属性,第三层级直接加入第二层级后面就行不需要再额外创建节点,只有和第二层级处于同一层级的需要额外建立节点 */
   JSON_Buffer["Birthday"]["Day"]["Min"] = 45;                          /* 在第三层级中,创建一个键名为Min,值为45的属性 */
   JSON_Buffer["Birthday"]["Day"]["Sec"] = 32.5;                        /* 在第三层级中,创建一个键名为Sec的浮点型数,值为32.5的属性 */

   
   serializeJsonPretty(JSON_Buffer, Serial); 
}
 
void loop() { 
}


运行结果:

有关Arduino学习笔记:JSON报文的解析与构建的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  4. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  5. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

    简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

  6. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  7. ruby - 在 Ruby 中构建长字符串的简洁方法 - 2

    在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  10. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

随机推荐