老听说json,在单片机软件开发中有啥用?
有了流式解析后,解析完部分数据后,可立即释放相关内存,维持低内存占用。这不最近一个"小项目"又把这玩意拿过来用用,整体还是挺舒适的,主要是json易读也比较容易把握,那顺便聊聊吧~在资源受限的单片机上解析JSON,开发者常面临内存不足、解析性能差等问题,所以在单片机上用cjson比较合适,:使用JSON定义通信指令,可读性不错,方便调试扯皮,扩展性不错增删都能够较好兼容。:将配置存储在JSON文件
正文
大家好,我是bug菌,又又见面了~
今天跟大家聊聊json这玩意,json说实在的bug菌也是后面联网的项目越来越多才用上了这玩意,玩物联网和智能硬件的朋友应该用得比较多。这不最近一个"小项目"又把这玩意拿过来用用,整体还是挺舒适的,主要是json易读也比较容易把握,那顺便聊聊吧~
1
cjson
在资源受限的单片机上解析JSON,开发者常面临内存不足、解析性能差等问题,所以在单片机上用cjson比较合适,一款专为嵌入式设计的开源JSON解析库,设计简洁高效,用得挺多的。
下面简单介绍下cjson:
cJSON是由Dave Gamble开发的超轻量级C语言JSON解析库,代码仅一个.h和一个.c文件,完全开源,专为嵌入式环境优化。
GitHub地址:
https://github.com/DaveGamble/cJSON
核心特点
• 极简内存占用:解析时仅需几KB内存,适合RAM稀缺的单片机(如STM32F103、ESP8266)。
• 纯C实现:无第三方依赖,跨平台支持(Keil、IAR、GCC均可编译),就两个文件,移植起来太简单了。
• 易用性:API简洁,10分钟即可上手。
• 灵活性:支持动态创建、修改、序列化和反序列化JSON数据。
下面是简单的cjson使用示例 :
1. 示例代码:创建JSON并输出字符串
#include"cJSON.h"
voidcreate_json(void){
// 1. 创建根对象
cJSON *root = cJSON_CreateObject();
// 2. 添加键值对
cJSON_AddStringToObject(root, "device", "ESP32");
cJSON_AddNumberToObject(root, "temperature", 25.6);
// 3. 添加嵌套对象
cJSON *location = cJSON_CreateObject();
cJSON_AddNumberToObject(location, "lat", 35.6895);
cJSON_AddNumberToObject(location, "lon", 139.6917);
cJSON_AddItemToObject(root, "location", location);
// 4. 生成JSON字符串
char *json_str = cJSON_Print(root);
printf("JSON: %s\n", json_str);
// 5. 释放内存(重要!)
free(json_str);
cJSON_Delete(root);
}
输出结果:
{
"device": "ESP32",
"temperature": 25.6,
"location": {
"lat": 35.6895,
"lon": 139.6917
}
}
2. 解析JSON数据
voidparse_json(constchar *json_str){
cJSON *root = cJSON_Parse(json_str);
if (root == NULL) {
printf("JSON解析失败!\n");
return;
}
// 提取字段
cJSON *device = cJSON_GetObjectItem(root, "device");
cJSON *temp = cJSON_GetObjectItem(root, "temperature");
cJSON *location = cJSON_GetObjectItem(root, "location");
printf("设备名: %s, 温度: %.1f\n", device->valuestring, temp->valuedouble);
printf("经纬度: (%.4f, %.4f)\n",
cJSON_GetObjectItem(location, "lat")->valuedouble,
cJSON_GetObjectItem(location, "lon")->valuedouble);
cJSON_Delete(root);
}
2
cjson在单片机中的主要应用
1、动态配置管理
痛点:传统配置方式需将参数硬编码在代码中,修改配置需重新编译固件,无法动态更新。
解决方案:将配置存储在JSON文件中,通过cJSON解析,增删都很方便,有较好的兼容性,支持OTA动态更新,当然还是会占一些内存。
示例代码:解析Wi-Fi配置
// config.json
{
"wifi": {
"ssid": "MyIoT",
"password": "123456"
},
"sampling_interval": 5000
}
voidload_config(void){
// 从Flash或SD卡读取JSON文件
char *json_str = read_file("config.json");
cJSON *root = cJSON_Parse(json_str);
cJSON *wifi = cJSON_GetObjectItem(root, "wifi");
char *ssid = cJSON_GetObjectItem(wifi, "ssid")->valuestring;
char *password = cJSON_GetObjectItem(wifi, "password")->valuestring;
int interval = cJSON_GetObjectItem(root, "sampling_interval")->valueint;
printf("Wi-Fi: %s/%s, 采样间隔: %dms\n", ssid, password, interval);
cJSON_Delete(root);
free(json_str);
}
2、设备间通信协议
痛点:自定义二进制协议调试困难,扩展性差。
解决方案:使用JSON定义通信指令,可读性不错,方便调试扯皮,扩展性不错增删都能够较好兼容。
下面的例子是一个非常有意思的玩法,作为参数动态扩展。
示例代码:解析控制指令
// 收到指令:{"cmd": "set_led", "args": {"id": 1, "brightness": 80}}
voidhandle_command(const char *json_str){
cJSON *root = cJSON_Parse(json_str);
char *cmd = cJSON_GetObjectItem(root, "cmd")->valuestring;
if (strcmp(cmd, "set_led") == 0) {
cJSON *args = cJSON_GetObjectItem(root, "args");
int id = cJSON_GetObjectItem(args, "id")->valueint;
int brightness = cJSON_GetObjectItem(args, "brightness")->valueint;
led_set(id, brightness); // 实际控制函数
}
cJSON_Delete(root);
}
3、本地数据存储与日志记录
痛点:传感器数据若以二进制格式存储,导出后需专用工具解析。
解决方案:将数据序列化为JSON字符串,直接存储为文本文件。
示例代码:记录温度数据
voidlog_sensor_data(float temp, float humidity){
cJSON *root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "temp", temp);
cJSON_AddNumberToObject(root, "humidity", humidity);
cJSON_AddStringToObject(root, "timestamp", "2023-08-15T14:30:00Z");
char *json_str = cJSON_PrintUnformatted(root); // 紧凑模式节省空间
write_to_sd_card("log.json", json_str);
free(json_str);
cJSON_Delete(root);
}
3
使用过程的注意事项
1、要注意调用cJSON_Delete()和free()及时的释放资源,防止内存泄漏,不然跑着跑着就奔了~。
2、想省一些内存和带宽,json相关的命名最好不要太长。
3、cjson支持
cJSON_ParseWithOpts流式解析,这在解析大型JSON时比较有用。每接收到一部分数据即可立即解析,无需等待全部数据到达,算是一种低延时的增量处理。
而且对于单片机的RAM资源有限,一次性加载大型JSON字符串可能导致内存溢出。有了流式解析后,解析完部分数据后,可立即释放相关内存,维持低内存占用。
最后
好了,今天就跟大家分享这么多了,如果你觉得有所收获,一定记得点个赞~
唯一、永久、免费分享嵌入式技术知识平台~
推荐专辑 点击蓝色字体即可跳转
☞ MCU进阶专辑
☞ “bug说”专辑
☞ 专辑|手撕C语言
☞ 专辑|经验分享
更多推荐





所有评论(0)