[嵌入式C语言专精]利用cJSON来高效地实现多机通信/物联网实例

接收与处理JSON数据串的代码模块

在前些天的示例中, 我们已经实现了利用串口中断来高效地接收JSON数据包, 并将其使用消息队列传递给解析线程

在这次的项目中, 我们将创建一个高效的Json指令处理模块

附注:

使用ESP32来实现BLE+WiFi的物联网通信, 同样以JSON数据包为示例
https://github.com/NinoC137/WiFi_BLE

接收并处理JSON数据包字符串

在cJSON中, JSON字符串的参数为**(const char* value)**

所以我们应当传入一个 const char* 或 char* 的字符串

开始对字符串进行解析 cmd_startParse

void cmd_startParse(char* JsonString){
    cJSON *root = cJSON_Parse(JsonString);
    if(root == NULL){
        uart3_printf("Error before: [%s]\n", cJSON_GetErrorPtr());
    }
    cJSON *cmd = cJSON_GetObjectItem(root, "cmd");
    switch (cmd->valueint) {
        case 1:
            cmd_setAngularDeviation(root);
            break;
        case 2:
            cmd_setServoAngle(root);
            break;
        case 3:
            cmd_getMotorSpeed(root);
            break;
        case 4:
            cmd_getMotorAngle(root);
            break;
        case 5:
            cmd_getMotorCurrent(root);
            break;
        case 6:
            cmd_getSystemMode(root);
            break;
        case 7:
            cmd_setHeartBeat(root);
            break;
        default:
            break;
    }
    cJSON_Delete(root);
}

在这里, 我根据自己的需要设定了7种不同的状态处理.

为了区分不同的指令, 我的数据包格式中包含了"cmd"这一int变量, 示例如下:

cmd_setAngularDeviation:

{
“cmd”:1,
“Deviation”: 5
}

进入JSON数据包的解析, 并进行后续处理

解析过程如下:

  1. 创建一个cJSON对象, 将其作为本次解析的根节点

    	cJSON *root = cJSON_Parse(JsonString);
    	//若是数据包不符合JSON格式, 则root不会被创建, 进入以下报错
        if(root == NULL){
            uart3_printf("Error before: [%s]\n", cJSON_GetErrorPtr());
        }
    
  2. 根据cmd值的不同, 进入不同的解析函数之中

    cJSON *cmd = cJSON_GetObjectItem(root, "cmd");
        switch (cmd->valueint) {
            case 1:
                cmd_setAngularDeviation(root);
                break;
            case 2:
                cmd_setServoAngle(root);
                break;
            case 3:
                cmd_getMotorSpeed(root);
                break;
            case 4:
                cmd_getMotorAngle(root);
                break;
            case 5:
                cmd_getMotorCurrent(root);
                break;
            case 6:
                cmd_getSystemMode(root);
                break;
            case 7:
                cmd_setHeartBeat(root);
                break;
            default:
                break;
        }
    cJSON_Delete(root);
    
  3. 在解析函数中对数据包的内容, 以变量名为目标进行针对性的解析

    void cmd_setServoAngle(cJSON* root){
        cJSON *cmd_AngleLeft = cJSON_GetObjectItem(root, "ServoAngle_Left");
        cJSON *cmd_AngleRight = cJSON_GetObjectItem(root, "ServoAngle_Right");
    
        uart3_printf("get left Angle: %d\tRight Angle: %d\r\n", cmd_AngleLeft->valueint, cmd_AngleRight->valueint);
    
    //    cJSON *response_root = cJSON_CreateObject();
    //    cJSON_AddItemToObject(response_root, "res", cJSON_CreateNumber(0));
    //    cJSON_AddItemToObject(response_root, "cmd", cJSON_CreateNumber(2));
    
    //    char* responseText = cJSON_Print(response_root);
    
    //    uart3_printf("%s", responseText);
    
    //    cJSON_Delete(response_root);
    //    free(responseText);
    }
    
  4. 创建一个JSON数据包用来回复消息

    void cmd_setServoAngle(cJSON* root){
    //    cJSON *cmd_AngleLeft = cJSON_GetObjectItem(root, "ServoAngle_Left");
    //    cJSON *cmd_AngleRight = cJSON_GetObjectItem(root, "ServoAngle_Right");
    
    //    uart3_printf("get left Angle: %d\tRight Angle: %d\r\n", cmd_AngleLeft->valueint, cmd_AngleRight->valueint);
    
        cJSON *response_root = cJSON_CreateObject();
        cJSON_AddItemToObject(response_root, "res", cJSON_CreateNumber(0));
        cJSON_AddItemToObject(response_root, "cmd", cJSON_CreateNumber(2));
    
        char* responseText = cJSON_Print(response_root);	//生成完整的JSON数据串
    
        uart3_printf("%s", responseText);
    
    //    cJSON_Delete(response_root);
    //    free(responseText);
    }
    
  5. 保护内存安全, 释放掉先前创建的无用的指针变量

    void cmd_setServoAngle(cJSON* root){
    //    cJSON *cmd_AngleLeft = cJSON_GetObjectItem(root, "ServoAngle_Left");
    //    cJSON *cmd_AngleRight = cJSON_GetObjectItem(root, "ServoAngle_Right");
    //
    //    uart3_printf("get left Angle: %d\tRight Angle: %d\r\n", cmd_AngleLeft->valueint, cmd_AngleRight->valueint);
    //
    //    cJSON *response_root = cJSON_CreateObject();
    //    cJSON_AddItemToObject(response_root, "res", cJSON_CreateNumber(0));
    //    cJSON_AddItemToObject(response_root, "cmd", cJSON_CreateNumber(2));
    //
    //    char* responseText = cJSON_Print(response_root);
    //
    //    uart3_printf("%s", responseText);
    
        cJSON_Delete(response_root);
        free(responseText);
    }
    
  • 30
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
假设我们有如下的JSON字符串: ```json { "name": "John", "age": 30, "city": "New York", "hobbies": ["reading", "swimming", "traveling"], "family": { "spouse": "Jane", "children": ["Alex", "Sophie"] } } ``` 我们可以使用cjson库来解析这个JSON字符串,并且使用for循环遍历其节点并获取子值。以下是一个示例程序: ```c #include <stdio.h> #include <stdlib.h> #include "cJSON.h" void print_json(cJSON *json) { if (json == NULL) { return; } switch(json->type) { case cJSON_NULL: printf("null\n"); break; case cJSON_False: printf("false\n"); break; case cJSON_True: printf("true\n"); break; case cJSON_Number: printf("%lf\n", json->valuedouble); break; case cJSON_String: printf("%s\n", json->valuestring); break; case cJSON_Array: for (int i = 0; i < cJSON_GetArraySize(json); i++) { cJSON *item = cJSON_GetArrayItem(json, i); print_json(item); } break; case cJSON_Object: cJSON *child = json->child; while (child != NULL) { printf("%s: ", child->string); print_json(child); child = child->next; } break; default: break; } } int main() { char *json_str = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\",\"hobbies\":[\"reading\",\"swimming\",\"traveling\"],\"family\":{\"spouse\":\"Jane\",\"children\":[\"Alex\",\"Sophie\"]}}"; cJSON *json = cJSON_Parse(json_str); if (json == NULL) { printf("Error before: [%s]\n", cJSON_GetErrorPtr()); return 1; } print_json(json); cJSON_Delete(json); return 0; } ``` 在此示例程序中,我们定义了一个`print_json`函数,它可以递归地遍历JSON节点,并打印出每个节点的值。在`print_json`函数中,我们使用了一个switch语句来根据节点的类型来处理不同的情况。当节点是一个数组或者对象时,我们使用for循环或者while循环来遍历它们的子节点。在主函数中,我们首先将JSON字符串解析为一个cJSON对象,然后调用`print_json`函数来遍历该对象,并打印出每个节点的值。最后,我们使用`cJSON_Delete`函数来释放cJSON对象所占用的内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值