赞
踩
| AT+CWQAP | 与AP断开连接 |
| AT+CWSAP | 设置ESP8266 softAP配置 |
| AT+CWLIF | 获取连接到 ESP8266 softAP 的 station 的信息 |
关于WiFi模式这里要说明一下,sta模式下模块相当于客户端,像我们手机平板一样是要去连接路由器的,而AP模式下模块相当于路由器,是发射WiFi被别人连的。ESP8266支持两种模式并存(模块出厂默认的是AP模式) 。另外,扫描WiFi指令 AT+CWLAP 只能在sta模式下使用,否则会报ERRO错误, AT+CWJAP 和 AT+CWQAP 指令也同理。
sta模式连接WiFi演示
AT+CWMODE=1
**指令配置模块为sta模式(参数1,2,3分别对应模式sta,AP和sta/AP)。AT+CWLAP
**指令扫描当前附近WiFi,模块会返回可用AP列表。AT+CWJAP="WiFi名称","WiFi密码"
连接到指定的路由器,比如我在图书馆的WiFi是 “Wang”,密码是“123456”,实际连接WiFi发送的指令就是AT+CWJAP="Wang","123456"
** 。AT+CWQAP
**断开当前连接的WiFi。TCP/IP相关AT指令
传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
我们常说互联网互联网,那两个连接到互联网的设备该如何相互“交流”呢?TCP连接就是其中一种最常用的方式。TCP是面向连接的传输层协议,通信双方都要实现TCP协议,其中一方只需目标ip地址和端口号就能发起连接,连接一旦建立,就像在双方之间拉了一条管子,管子两端可进行全双工(双向同时收发)通信。
TCP是传输层协议,是在网络层IP协议的基础上封装而来。而这些封装的实现细节也是与我们无关,我们只需使用系统所提供的相关接口“拿来即用”,比如网络编程中的Socket。ESP8266模块中也实现了TCP/IP协议栈,模块作为客户端可轻松使用AT指令向服务端发起TCP连接。连接TCP服务器并开启透传模式后,模块串口收到的数据就会通过TCP连接透传到服务端,这样就完成了数据从硬件串口通过网络到程序进程的传输,实现软硬结合。
指令 | 描述 |
---|---|
AT+CIPSTATUS | 查询网络连接信息 |
AT+CIPMUX | 设置多连接模式 |
AT+CIPSTART | 建立TCP连接UDP传输或者SSL连接 |
AT+CIPCLOSE | 关闭TCP/UDP/SSL传输 |
AT+CIPMODE | 设置透传模式 |
AT+CIPSEND | 发送数据 |
把WiFi模块和电脑连接,在sscom确定AT指令能正常使用后,就可以开始配置TCP连接了,具体步骤如下:
AT+CIPMUX=0
**设置单连接AT+CIPSTART="TCP","192.168.43.140",1234
(指令参数分别为连接类型、目标IP地址和端口号)向服务器发起TCP连接请求,握手成功并建立连接后,服务器端的“网络调试助手”就会显示客户端IP和端口信息,此时双方已做好收发数据的准备(根据实际需要连接的IP地址来)AT+CIPMODE=1
**开启透传模式AT+CIPSEND
进入透传模式,此时模块会把所有串口收到的数据都从TCP端口发送至服务器,同样的,从服务器收到的数据也会从模块串口发送出去打印到sscom上。这样WiFi模块就真正成为了连接硬件与网络的桥梁,实现了串口到TCP的协议转换以上其实就是大概本次项目需要使用到的指令,ESP8266配置代码如下:
void esp8266_config(void)
{
char str[200];
sprintf(str, "AT+CWJAP=\"%s\",\"%s\"\r\n", WIFI_NAME, WIFI_PSW);
// SendATCmd("+++", 500); // 退出透传模式
SendATCmd("AT\r\n", 2000); // 测试ESP01模块是否存在
// SendATCmd("AT+GMR\r\n",3000); // 查看模块版本信息
SendATCmd("AT+CWMODE=1\r\n", 2000); // 开启STA+AP模式 ==================
SendATCmd("AT+RST\r\n", 3000);
SendATCmd(str, 10000); // 连接无线路由器或者手机热点,等待10秒 ============
SendATCmd("AT+CIPMUX=0\r\n", 2000); // 关闭多连接
SendATCmd("AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80\r\n", 2000); // 连接心知 天气TCP服务器
SendATCmd("AT+CIPMODE=1\r\n", 500); // 开启透传模式
SendATCmd("AT+CIPSEND\r\n", 500); // 开始透传
}
本项目为WiFi天气时钟,自然离不开需要从网页上读取天气信息。这里我们使用业内比较著名的知心天气。
没有账号的朋友可以自己去注册一下,流程很简单。不商用的话,知心天气是免费的,还是比较良心的(网站响应率也很高)。
点击“立即免费试用”
点击免费版的“免费申请”
申请后可查看到自己的私钥(自行保存后面需要用到)
目前,大部分网络数据调用都是习惯性的调用数据提供商的API接口函数。
重新点击“产品”—>“天气数据”,点击**“查看API文档”**
点击"天气实况",打开对应的API接口文档
查看天气实况的接口地址,以及返回的数据结果示例(自行保存后面需要用到)
(1)上述知心天气API接口函数的寻找和使用通用性很高,大部分网络数据读取的流程与之类似。
(2)嵌入式开发大部分情况下一般都是C语言进行开发的,由于C语言的局限性,没有直接的字典类型处理(python),所以,对于服务器返回给ESP8266的JSON数据一般是无法直接解码读取的。目前有2种方法处理:①、移植CJSON去解码;②取巧去比对字符串(本次使用的方法);
项目使用过程中直接使用知心天气自带的API函数,项目大致流程:开启STA模式后,成功连上WiFi后,通过TCP协议去访问执行天气网站的服务器,在发送特定的API接口函数,服务器响应后返回需要的结果信息。
STM32作为MCU与ESP8266直接的通讯就是简单的UART(串口)通信,这一点依旧与蓝牙模块很类似。使用方法:通过串口UARTx_TX连接ESP8266的UART_RX,然后单片机通过串口发送AT指令集。ESP8266后续从服务器接受的数据信息也从ESP8266的UART_TX传输给单片机UARTx_RX。后续只需要使用自己的方法去解析串口接收到的数据,即可得到自己想要的数据信息。
可以初步使用电脑串口去读取MCU接收到ESP8266返回的信息:
1、RCC配置外部高速晶振(精度更高)——HSE;
2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);
3、GPIO配置:此处模拟使用SPI通信,并且设置ESP8266的EN和RST;
4、RTC配置:年月日,时分秒;
5、UART1和UART3配置:MCU分别与电脑和ESP8266通讯(记得开启串口通信中断);
6、时钟树配置
7、工程配置
LCD显示部分其实都是非常基础的操作,不熟悉的可以去看看笔者另一篇文章了解一下。作者这里主要把工程中不一样的地方指出来一下。【强烈推荐】基于STM32的TFT-LCD各种显示实现(内容详尽含代码)_混分巨兽龙某某的博客-CSDN博客_lcd显示屏显示代码
WiFi天气时钟中最要的点——UI设计,需要去设计很多界面图标,作者这里耗费了超级多的时间,翻遍了GitHub和视觉中国。最后找到了差不多符合作者要求的UI库(有需要的可以评论区留下邮箱),如下:
目前,由于STM32自身内存的缘故,其实STM32是不太适合实现GIF动图的。所以,网上这方面的资料和代码都很少。目前,较为主流的方法:(1)enWin或者Lvgl库实现GIF动图;(2)从SD卡读取数据去显示。
作者这里用了一直笨方法去实现了GIF显示,就是去循环遍历GIF动图的每一帧。
使用GIF分离器去分离GIF动图的每一帧;
再利用**Image2Lcd 2.9(破解版)**去提前图模;
将取模代码变为2维数组,第一维度为帧数,第二维度为每帧图片的取模。
之后循环显示该GIF数组的每一帧,即可实现GIF动图显示。
代码:
void showimage4(const unsigned char *p) { int i; unsigned char picH,picL; Address_set(180,146,228,195); for(i=0;i<49*50;i++) { picL=*(p+i*2); picH=*(p+i*2+1); LCD_WR_DATA(picH<<8|picL); } } for(int a=0;a<11;a++) { showimage4(gImage_1[a]); }
EPS8266部分代码主要是配置后负责和目标服务器去实现通讯,当然还有需要解码服务器返回信息。
UART回调处理函数:
/* USER CODE BEGIN 4 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Prevent unused argument(s) compilation warning */ UNUSED(huart); /* NOTE: This function Should not be modified, when the callback is needed, the HAL_UART_TxCpltCallback could be implemented in the user file */ if(huart == &huart1) { g_uart1_rx.buf[g_uart1_rx.size++] = aRxBuffer_rx1; if((g_uart1_rx.buf[g_uart1_rx.size-1] == 0x0A)&&(g_uart1_rx.buf[g_uart1_rx.size-2] == 0x0D)) { HAL_UART_Transmit(&huart1, (uint8_t *)&g_uart1_rx.buf, g_uart1_rx.size,0xFFFF); while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); g_uart1_rx.size = 0; memset(g_uart1_rx.buf,0x00,sizeof(g_uart1_rx.buf)); } HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer_rx1, 1); } if(huart == &huart3) { g_uart3_rx.buf[g_uart3_rx.size++] = aRxBuffer_rx3; if((g_uart3_rx.buf[g_uart3_rx.size-1] == 'K')&&(g_uart3_rx.buf[g_uart3_rx.size-2] == 'O')) { HAL_UART_Transmit(&huart1, (uint8_t *)&g_uart3_rx.buf, g_uart3_rx.size,0xFFFF); while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); g_uart3_rx.size = 0; memset(g_uart3_rx.buf,0x00,sizeof(g_uart3_rx.buf)); } else if((g_uart3_rx.buf[g_uart3_rx.size-2] == ']')&&(g_uart3_rx.buf[g_uart3_rx.size-1] == '}') &&(g_uart3_rx.buf[g_uart3_rx.size-3] == '}')) { HAL_UART_Transmit(&huart1, (uint8_t *)&g_uart3_rx.buf, g_uart3_rx.size,0xFFFF); while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); // strcpy(Data_buff,(char *)g_uart3_rx.buf); temp = 1; g_uart3_rx.size = 0; memset(g_uart3_rx.buf,0x00,sizeof(g_uart3_rx.buf)); } HAL_UART_Receive_IT(&huart3, (uint8_t *)&aRxBuffer_rx3, 1); } } /* USER CODE END 4 */
ESP8266.h(AT控制):
#ifndef __ESP8266_H #define __ESP8266_H //#include "stdint.h" //uint8_t aRxBuffer_rx1; //接收中断缓冲 //uint8_t aRxBuffer_rx3; //接收中断缓冲 //typedef struct { // uint16_t size; // uint8_t buf[1022]; // 接收缓冲数组 //} UART_RXDATA; //UART_RXDATA g_uart1_rx; //UART_RXDATA g_uart3_rx; //char Data_buff[1022]; //char weather[10]; //存储天气 //uint8_t temperature[2]={0,0}; //储存最高气温和最低气温 //uint8_t temp = 0; //需要连接的wifi账号和密码,需要修改,且WiFi频段不支持5GHz #define WIFI_NAME "Wang" #define WIFI_PSW "123456" 心知天气api,注意key=后面需要替换成自己账号的密钥 //char *get="GET https://api.seniverse.com/v3/weather/daily.json?key=SkV9zIBpwJAOixrJZ&location=chongqing&language=en&unit=c\r\n"; //void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); void SendATCmd(char *cmd, int waitms); void esp8266_config(void); #endif
ESP8266.c:
#include "esp8266.h" #include "usart.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include "lcd.h" void SendATCmd(char *cmd, int waitms) { // 发送AT指令给串口3 if (NULL != cmd) { HAL_UART_Transmit(&huart3, (uint8_t *)cmd, strlen(cmd), 0xFFFF); if (waitms > 0) HAL_Delay(waitms); // 延时等待ESP01模块应答时间 } } void esp8266_config(void) { char str[200]; sprintf(str, "AT+CWJAP=\"%s\",\"%s\"\r\n", WIFI_NAME, WIFI_PSW); // SendATCmd("+++", 500); // 退出透传模式 SendATCmd("AT\r\n", 2000); // 测试ESP01模块是否存在 // SendATCmd("AT+GMR\r\n",3000); // 查看模块版本信息 SendATCmd("AT+CWMODE=1\r\n", 2000); // 开启STA+AP模式 ================== SendATCmd("AT+RST\r\n", 3000); SendATCmd(str, 10000); // 连接无线路由器或者手机热点,等待10秒 ============ SendATCmd("AT+CIPMUX=0\r\n", 2000); // 关闭多连接 SendATCmd("AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80\r\n", 2000); // 连接心知天气TCP服务器 SendATCmd("AT+CIPMODE=1\r\n", 500); // 开启透传模式 SendATCmd("AT+CIPSEND\r\n", 500); // 开始透传 SendATCmd("GET https://api.seniverse.com/v3/weather/daily.json?key=SkV9zIBpwJAOixrJZ&location=zhenjiang&language=en&unit=c\r\n", 2000); }
注意,key=后面尽量换成自己的密钥,location=后面也可以换成自己所在城市的字母。
这部分作者取巧,使用了字符串对比和指针取值的操作。
strstr()函数:
atoi()函数:
代码:
char *p; p = strstr(Data_buff,"text_day"); //查找天气 sscanf(p+11,"%[^\"]",weather); // LCD_ShowString(40,80,(uint8_t*)weather); p = strstr(Data_buff,"high"); //查找气温 temperature[0]=atoi(p+7); p = strstr(Data_buff,"low"); temperature[1]=atoi(p+6); // LCD_ShowxNum2(45,40,temperature[1],2,24,0); LCD_ShowxNum2(160,207,temperature[0],2,24,0); //温度 value = (temperature[1]+temperature[0])/2; LCD_ShowxNum2(52,160,value,2,24,0); //湿度 p = strstr(Data_buff,"humidity"); humidity=atoi(p+11); LCD_ShowxNum2(132,160,humidity,2,24,0); LCD_ShowNew(161,160,'%',24,0); if((strstr(weather,"Overcast")) || (strstr(weather,"Mostly Cloudy")) || (strstr(weather,"Partly Cloudy")) || strstr(weather,"Cloudy")) { Overcast(); } if((strstr(weather,"Sunny")) || (strstr(weather,"Clear")) || (strstr(weather,"Fair"))) //ÇçÌì **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!** **因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。** ![img](https://img-blog.csdnimg.cn/img_convert/fb7e2e89daa06135eb57c0e279a80c1d.png) ![img](https://img-blog.csdnimg.cn/img_convert/f29243d63a30d537f1ca4cc7653f0c77.jpeg) ![img](https://img-blog.csdnimg.cn/img_convert/25bc049b4fba8bb4e38e174084169372.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!** ![img](https://img-blog.csdnimg.cn/img_convert/f22d2eab77b7a5105b85c32dee7bacfc.png) ![img](https://img-blog.csdnimg.cn/img_convert/3ac4b094fd48b7fe4c593a6f904aa557.png) **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)** <img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" /> # 最后 **资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~** **你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!** 2383530773)] **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!** [外链图片转存中...(img-Q0WWeRhM-1712383530773)] [外链图片转存中...(img-wNY26F7T-1712383530774)] **由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新** **如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)** <img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" /> # 最后 **资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~** **你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!** **[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。