(一)实验目的和任务
1、掌握esp8266模块的TCP协议,进行联网和服务器
2、熟悉jscon库的移植和API的使用,对jscon格式的数据进行解析
3、掌握LCD或串口屏显示东京奥运会奖牌榜
(二)实验设备介绍
1、系统需求:安装有windows系统的PC机
2、软件需求: keil5,USART HMI软件
(三)实验步骤
3.1? WiFi和服务器连接
?AT指令:
? ? 1.AT
?? 回复:AT? OK
? ? ?2.WiFi连接
WIFI功能指令(模式)
?? Station模式(客户端模式):模块相当于一个客户端,可以链接到其他路由器发出的WiFi信号
?? SoftAP模式(软路由模式):模块相当于一个路由器,其他设备可以连接到该模块发送的信号
?? Station+softAP模式(混合模式):模块可在其他设备链接的同时充当路由器。
?
station模式:
1、WIFI模式设置指令:AT+CWMODE_DEF=1 回复:AT+CWMODE_DEF=1 OK | 2、WIFI 模式查询指令:AT+CWMODE? 回复:+CWMODE:1 //1:station 模式 2:softAP 模式 3:station+softAP 模式 OK | 3、连接 AP 指令:AT+CWJAP_DEF=”mwh”,”123123123” 回复:AT+CWJAP_DEF="mwh","123123123" WIFI CONNECTED WIFI GOT IP OK | 4、断开与 AP 连接指令:AT+CWQAP 回复:AT+CWQAP OK WIFI DISCONNECT | 5、连接 TCP 服务器 指令:AT+CIPSTART="TCP","111.206.176.78",80 响应:OK | 6、开启透传模式传输数据 指令:AT+CIPMODE=1 响应:OK | 7、发送数据 指令:AT+CIPSEND 响应:> | 8、退出透传模式 在透传传输数据过程中,若识别到数据“+++”就会退出透传模式。所以,发送“+++”即可退出透传模式,注 意不要加\r\n 结尾。 | 9、断开与 TCP 服务器连接 指令:AT+CIPCLOSE 响应:CLOSED OK | 10、断开与 AP 的连接 指令:AT+CWQAP 响应:OK | |
3.2获取网址API接口数据 ??
//串口2,printf 函数 //确保一次发送数据不超过USART2_MAX_SEND_LEN字节 void u2_printf(char *fmt, ...) { ??? u16 i, j; ??? va_list ap; ??? va_start(ap, fmt); ??? vsprintf((char *)USART2_TX_BUF, fmt, ap); ??? va_end(ap); ??? i = strlen((const char *)USART2_TX_BUF);??? //此次发送数据的长度 ??? for (j = 0; j < i; j++)???????????????????? //循环发送数据 ??? { ??????? while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); //循环发送,直到发送完毕 ??????? USART_SendData(USART2, USART2_TX_BUF[j]); ??? } } | uint8_t get_api(char *api_addr, uint8_t (*parse_fun)(void)) { ??? printf("获取东京奥运会奖牌榜:\r\nGET %s\r\n", api_addr); ??? u2_printf("GET %s\r\n\r\n", api_addr); ??? delay_ms(20); ??? USART2_RX_STA = 0; ??? delay_ms(1000); ??? printf("%d\r\n",USART2_RX_STA); ??? if (USART2_RX_STA & 0X8000)???? ??? { ??????? USART2_RX_BUF[USART2_RX_STA & 0X7FFF] = 0; //添加结束符 ??? } ?? //? printf("接收到:%d bytes\r\n%s\r\n\r\n", strlen((const char*)USART2_RX_BUF),USART2_RX_BUF);??? ??? parse_fun(); ??? USART2_RX_STA = 0; ??? memset(USART2_RX_BUF, 0, sizeof(USART2_RX_BUF)); //??? atk_8266_quit_trans(); //??? printf("退出透传\r\n"); ??? return 0; } |
3.3解析JOSN字符串
在cJSON.h中有为cJSON的结构体和和三个函数: typedef struct cJSON { ??? struct cJSONnext,prev; /* 遍历数组或对象链的前向或后向链表指针*/ ??? struct cJSON child; /数组或对象的孩子节点 / ??? int type; / key的类型 */ ??? char valuestring; /字符串值 / ??? int valueint; / 整数值 / ??? double valuedouble; / 浮点数值 */ ??? char string; / key的名字 */ } cJSON;
cJSON *cJSON_Parse(const char *value); //将JSON字符串转换成cJSON结构体 cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);//在cJSON结构体中查找某个键的名称(key) void cJSON_Delete(cJSON *c);//释放cJSON结构体指针
1、解析一个简单的键值对字符串: { ??? "key": "value" } 其中字符串中健为key,值为value。 使用如下: char *str = "{"key":"value"}";// 花括号里面的(")前面必须加(),将其转换为转义字符,以免和c语言字符串冲突 char *root = NULL, *ret = NULL; root = cJSON_Parse(str);//将cJSON字符串转换为cJSON结构体指针 ret = cJSON_GetObjectItem(root, "key");//在root结构体中查找"key"这个键(一个字符串),成功返回一个cJSON结构体,失败返回NULL。 printf("%s\n", ret->valuestring);//打印出来的结果是value cJSON_Delete(root);//释放cJSON结构体 ? | |
2、解析复杂一点的cJSON结构体: { ??? "json": { ??? ??? ??? "num": -1, ??? ??? ??? "num_1": 0, ??? ??? ??? "num_2": 1, ??? ??? ??? "string": "str", ??? ??? ??? "string_1": "abcd", ??? ??? ??? "string_2": "123abc123" ??? ??? ??? }, ??? "string": "str", ??? "num": 2 } 同样使用上面那三个函数搞定: /******************************解析cJSON**************************/ char str = "{"json": {"num": -1,"num_1": 0,"num_2": 1,"string": "str","string_1": "abcd","string_2": "123abc123"},"string": "str","num": 2}"; char root = NULL, ret = NULL, json = NULL;//定义三个cJOSN结构体指针 root = cJSON_Parse(str);//将cJSON字符串转换为cJSON结构体指针 json = cJSON_GetObjectItem(root, "json");//在root结构体中查找"josn" /--------------------------解析"json"---------------------------/ ret = cJSON_GetObjectItem(json, "num");//在josn结构体中查找"num" printf("%d\n", ret->valueint);//打印出来的结果是-1 ret = cJSON_GetObjectItem(json, "num_1");//在josn结构体中查找"num_1" printf("%d\n", ret->valueint);//打印出来的结果是0 ret = cJSON_GetObjectItem(json, "num_2");//在josn结构体中查找"num_2" printf("%d\n", ret->valueint);//打印出来的结果是1 ret = cJSON_GetObjectItem(json, "string");//在josn结构体中查找"string" printf("%s\n", ret->valuestring);//打印出来的结果是str ret = cJSON_GetObjectItem(json, "string_1");//在josn结构体中查找"string_1" printf("%s\n", ret->valuestring);//打印出来的结果是abcd ret = cJSON_GetObjectItem(json, "string_2");//在josn结构体中查找"string_2" printf("%s\n", ret->valuestring);//打印出来的结果是123abc123 /-------------------------------解析"json" end-----------------------/ json = cJSON_GetObjectItem(root, "string");//在root结构体中查找"string" printf("%s\n", ret->valuestring);//打印出来的结果是str ret = cJSON_GetObjectItem(root, "num");//在root结构体中查找"num" printf("%d\n", ret->valueint);//打印出来的结果是2
cJSON_Delete(root);//释放总的cJSON结构体只需要释放cJSON_Parse函数创建的cJOSN结构体即可 |
3、解析JSON结构体数组: 再多用到两个函数: int cJSON_GetArraySize(cJSON array);//获取JSON数组的大小 cJSONcJSON_GetArrayItem(cJSON *array,int item); //获取数组下标的成员 解析复杂更一点的JSON结构体和JSON结构体: { ??? "array": [{ ??? ????????? "num_0": 0, ??? ????????? "string_0": "str0" ?????????? }, ?????????? { ??? ????????? "num_1": 1, ??? ??? ??? ??? "string_1": "str1" ??? ??? ??? }, ??? ??? ??? { ??? ??? ??? ??? "num_2": 2, ??? ??? ??? ??? "string_2": "str2" ??? ??? ??? } ??? ??? ??? ] } char *str = "{"array": [{"num_0": 0,"string_0": "str0"},{"num_1": 1,"string_1": "str1"},{"num_2": 2,"string_2": "str2"}]}"; char *root = NULL, *ret = NULL, *arr = NULL, *json = NULL;//定义4个cJOSN结构体指针 int size = 0;//用于存储数组大小 /******************************解析cJSON**************************/ root = cJSON_Parse(str);//将cJSON字符串转换为cJSON结构体指针 arr= cJSON_GetObjectItem(root, "array");//在root结构体中查找"array" size = cJSON_GetArraySize(arr);//此时size值为3 /-------------------------1------------------------------------/ json= cJSON_GetArrayItem(arr, 0);//获取数组第1个成员 ret = cJSON_GetObjectItem(json, "num_0");//在josn结构体中查找"num_0" printf("%d\n", ret->valueint);//打印出来的结果为:0 ret = cJSON_GetObjectItem(json, "string_0");//在josn结构体中查找"string_0" printf("%s\n", ret->valuestring);//打印出来的结果为:str0 /-------------------------1 end-------------------------------/ /-------------------------2------------------------------------/ json= cJSON_GetArrayItem(arr, 1);//获取数组第2个成员 ret = cJSON_GetObjectItem(json, "num_1");//在josn结构体中查找"num_1" printf("%d\n", ret->valueint);//打印出来的结果为:1 ret = cJSON_GetObjectItem(json, "string_1");//在josn结构体中查找"string_1" printf("%s\n", ret->valuestring);//打印出来的结果为:str1 /-------------------------2 end-------------------------------/ /-------------------------3------------------------------------/ json= cJSON_GetArrayItem(arr, 2);//获取数组第3个成员 ret = cJSON_GetObjectItem(json, "num_2");//在josn结构体中查找"num_1" printf("%d\n", ret->valueint);//打印出来的结果为:2 ret = cJSON_GetObjectItem(json, "string_2");//在josn结构体中查找"string_2" printf("%s\n", ret->valuestring);//打印出来的结果为:str2 /-------------------------3 end-------------------------------/ cJSON_Delete(root);//释放cJSON结构体 ? |
(四)实验现象
?
注意:使用的芯片为STM32F103系列?? 如果使用STM32F103C8T6会出现内存溢出的情况。
参考资料链接:(15条消息) STM32使用API函数奖牌详细实现相应的功能-嵌入式文档类资源-CSDN文库https://download.csdn.net/download/weixin_41114301/83986511
案例参考网址为:http://www.wangchaochao.top/2021/04/18/stm32-ncov-vaccine/
总结:只有在实践中总结,才能走的更远,领悟技术的细节。
|