JSON数据格式解析库(cJSON、Jansson)的使用在STM32上移植和使用

json | json-c使用入门 这篇讲的也不错,抽空看下(网络传输json数据)
https://www.bilibili.com/video/av669454528?p=3&spm_id_from=pageDriver

目录

  • 轻量级C语言JSON解析库
    • 1.JSON与cJSON
      • JSON —— 轻量级的数据格式
      • JSON语法规则
      • cJSON
    • 2.cJSON数据结构和设计思想
    • 3.JSON数据封装
      • 封装方法
      • 输出JSON数据
      • 封装数据和打印数据示例
    • 4.cJSON数据解析
      • 解析方法
      • 解析示例
      • 注意事项
    • 5.cJSON使用过程中的内存问题
      • 内存及时释放
      • 内存钩子
  • cJSON在STM32移植和使用
    • 概要
    • 硬件准备
    • 软件准备
    • 实际操作步骤
    • 总结
  • 快速生成JSON数据(sprintf)和解析JSON数据(strstr)技巧
    • 1. 生成JSON数据
    • 2. 解析JSON数据
  • Keil环境下Jansson解析库的使用

轻量级C语言JSON解析库

参考博文:cJSON使用详细教程 | 一个轻量级C语言JSON解析器
作者:Mculover666
地址:https://mculover666.blog.csdn.net/article/details/103796256?spm=1001.2014.3001.5502

1.JSON与cJSON

JSON —— 轻量级的数据格式

JSON 全称 JavaScript Object Notation,即 JS对象简谱,是一种轻量级的数据格式。

它采用完全独立于编程语言的文本格式来存储和表示数据,语法简洁、层次结构清晰,易于人阅读和编写,同时也易于机器解析和生成,有效的提升了网络传输效率。

JSON语法规则

JSON对象是一个无序的"名称/值"键值对的集合:

  • 以"{“开始,以”}"结束,允许嵌套使用,即对象里面嵌套对象;
  • 每个名称和值成对出现(名称又叫做键,所以又叫键值对),名称和值之间使用":"分隔;
  • 键值对之间用","分隔
  • 在这些字符前后允许存在无意义的空白符;

对于键值,可以有如下值:

  • 一个新的json对象
  • 数组:使用"[“和”]"表示
  • 数字:直接表示,可以是整数,也可以是浮点数
  • 字符串:使用引号"表示
  • 字面值:false、null、true中的一个(必须是小写)

注意:
在这里插入图片描述
详细的JSON数据格式参照:太极创客JSON基础

示例如下:

{"name": "mculover666","age": 22,"weight": 55.5,"address":{		//值是一个对象,即对象里面嵌套对象"country": "China","zip-code": 111111},"skill": ["c", "Java", "Python"],//数组"student": false				 //布尔
}

cJSON

cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。

cJSON项目托管在Github上,仓库地址如下:

https://github.com/DaveGamble/cJSON

使用Git命令将其拉取到本地:

git clone https://github.com/DaveGamble/cJSON.git

从Github拉取cJSON源码后,文件非常多,但是其中cJSON的源码文件只有两个:

  • cJSON.h
  • cJSON.c

使用的时候,只需要将这两个文件复制到工程目录,然后包含头文件cJSON.h即可,如下:

#include "cJSON.h"

2.cJSON数据结构和设计思想

cJSON的设计思想从其数据结构上就能反映出来。

cJSON使用cJSON结构体来表示一个JSON数据,定义在cJSON.h中,源码如下:

/* The cJSON structure: */
typedef struct cJSON
{/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */struct cJSON *next;struct cJSON *prev;/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */struct cJSON *child;/* The type of the item, as above. */int type;/* The item's string, if type==cJSON_String  and type == cJSON_Raw */char *valuestring;/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */int valueint;/* The item's number, if type==cJSON_Number */double valuedouble;/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */char *string;
} cJSON;

cJSON的设计很巧妙。

首先,它不是将一整段JSON数据抽象出来,而是将其中的一条JSON数据抽象出来,也就是一个键值对,用上面的结构体 strcut cJSON 来表示,其中用来存放值的成员列表如下:

  • String:用于表示该键值对的名称
  • type:用于表示该键值对中值的类型
  • valuestring:如果键值类型(type)是字符串,则将该指针指向键值;
  • valueint:如果键值类型(type)是整数,则将该指针指向键值;
  • valuedouble:如果键值类型(type)是浮点数,则将该指针指向键值;

其次,一段完整的JSON数据中由很多键值对组成,并且涉及到键值对的查找、删除、添加,所以使用链表来存储整段JSON数据,如上面的代码所示:

  • next指针:指向下一个键值对
  • prev指针:指向上一个键值对

最后,因为JSON数据支持嵌套,所以一个键值对的值会是一个新的JSON数据对象(一条新的链表),也有可能是一个数组,方便起见,在cJSON中,数组也表示为一个数组对象,用链表存储,所以:

在键值对结构体中,当该键值对的值是一个嵌套的JSON数据或者一个数组时,由child指针指向该条新链表。

3.JSON数据封装

封装方法

封装JSON数据的过程,其实就是创建链表和向链表中添加节点的过程。

首先来讲述一下链表中的一些术语:

  • 头指针:指向链表头结点的指针;
  • 头结点:不存放有效数据,方便链表操作;
  • 首节点:第一个存放有效数据的节点;
  • 尾节点:最后一个存放有效数据的节点;

明白了这几个概念之后,我们开始讲述创建一段完整的JSON数据,即如何创建一条完整的链表。

① 创建头指针:

 cJSON* cjson_test = NULL;

② 创建头结点,并将头指针指向头结点:

cjson_test = cJSON_CreateObject();

③ 尽情的向链表中添加节点:

cJSON_AddNullToObject(cJSON * const object, const char * const name);cJSON_AddTrueToObject(cJSON * const object, const char * const name);cJSON_AddFalseToObject(cJSON * const object, const char * const name);cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);cJSON_AddObjectToObject(cJSON * const object, const char * const name);cJSON_AddArrayToObject(cJSON * const object, const char * const name);

输出JSON数据

上面讲述,一段完整的JSON数据就是一条长长的链表,那么,如何打印出这段JSON数据呢?

cJSON提供了一个API,可以将整条链表中存放的JSON信息输出到一个字符串中:

(char *) cJSON_Print(const cJSON *item);

使用的时候,只需要接收该函数返回的指针地址即可。

封装数据和打印数据示例

单纯的讲述方法还不够,下面用一个例子来说明,封装出开头给出的那段JSON数据:

#include <stdio.h>
#include "cJSON.h"int main(void)
{cJSON* cjson_test = NULL;cJSON* cjson_address = NULL;cJSON* cjson_skill = NULL;char* str = NULL;/* 创建一个JSON数据对象(链表头结点) */cjson_test = cJSON_CreateObject();/* 添加一条字符串类型的JSON数据(添加一个链表节点) */cJSON_AddStringToObject(cjson_test, "name", "mculover666");/* 添加一条整数类型的JSON数据(添加一个链表节点) */cJSON_AddNumberToObject(cjson_test, "age", 22);/* 添加一条浮点类型的JSON数据(添加一个链表节点) */cJSON_AddNumberToObject(cjson_test, "weight", 55.5);/* 添加一个嵌套的JSON数据(添加一个链表节点) */cjson_address = cJSON_CreateObject();cJSON_AddStringToObject(cjson_address, "country", "China");cJSON_AddNumberToObject(cjson_address, "zip-code", 111111);cJSON_AddItemToObject(cjson_test, "address", cjson_address);/* 添加一个数组类型的JSON数据(添加一个链表节点) */cjson_skill = cJSON_CreateArray();cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "C" ));cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Java" ));cJSON_AddItemToArray(cjson_skill, cJSON_CreateString( "Python" ));cJSON_AddItemToObject(cjson_test, "skill", cjson_skill);/* 添加一个值为 False 的布尔类型的JSON数据(添加一个链表节点) */cJSON_AddFalseToObject(cjson_test, "student");/* 打印JSON对象(整条链表)的所有数据 */str = cJSON_Print(cjson_test);printf("%s\n", str);return 0;
}

编译运行:

gcc cJSON.c example1.c -o example1

实验结果如图:
在这里插入图片描述

该JSON数据链表的关系如图:
在这里插入图片描述

4.cJSON数据解析

解析方法

解析JSON数据的过程,其实就是剥离一个一个链表节点(键值对)的过程。

解析方法如下:

① 创建链表头指针:

cJSON* cjson_test = NULL;

② 解析整段JSON数据,并将链表头结点地址返回,赋值给头指针:
解析整段数据使用的API只有一个:

(cJSON *) cJSON_Parse(const char *value);

③ 根据键值对的名称从链表中取出对应的值,返回该键值对(链表节点)的地址

(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);

④ 如果JSON数据的值是数组,使用下面的两个API提取数据:

(int) cJSON_GetArraySize(const cJSON *array);
(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);

解析示例

下面用一个例子来说明如何解析出开头给出的那段JSON数据:

#include <stdio.h>
#include "cJSON.h"char *message = //json格式数据,需要显示引号,都需要用\转义
"{                              \\"name\":\"mculover666\",   \\"age\": 22,                \\"weight\": 55.5,           \\"address\":                \{                       \\"country\": \"China\",\\"zip-code\": 111111\},                      \\"skill\": [\"c\", \"Java\", \"Python\"],\\"student\": false          \
}";int main(void)
{cJSON* cjson_test = NULL;cJSON* cjson_name = NULL;cJSON* cjson_age = NULL;cJSON* cjson_weight = NULL;cJSON* cjson_address = NULL;cJSON* cjson_address_country = NULL;cJSON* cjson_address_zipcode = NULL;cJSON* cjson_skill = NULL;cJSON* cjson_student = NULL;int    skill_array_size = 0, i = 0;cJSON* cjson_skill_item = NULL;/* 解析整段JSO数据 */cjson_test = cJSON_Parse(message);if(cjson_test == NULL){printf("parse fail.\n");return -1;}/* 依次根据名称提取JSON数据(键值对) */cjson_name = cJSON_GetObjectItem(cjson_test, "name");cjson_age = cJSON_GetObjectItem(cjson_test, "age");cjson_weight = cJSON_GetObjectItem(cjson_test, "weight");printf("name: %s\n", cjson_name->valuestring);printf("age:%d\n", cjson_age->valueint);printf("weight:%.1f\n", cjson_weight->valuedouble);/* 解析嵌套json数据 */cjson_address = cJSON_GetObjectItem(cjson_test, "address");cjson_address_country = cJSON_GetObjectItem(cjson_address, "country");cjson_address_zipcode = cJSON_GetObjectItem(cjson_address, "zip-code");printf("address-country:%s\naddress-zipcode:%d\n", cjson_address_country->valuestring, cjson_address_zipcode->valueint);/* 解析数组 */cjson_skill = cJSON_GetObjectItem(cjson_test, "skill");skill_array_size = cJSON_GetArraySize(cjson_skill);printf("skill:[");for(i = 0; i < skill_array_size; i++){cjson_skill_item = cJSON_GetArrayItem(cjson_skill, i);printf("%s,", cjson_skill_item->valuestring);}printf("\b]\n");/* 解析布尔型数据 */cjson_student = cJSON_GetObjectItem(cjson_test, "student");if(cjson_student->valueint == 0){printf("student: false\n");}else{printf("student:error\n");}return 0;
}

编译:

gcc cJSON.c example2.c -o example2

运行结果如图:
在这里插入图片描述

注意事项

在本示例中,因为我提前知道数据的类型,比如字符型或者浮点型,所以我直接使用指针指向对应的数据域提取,在实际使用时,如果提前不确定数据类型,应该先判断type的值,确定数据类型,再从对应的数据域中提取数据。

5.cJSON使用过程中的内存问题

内存及时释放

cJSON的所有操作都是基于链表的,所以cJSON在使用过程中大量的使用malloc从堆中分配动态内存的,所以在使用完之后,应当及时调用下面的函数,清空cJSON指针所指向的内存,该函数也可用于删除某一条数据:

(void) cJSON_Delete(cJSON *item);

注意:该函数删除一条JSON数据时,如果有嵌套,会连带删除。

内存钩子

cJSON在支持自定义malloc函数和free函数,方法如下:

① 使用cJSON_Hooks来连接自定义malloc函数和free函数:

typedef struct cJSON_Hooks
{/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */void *(CJSON_CDECL *malloc_fn)(size_t sz);void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;

② 初始化钩子cJSON_Hooks

(void) cJSON_InitHooks(cJSON_Hooks* hooks);

cJSON在STM32移植和使用

参照:物联网项目设计(四)cJSON 在 STM32 移植和使用
作者:张竞豪
地址:https://blog.csdn.net/weixin_42487906/article/details/104542529

概要

JSON格式是互联网通讯过程中常用的格式。包括MQTT协议也不例外,MQTT协议的数据收发都是使用JSON格式完成的。在使用MQTT协议进行通讯之前,我们需要掌握在c语言环境下JSON格式数据的操作。对JSON数据的操作我们使用了cJSON开源库。在使用的过程中,也遇到了不少问题(见后文),为此我查阅了很多资料,最后找到比较简单的方法解决了这个问题。

本篇介绍如何生成cJSON格式数据,并转化成字符串,通过串口发送到上位机。

硬件准备

使用STM32主控的开发板或相关硬件设备

软件准备

上位机串口助手

实际操作步骤

1.使用CubeMx建立一个简单的工程,只需要配置串口,但一定要注意,配置堆栈大小的时候一定要配置的大一点,因为cJSON分配内存的时候会占用不少内存空间,内存分配是单片机移植cJSON遇到的最常见的问题,如果内存分配的不对,很容易就导致生成的JSON字符串里面什么都没有。网上很多解决方案是自行编写内存管理函数,也就是malloc和free,这种方法太麻烦而且可移植性不高,最后我选择了使用增大堆栈的方式。
在这里插入图片描述
2.从github上获取cJSON的源码并解压,如下图
在这里插入图片描述
我们只需要其中的cJSON.c和cJSON.h,并把他们复制到工程中。
在这里插入图片描述
3.实际编写代码部分,我们需要生成一个JSON格式的字符串如下

{"name":	"Alpha","address":	{"conutry":	"China","city":	"Luoyang"},"info":	{"age":	21,"weight":	66}
}

实际编写代码部分,我们要注意的是,在使用cJSON之后,要及时将其删除,其中删除父对象也会自动迭代删除子对象

下面是初始化部分,完成生成JSON格式数据,并将其转化为字符串格式数据,最后删除

char *buffer;cJSON* cjson_test = NULL;cJSON* cjson_address = NULL;cJSON* cjson_info = NULL;cjson_test = cJSON_CreateObject();////cJSON_AddStringToObject(cjson_test,"name","Alpha");cjson_address = cJSON_CreateObject();cJSON_AddStringToObject(cjson_address,"conutry","China");cJSON_AddStringToObject(cjson_address,"city","Luoyang");cJSON_AddItemToObject(cjson_test,"address",cjson_address);cjson_info = cJSON_CreateObject();cJSON_AddNumberToObject(cjson_info,"age",21);cJSON_AddNumberToObject(cjson_info,"weight",66);cJSON_AddItemToObject(cjson_test,"info",cjson_info);buffer = cJSON_Print(cjson_test);cJSON_Delete(cjson_test);

下面是发送字符串到上位机部分

/* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_Delay(1000);u1_printf("You Json Is:%s\r\n",buffer);}/* USER CODE END 3 */
}

4,编译代码并在上位机中观察现象在这里插入图片描述
完成了所需要的功能

总结

本部分内容完成了cJSON的移植和JSON格式的初步使用,下一阶段准备使用paho 的开源mqtt库链接百度云天工,并且使用paho自带的ping函数,完成stm32链接百度云天工后的连接检测。

快速生成JSON数据(sprintf)和解析JSON数据(strstr)技巧

参照:骚操作!快速创建JSON数据和解析JSON数据
作者:Mculover666
地址:https://mculover666.blog.csdn.net/article/details/103794279?spm=1001.2014.3001.5502

乐鑫云平台在对接的时候,可以使用tcp socket发送和接收json数据进行交互,之前专门写了一篇文章讲述cJSON的使用,然而,看了乐鑫给的官方代码后,我只能说,突如其来的骚,闪了**的腰!

1. 生成JSON数据

核心思想:构造字符串!

这里我拿设备激活举个例子,设备激活的数据格式如下:

{"path": "/v1/device/activate/", "method": "POST", "meta": {"Authorization": "token HERE_IS_THE_MASTER_DEVICE_KEY"}, "body": {"encrypt_method": "PLAIN", "bssid": ":bssid", "token": ":token"}}

其中:

  • HERE_IS_THE_MASTER_DEVICE_KEY:填写之前获取的秘钥;
  • bssid:填写设备MAC地址;
  • token :随机值即可,可以留空;

这样的一条数据,如果使用cJSON的函数一条一条创建,不仅代码量大,而且内存占用量也极大,接下来向大家介绍一个骚操作,看完后,我相信你会点赞的!

首先直接使用宏定义将整段JSON字符串给出:

#define ACTIVE_DATA                  \
"{\n\"path\": \"/v1/device/activate/\",\n\
\"method\": \"POST\",\n\
\"meta\":\
{\"Authorization\": \"token %s\"},\n\
\"body\":\
{\"encrypt_method\": \"PLAIN\",\
\"bssid\": \"%s\",\
\"token\": \":\"}\n}\n"

然后一行命令即可构造出将其中两个需要用户给出的值定义:

#define TOKEN   "ef97b306620d5e9de19d7b2131742b152b2e94d0"
#define BSSID   "dc:4f:22:5e:90:b7"

最后一行代码解决问题,简洁到爆炸:使用拼接函数

sprintf(active_data, ACTIVE_DATA, TOKEN, BSSID);

整段程序如下:

#include <stdio.h>
#include <stdlib.h>#define ACTIVE_DATA                  \
"{\n\"path\": \"/v1/device/activate/\",\n\
\"method\": \"POST\",\n\
\"meta\":\
{\"Authorization\": \"token %s\"},\n\
\"body\":\
{\"encrypt_method\": \"PLAIN\",\
\"bssid\": \"%s\",\
\"token\": \":\"}\n}\n"#define TOKEN   "ef97b306620d5e9de19d7b2131742b152b2e94d0"
#define BSSID   "dc:4f:22:5e:90:b7"int main(void)
{char* active_data = malloc(300);sprintf(active_data, ACTIVE_DATA, TOKEN, BSSID);printf(active_data);return 0;
}

编译运行:
在这里插入图片描述

2. 解析JSON数据

"deliver_to_device": true, "get": "action": "LED_ON", "meta": "Authorization": "token 8668c64f40d172be31eb4f12cbcaf4e57c9e1e3c", "Time-Zone": "Asia/Shanghai", "method": "GET", "nonce": 587250592, "path": "/v1/device/rpc/"

其中想要的数据只有:
在这里插入图片描述
所以,为什么要浪费精力,浪费代码,浪费内存去用cJSON一条一条解析数据,而且解析出来有用的值只有“LED_ON”,所以直接使用C库函数strstr()判断这段字符串中有没有“LED_ON”就ok啦~

#include <stdio.h>
#include <string.h>char rpc_cmd[] = "\
\"deliver_to_device\": true,\
\"get\": \"action\": \"LED_ON\",\
\"meta\": \"Authorization\": \"token 8668c64f40d172be31eb4f12cbcaf4e57c9e1e3c\",\
\"Time-Zone\": \"Asia/Shanghai\",\
\"method\": \"GET\",\
\"nonce\": 587250592,\
\"path\": \"/v1/device/rpc/\"\
";int main(void)
{if(strstr(rpc_cmd, "LED_ON")){printf("LED need to turn on!\n");}return 0;
}

编译运行:
在这里插入图片描述

Keil环境下Jansson解析库的使用

摘自:Keil环境下Jansson解析库的使用——基于STM32F103
地址:https://blog.csdn.net/whik1194/article/details/106872260
摘自:Keil环境下使用Jansson构建JSON——基于STM32F103
地址:https://blog.csdn.net/whik1194/article/details/108596840?spm=1001.2014.3001.5502

对于嵌入式开发,比较常用的就是cJSON解析库了,但是使用这个库对内存开销比较大,需要大量使用malloc和free进行动态内存分配和释放。对于单片机这种资源短缺的芯片来说,简直是太吃力了。使用STM32等单片机,不能解析多层JSON时,还需要调大堆栈。

今天来了解一下一个和cJSON非常类似的解析库——Jansson的使用,支持解析和构建JSON字符串,不需要动态分配内存,使用方法和cJSON几乎一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/264997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TEA、XTEA、XXTEA加密解密算法

参考&#xff1a;TEA、XTEA、XXTEA加密解密算法 地址&#xff1a;https://blog.csdn.net/gsls200808/article/details/48243019 其他相关博文链接&#xff1a;tea系列加密算法学习笔记、TEA和XxTEA跨平台加密算法 XXTEA可以直接加密解密字符串吗&#xff1f; 如果是字符串加密&…

WIFI 配网方式(AP模式、Smartconfig等模式)

参考&#xff1a;智能设备WIFI配网方式汇总 地址&#xff1a;https://blog.csdn.net/beauytlife_1985/article/details/87539350?spm1001.2014.3001.5502 参考&#xff1a;Wifi设备配网问题 地址&#xff1a;https://blog.csdn.net/boazheng/article/details/90906184 目录概述…

动态显示产品信息

为什么80%的码农都做不了架构师&#xff1f;>>> 今天做了个产品介绍的功能,想到只是简单的显示信息实在是无聊,那就让它动态的一个一个显示出来好了. 效果展示:http://runjs.cn/detail/topt9b26 主要的代码如下 html: info里面保存着产品的信息. <div id"c…

ALGO-162——Airport Configuration

问题描述&#xff1a;ACM机场是一个本地机场&#xff0c;对于大多数人来说&#xff0c;机场不是他们的终点或起点&#xff0c;而是中转站。机场有一个规划图。到达的大门在机场的北边&#xff08;相当于空格&#xff09;。出发的大门在机场的南边&#xff08;也相当于空格&…

CRC校验及C语言实现

摘自&#xff1a;CRC校验原理及其C语言实现 地址&#xff1a;https://blog.csdn.net/whik1194/article/details/108837493?spm1001.2014.3001.5502 什么是校验算法 最近的工作中&#xff0c;要实现对通信数据的CRC计算&#xff0c;所以花了两天的时间好好研究了一下&#xff…

技术篇(3)--QPG界面分解方法介绍

在实际开发中,我发现很多程序员花很多时间在界面处理上.并且界面之间的关系和控制逻辑可能工作量并不小.所以好些老手到后面就跑去做后台服务,做通讯去了.界面布局和交互设计本身有很多的学问,或者有很多艺术,但是本文这里先不讨论这个问题.在QPG团队实践中,我们把界面划分成很…

Linux编程MQTT实现主题发布订阅

【物联网阿里云平台开发项目实战|附课件资料】智能硬件开发-数据上云&#xff0c;零基础入门 4G模块连接阿里云教程 MQTT通信协议(mosquitto)在Linux上的环境构建与测试 MQTT通信协议(mosquitto)发布订阅例子C语言实现 MQTT客户端软件(MQTT.fx)的使用详解 各类MQTT代理服务器特…

Linux串口应用编程

目录Demo串口应用编程介绍终端Terminal串口应用编程(配置、读取、写入)struct termios 结构体配置输入模式: c_iflag输出模式: c_oflag控制模式: c_cflag(波特率、数据位、校验位、停止位)本地模式: c_lflag特殊控制字符: c_cc注意事项三种工作模式(原始模式read是否阻塞)什么时…

Linux MQTT 物联网通信

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

.NET平台下Web树形结构程序设计

.NET平台下Web树形结构程序设计 我的上篇文章《树形结构在开发中的应用》主要是在Windows Form下的实现&#xff0c;下面是Web Form下的实现。数据库设计 首先&#xff0c;我们在SQL SERVER 2000里建立一个表tbTree&#xff0c;表的结构设计如下&#xff1a;列名数据类型描述长…

Advanced Installer 9.8打包实录

原文 Advanced Installer 9.8打包实录 主要介绍&#xff1a;&#xff08;1&#xff09;创建工程&#xff0c;&#xff08;2&#xff09;创建快捷方式及其图标&#xff08;3&#xff09;卸载设置 创建工程&#xff08;.net为例&#xff09;&#xff1a; 工程创建完成。。。。接下…

CMake 入门与进阶

目录cmake简介cmake的下载cmake 的使用方法示例一&#xff1a;单个源文件(cmake生成的中间文件以及可执行文件都放在build目录下)示例二&#xff1a;多个源文件示例三&#xff1a;生成库文件(动态库和静态库、修改库文件名字、最低版本要求)示例四&#xff1a;将源文件放到不同…

Linux开发板网线直连电脑配置方法/vmware虚拟机与本机的网络ping通

目录Linux开发板网线直连电脑配置方法vmware虚拟机与本机的网络ping通Linux开发板网线直连电脑配置方法 参考&#xff1a;https://www.bilibili.com/video/BV1n541197rk?spm_id_from333.999.0.0 一般情况&#xff0c;开发板连路由器&#xff0c;电脑也连路由器&#xff0c;路由…

ubuntu网站做图像外链

http://paste.ubuntu.org.cn 转载于:https://www.cnblogs.com/yuliyang/p/3658964.html

Markdown 基础学习

Markdown是什么&#xff1f; Markdwon是一种轻量级标记语言&#xff0c;它以纯文本形式&#xff08;易读、易写、易更改&#xff09;编写文档&#xff0c;并最终以HTLM格式发布。Markdown也可以理解为将以 MARKDOWN语法编写的语言转换成HTML内容的工具。 为什么要使用Markdown?…

状态机模型

参考&#xff1a;什么是状态机&#xff1f;用C语言实现进程5状态模型 参考&#xff1a;设计模式&#xff1a;一目了然的状态机图 案例&#xff1a;状态模式(C语言实现)——MP3播放、暂停案例 STM32按键消抖——入门状态机思维&#xff08;常用的switch-case形式&#xff0c;实现…

yii开启gii功能

如果不想面对黑白界面&#xff0c;那么yii框架&#xff0c;给我们提供了一个模块gii 在配置文件中main.php 再通过访问模块的方式访问gii转载于:https://www.cnblogs.com/xiashuo-he/p/3659334.html

2、基于wsgiref模块DIY一个web框架

一 web框架 Web框架(Web framework)是一种开发框架&#xff0c;用来支持动态网站、网络应用和网络服务的开发。这大多数的web框架提供了一套开发和部署网站的方式&#xff0c;也为web行为提供了一套通用的方法。web框架已经实现了很多功能&#xff0c;开发人员使用框架提供的方…

C标准时间与时间戳的相互转换

什么是时间戳&#xff1f; 时间戳是指格林威治时间自1970年1月1日&#xff08;00:00:00 GTM&#xff09;至当前时间的总秒数。它也被称为Unix时间戳&#xff08;Unix Timestamp&#xff09;。时间戳是能够表示一份数据在一个特定时间点已经存在的完整的可验证的数据&#xff0…

Linux系统信息与系统资源

目录系统信息系统标识unamesysinfo 函数gethostname 函数sysconf()函数时间、日期GMT 时间UTC 时间UTC 时间格式时区实时时钟RTC获取时间time/gettimeofday时间转换函数设置时间settimeofday总结进程时间times 函数clock 函数产生随机数休眠(延时)秒级休眠: sleep微秒级休眠: u…