单片机解析JSON数据的代码实现
前言
我们都知道在有限的ARM中实现JSON解析是很复杂的,因为MCU空间很小。基于此本文提供了一种低开销的JSON的解析方法及代码。JSON文本协议通常也用于物联网数据传输等。
JSON简介
再粘贴代码前先我们先简单熟悉下什么是JSON。
JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
JSON文本的组成
JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面值。
JSON是一个序列化的对象或数组。
1. 六个构造字符:
begin-array = ws %x5B ws ; [ 左方括号
begin-object = ws %x7B ws ; { 左大括号
end-array = ws %x5D ws ; ] 右方括号
end-object = ws %x7D ws ; } 右大括号
name-separator = ws %x3A ws ; : 冒号
value-separator = ws %x2C ws ; , 逗号
2. 在这六个构造字符的前或后允许存在无意义的空白符(ws):
ws = *(%x20 /; 空间
%x09 /; 水平标签
%x0A /; 换行或换行
%x0D); 回程
3.JSON的值:
JSON的构成: ws 值 ws [1]
值可以是对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个。值中的字面值中的英文必须使用小写。
对象由花括号括起来的逗号分割的成员构成,成员是字符串键和上文所述的值由逗号分割的键值对组成,如:
{"name": "John Doe", "age": 18, "address": {"country" : "china", "zip-code": "10000"}}
该段信息来着于百科,详细地址:JSON_百度百科
JSON在单片机中的实现
多的不说直接上干货
编程语言:C语言
示例代码:如下
/**
作者:戚茂华
功能描述:比较两个字符串是否相等
**/
bit CompareString_V3(char CMD_tail[],char sourceString[])
{
unsigned char len = strlen(sourceString) ;
unsigned char CharNum;
for(CharNum=0;CharNum<len;CharNum++)
{
if(!(sourceString[CharNum]==CMD_tail[CharNum]))
{
return 0;
}
}
return 1;
}
//截取指定位置字符串字符串 默认0开始
char *getSubString_V2(unsigned char start,unsigned char end,char str[]){
int surplusLength = end ;
char res[]="" ;
char out[]="" ;
char i = 0;
unsigned char CharNum;
// 读取0x03 如果有则跳过
for(CharNum=start;CharNum<surplusLength;CharNum++){
res[i] = str[CharNum];
i++;
}
strcpy(str, ""); // 内容清空
return res;
}
/**
作者:戚茂华
功能描述:截取json value字符串 如果value是字符串 则去掉首个" 和末尾"
**/
char *parseString(char str[]){
unsigned char CharNum;
int len = strlen(str);
char output[] = "";
if (str[0]=='"'&&str[len-1]=='"'){
str[0] = ' ';
str[len-1] = ' ';
for (CharNum=0;CharNum<len-2;CharNum++){
output[CharNum] = str[CharNum+1];
}
strcpy(str, ""); // 内容清空
return output;
}
return str;
}
/**
作者:戚茂华
功能描述:获取json特定key的value
**/
char *GetJSONObjectItem(char CMD_head[])
{
//char resStr[]="";
char resStr[]="";
unsigned char oneBit;
unsigned char twoBit;
unsigned char CharNum;
unsigned char result = 0; // 初始不存在
int jsonLength = strlen(buf_string); // json长度
int keyLength=strlen(CMD_head); // keyItem长度
for(CharNum=0;CharNum<jsonLength;CharNum++) // 校验key是否存在
{
// 读取首个 "字符串
if (buf_string[CharNum]=='"'){
if (buf_string[CharNum+1]!=':'){
// 开始循环比较
unsigned char index;
int compareKeyLength = 0;
// 比较json字符串 KEY是否存在
for (index=0;index<keyLength;index++){
if ((CharNum+1+index)<=jsonLength){
if (CMD_head[index]==buf_string[CharNum+1+index]){
compareKeyLength+=1;
}
}
}
// 开始从key读取value
if ((compareKeyLength==keyLength)&&(buf_string[CharNum+1+keyLength]=='"')&&(buf_string[CharNum+2+keyLength]==':')){
// 开始从 CharNum+2+keyLength 位 继续往后读 value 直到读取到 ", 或则}或则} 则结束读取
// 直到读取到 ", 或则, 或则"}或则} 则结束读取
// 开始位置
int startBit = CharNum+3+keyLength; // 从key的最后一位标识位读取
int surplusBit = jsonLength – startBit; // 剩余字符串
if (surplusBit>2){
unsigned char valueNum;
unsigned char endFlag = 0; // 输出字符串长度
unsigned char start = 0;
for (valueNum=0;valueNum<surplusBit;valueNum++){
endFlag=valueNum;
oneBit = buf_string[startBit+valueNum];
twoBit = buf_string[startBit+valueNum+1];
if ((oneBit=='"')&&(twoBit=='}')){
resStr[valueNum]=buf_string[startBit+valueNum];
resStr[valueNum+1]=buf_string[startBit+valueNum+1];
endFlag=valueNum+1;
break;
}
if ((oneBit=='"')&&(twoBit==',')){
endFlag=valueNum+1;
break;
}
if ((oneBit==',')){
endFlag=valueNum+1;
break;
}
if (oneBit=='}'){
resStr[valueNum]=buf_string[startBit+valueNum];
endFlag=valueNum;
break;
}
resStr[valueNum]=buf_string[startBit+valueNum];
}
if (resStr[0]=='"'){
start = 1;
}
strcpy(buf_string, ""); // 内容清空
return getSubString_V2(0,endFlag,resStr);
}
// if (buf_string[startBit])
return resStr;
//result = 1;
break;
}
return resStr;
}
}
}
return resStr; //检测是否存在key
}
重点说明下其中 buf_string表示接收到的串口数据
定义如下:char buf_string[16]; 这个大小建议开发者自由定义 ,或则把代码里面的buf_string改为入参即可全局通用。
经测试:该原生代码可用于小内存的STC89系列单片机以及STM32等单片机。
测试示例
调用示例:
char *receiveData = parseString(GetJSONObjectItem("led"));
代码解释:获取键名为led的值
解析结果如下:
注:以上代码均为原创 直接移植到单片机中即可直接使用。
作者:ByteIOT