单片机之解析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的值

解析结果如下:

b85d4148eed347cbb68e3e49516ec63e.png

c7a987be80ef475ca0f1a159fcf3986a.png

注:以上代码均为原创 直接移植到单片机中即可直接使用。

  • 0
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值