基于STM32与ESP8266的太空人WiFi天气时钟(代码开源)_esp8266 开源项目(1)

| AT+CWQAP | 与AP断开连接 |
| AT+CWSAP | 设置ESP8266 softAP配置 |
| AT+CWLIF | 获取连接到 ESP8266 softAP 的 station 的信息 |

关于WiFi模式这里要说明一下,sta模式下模块相当于客户端,像我们手机平板一样是要去连接路由器的,而AP模式下模块相当于路由器,是发射WiFi被别人连的。ESP8266支持两种模式并存(模块出厂默认的是AP模式) 。另外,扫描WiFi指令 AT+CWLAP 只能在sta模式下使用,否则会报ERRO错误, AT+CWJAPAT+CWQAP 指令也同理。

sta模式连接WiFi演示

  1. 发送 **AT+CWMODE=1**指令配置模块为sta模式(参数1,2,3分别对应模式sta,AP和sta/AP)。
  2. 发送**AT+CWLAP**指令扫描当前附近WiFi,模块会返回可用AP列表。
  3. 使用**AT+CWJAP="WiFi名称","WiFi密码"连接到指定的路由器,比如我在图书馆的WiFi是 “Wang”,密码是“123456”,实际连接WiFi发送的指令就是AT+CWJAP="Wang","123456"** 。
  4. 返回的“WIFI CONNECTED”说明连接成功,“WIFI GOT IP”代表模块分配到了IP。
  5. 最后可使用 **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连接了,具体步骤如下:

  1. 根据上面“sta模式连接WiFi演示”一节把模块连上WiFi
  2. 输入指令 **AT+CIPMUX=0**设置单连接
  3. 从“网络调试助手”得知本机IP和端口,输入指令 AT+CIPSTART="TCP","192.168.43.140",1234(指令参数分别为连接类型、目标IP地址和端口号)向服务器发起TCP连接请求,握手成功并建立连接后,服务器端的“网络调试助手”就会显示客户端IP和端口信息,此时双方已做好收发数据的准备(根据实际需要连接的IP地址来
  4. 输入指令**AT+CIPMODE=1**开启透传模式
  5. 输入命令 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);		// 开始透传
}

二、知心天气API使用

本项目为WiFi天气时钟,自然离不开需要从网页上读取天气信息。这里我们使用业内比较著名的知心天气

2.1 登陆心知天气官网,注册

没有账号的朋友可以自己去注册一下,流程很简单。不商用的话,知心天气是免费的,还是比较良心的(网站响应率也很高)。

点击“立即免费试用”

点击免费版的“免费申请”

申请后可查看到自己的私钥(自行保存后面需要用到)

2.1 API函数的使用

目前,大部分网络数据调用都是习惯性的调用数据提供商的API接口函数

重新点击“产品”—>“天气数据”,点击**“查看API文档”**

点击"天气实况",打开对应的API接口文档

查看天气实况的接口地址,以及返回的数据结果示例(自行保存后面需要用到)

(1)上述知心天气API接口函数的寻找和使用通用性很高,大部分网络数据读取的流程与之类似。

(2)嵌入式开发大部分情况下一般都是C语言进行开发的,由于C语言的局限性,没有直接的字典类型处理(python),所以,对于服务器返回给ESP8266的JSON数据一般是无法直接解码读取的。目前有2种方法处理:①、移植CJSON去解码②取巧去比对字符串(本次使用的方法)

项目使用过程中直接使用知心天气自带的API函数,项目大致流程:开启STA模式后,成功连上WiFi后,通过TCP协议去访问执行天气网站的服务器,在发送特定的API接口函数,服务器响应后返回需要的结果信息。

三、UART串口通讯

STM32作为MCU与ESP8266直接的通讯就是简单的UART(串口)通信,这一点依旧与蓝牙模块很类似。使用方法:通过串口UARTx_TX连接ESP8266的UART_RX,然后单片机通过串口发送AT指令集。ESP8266后续从服务器接受的数据信息也从ESP8266的UART_TX传输给单片机UARTx_RX。后续只需要使用自己的方法去解析串口接收到的数据,即可得到自己想要的数据信息。

可以初步使用电脑串口去读取MCU接收到ESP8266返回的信息:

四、CubeMX配置

1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug设置成Serial Wire否则可能导致芯片自锁);

3、GPIO配置:此处模拟使用SPI通信,并且设置ESP8266的EN和RST;

4、RTC配置:年月日,时分秒;

5、UART1和UART3配置:MCU分别与电脑和ESP8266通讯(记得开启串口通信中断);

6、时钟树配置

7、工程配置

五、代码与解析

5.1 TFT-LCD显示代码

LCD显示部分其实都是非常基础的操作,不熟悉的可以去看看笔者另一篇文章了解一下。作者这里主要把工程中不一样的地方指出来一下。【强烈推荐】基于STM32的TFT-LCD各种显示实现(内容详尽含代码)_混分巨兽龙某某的博客-CSDN博客_lcd显示屏显示代码

5.1.1 UI设计

WiFi天气时钟中最要的点——UI设计,需要去设计很多界面图标,作者这里耗费了超级多的时间,翻遍了GitHub视觉中国。最后找到了差不多符合作者要求的UI库(有需要的可以评论区留下邮箱),如下:

5.1.2 GIF动图实现

目前,由于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]);
}

5.2 ESP8266代码

EPS8266部分代码主要是配置后负责和目标服务器去实现通讯,当然还有需要解码服务器返回信息。

5.2.1 ESP8266配置代码(含UART处理)

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=后面也可以换成自己所在城市的字母。

5.2.2 ESP8266信息解码

这部分作者取巧,使用了字符串对比和指针取值的操作。

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年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/ba0c325f3557b062b65de5c2e872ac50.png)

![img](https://img-blog.csdnimg.cn/img_convert/cba91a8727e5cf28b2cb4ad0185379fd.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/8404e99999080d96caeee6908911cb35.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/dc1e01c19d30f236c72c240230fefe24.png)

![img](https://img-blog.csdnimg.cn/img_convert/617a942e2c19cdeea966bcf6bb302530.png)

![img](https://img-blog.csdnimg.cn/img_convert/abfc6a97f47e7d1ee6531ac7106865df.png)

![](https://img-blog.csdnimg.cn/img_convert/cc231e2a404f52523779ce813f9ba7b7.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


779948)]

[外链图片转存中...(img-1BAXDjeK-1715683779950)]

[外链图片转存中...(img-4O9xsyxJ-1715683779951)]

 [外链图片转存中...(img-2pSzWsps-1715683779951)]

[外链图片转存中...(img-uIDhn7DU-1715683779952)]

[外链图片转存中...(img-gCwAHcM3-1715683779953)]

[外链图片转存中...(img-j2rg2lXC-1715683779954)]

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值