STM32+ESP8266获取时间和天气

ESP8266获取天气数据


文章目录

  • ESP8266获取天气数据
    • 通过HC05配置ESP01s将获取时间和天气显示到TFT1.3寸彩屏上
    • 必读
    • 心知天气注册
    • 串口AT调试
      • AT测试
      • 设置wifi模式
      • 重启模块
      • 连接WIFI
      • 建立TCP连接
      • 开启透传模式
      • 开始透传
      • 提出请求
    • 程序例程
      • 硬件连线
      • 软件设计
      • 代码
        • esp8266.h
        • esp8266.c
        • USART_LY.h
        • USART_LY.c
        • TFToled.h
        • TFToled.c
        • main.c
    • 工程演示
    • 感谢


通过HC05配置ESP01s将获取时间和天气显示到TFT1.3寸彩屏上

必读

在文章最后我会给出百度网盘链接,尽管如此还是希望大家认真观看文章,并琢磨程序代码逻辑在我的基础上可以改出属于自己特点的工程!

对于ESP8266 AT指令不熟悉的可以观看我的上一篇文章 认识 ESP8266—ESP-01S (含AT指令)

心知天气注册

登陆心知天气官网,注册

https://www.seniverse.com/

注册完成后点击“产品”,进入“天气数据”
在这里插入图片描述

点击“立即免费试用”
在这里插入图片描述

点击免费版的“免费申请”
在这里插入图片描述

申请后可查看到自己的私钥(自行保存后面需要用到)
在这里插入图片描述

重新点击“产品”—>“天气数据”,点击“查看API文档”
在这里插入图片描述

点击"天气实况",打开对应的API接口文档
在这里插入图片描述
查看天气实况的接口地址,以及返回的数据结果示例(自行保存后面需要用到)
在这里插入图片描述

串口AT调试

指令关键字 指令作用 响应
AT 测试指令 OK
AT+RST 重启模块指令 OK
AT+GMR 查看版本信息 AT version,SDK version,company,date,OK
ATE 开关回显功能ATE关闭回显,ATE开启回显 OK
AT+RESTORE 恢复出厂设置 OK
AT+UART 设置串口配置 OK
AT+CWMODE=mode 设置WiFi应用模式 OK
AT+CWMODE? 响应返回当前模块的模式 +CWMODE:mode;OK
AT+CWLIF 查看已接入设备的IP 已连接所有设备的IP地址
AT+CIPMUX 启动多连接 OK
AT+CWJAP 加入AP OK
AT+CWQAP 退出与AP的连接 OK
AT+CWSMARTSTART 启动智能连接 OK或者ERROR
AT+CWSMARTSTOP 停止智能连接 OK或者ERROR

使用AT指令获取到天气情况,这里列出对应的AT指令
串口助手波特率设置位115200,其他设置默认即可

AT测试

发送 “AT” :正常启动就会响应“OK”

AT

在这里插入图片描述

设置wifi模式

  • Station模式 :ESP32连接到接入点
  • AP模式 :热点模式
  • Station+AP模式 :(两种模式共存)

使用串口发送指令AT+CWMODE=1设置模块Wi_Fi应用模式为Station模式

AT+CWMODE=1

在这里插入图片描述
在这里插入图片描述

重启模块

发送指令AT+RST使模块重启,重启后等待一段时间

AT+RST

在这里插入图片描述

连接WIFI

发送指令AT+CWJAP=“ssid”,“pwd”,ssid就是你要连接WiFi的名字,pwd就是密码

AT+CWJAP="amh","12345678"

在这里插入图片描述
在这里插入图片描述

建立TCP连接

发送指令AT+CIPSTART=“TCP”,“api.seniverse.com”,80,和心知天气建立TCP连接

AT+CIPSTART="TCP","api.seniverse.com",80

在这里插入图片描述

开启透传模式

发送指令“AT+CIPMODE=1”设置成功则返回OK

AT+CIPMODE=1

在这里插入图片描述

在这里插入图片描述

开始透传

发送指令“AT+CIPSEND” 开始透传

AT+CIPSEND

在这里插入图片描述

提出请求

发送“GET https://api.seniverse.com/v3/weather/now.json?key=私钥&location=城市拼音&language=zh-Hans&unit=c”向网址提出请求

GET https://api.seniverse.com/v3/weather/now.json?key=私钥&location=城市&language=zh-Hans&unit=c

在这里插入图片描述

这里的location可以改为自己的城市,我的是西安(XiAn)
私钥为心知天气中获取到的私钥
语言language用的是中文(zh-Hans),这部分可以自行到心知天气官网的文档查看

注意:设置zh-Hans可能会乱码,建议改成en(返回英文)

程序例程

硬件连线

MCU ESP8266
3.3V VCC
GND GND
PB10 RXD
PB11 TXD
3.3V IO
3.3V RST
MCU USB转TTL
5V VCC
GND GND
PA9 RXD
PA10 TXD
MCU TFT1.3彩屏
5V VCC
GND GND
PA5 SCL
PA7 SDA
PB0 RES
PB1 DC
A4 BLK
MCU HC-05
5V VCC
GND GND
PA2 RXD
PA3 TXD

软件设计

  • 使用ESP-01s模块从心知天气获取天气数据数据,使用cJSON包解析数据包。
  • 使用的串口USART3给ESP-01s模块发送AT指令。
  • 使用串口USART1回显ESP-01s返回的数据,到上位机。
  • 使用HC-05模块通过手机APP给ESP-01s模块配置简单的AT指令。
  • 使用串口USART2接收HC-05模块传过来的AT命令,当做参数,给串口USART3,并且使用使用串口USART2回显ESP-01s模块返回的数据到手机APP中
  • 将显示回来的时间,使用定时器一秒加1,来维持时间的正确性(具有误差2-3秒)。
  • 使用TFT1.3寸彩屏,排版显示数据内容
  • 使用了独立看门狗来检测程序是否正常运行,2秒一次喂狗
  • 使用定时器每15分钟更新一次天气和时间

代码

这里只给了部分代码,在文章最后会给出百度网盘链接,尽管如此还是希望大家认真观看。

esp8266.h
#ifndef __ESP8266_H
#define __ESP8266_H
#include "sys.h"
#include "stdio.h"	
#include "oled.h"
#include <stdbool.h> 
//子对象1结构体--Location
typedef struct
{
   
	char id[32];
	char name[32];
	char country[32];
	char path[64];
	char timezone[32];
	char timezone_offset[32];
}Location;
 
//子对象2结构体--Now
typedef struct
{
   
	char text[32];
	char code[32];
	char temperature[32];
}Now;

typedef struct
{
   
	Location location;		//子对象1
	Now now;				//子对象2
	char last_update[64];	//子对象3
}Results;

typedef struct   //结构体。
{
   
    vu16  year;
    vu8   month;
    vu8   date;
    vu8   hour;
    vu8   min;
    vu8   sec;	 
}nt_calendar_obj;	 

//用户配置AT指令的函数

//检查WIFI模块是否在线
bool esp_wifi_on_line(char *at);
//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
bool esp_work_pattern(char *at);
//esp重启
bool esp_restart(char *at);
//esp设置连接模式
bool esp_Connection_mode(char *at);
//esp连接wifi
bool esp_link_WIFI(char *at);

//函数

u8 esp8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime);
u8* esp8266_send_data(u8 *cmd,u16 waittime);
u8* esp8266_check_cmd(u8 *str);
void esp8266_start_trans(void);
u8 esp8266_quit_trans(void);
u8 get_current_weather(void);
u8 cloes_weather(void);
u8 get_weather(void);
u8 esp8266_quit_trans(void);
int cJSON_WeatherParse(char *JSON, Results *results);


void atk_8266_get_wanip(u8* ipbuf);
u8 get_beijing_time(void);
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);
u8* atk_8266_check_cmd(u8 *str);
u8 Is_Leap_Year(u16 year);
#endif

esp8266.c
#include "esp8266.h"
#include "string.h"
#include "usart.h"
#include "usart3.h"
#include "stm32f10x.h"
#include "sys.h" 
#include "delay.h"
#include "led.h"
#include "stdlib.h"
#include "malloc.h"
#include "cJSON.h"
#include <stdbool.h> 
#include "USART_LY.h"
#include "bsp_systick.h"
nt_calendar_obj nwt;  //定义结构体变量


//const u8* wifista_ssid="59";							//路由器SSID号
//const u8* wifista_password="12345678"; 				//连接密码

#define WEATHER_PORTNUM 	"80"						//天气连接端口号:80	
#define WEATHER_SERVERIP 	"api.seniverse.com"			//天气服务器IP


#define TIME_PORTNUM			"80"					//时间端口号
#define TIME_SERVERIP			"www.beijing-time.org"	//时间服务器IP


//月份数据表											 
u8 const table_week[12]={
   0,3,3,6,1,4,6,2,5,0,3,5}; 		//月修正数据表	  
//平年的月份日期表
const u8 mon_table[12]={
   31,28,31,30,31,30,31,31,30,31,30,31};



u8 *p;
Results results[] = {
   {
   0}};
extern char USART2_RX_BUF[USART2_MAX_RECV_LEN];
extern vu16 USART2_RX_STA;
/*********************************************************************************
* Function Name    : esp8266_start_trans,ESP8266初始化设置
* Parameter		   : 
* Return Value     : 
* Function Explain : 连接wifi
* Create Date      : 2021/6/5 by zzh
**********************************************************************************/
void esp8266_start_trans(void)
{
   
	int i=0;
  while(esp_wifi_on_line(USART2_RX_BUF))
	{
   
			i++;
		  if(i==5)
			{
   
			LY_Printf("err");
			printf("\r\nAT指令输入有误,重新输入\r\n");
			USART2_RX_BUF[0]='\0';
			i=0;
			}
	}
	//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
	i=0;
	while(esp_work_pattern(USART2_RX_BUF))
	{
   
	    i++;
		  if(i==5)
			{
   
			LY_Printf("err");
			printf("\r\nAT指令输入有误,重新输入\r\n");
			USART2_RX_BUF[0]='\0';
			i=0;
			}
	}
	//Wifi模块重启
	i=0;
  esp_restart(USART2_RX_BUF);

	//设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据您自己的路由器设置进行修改!! 
	
	//esp设置连接模式
	i=0;
  while(esp_Connection_mode(USART2_RX_BUF))
	{
   
		  
			i++;
		
		  if(i==5)
			{
   
			LY_Printf("err");
			printf("\r\nAT指令输入有误,重新输入\r\n");
			USART2_RX_BUF[0]='\0';
			i=0;
			}
	}
	
	//连接目标路由器,并且获得IP
	i=0;
  while(esp_link_WIFI(USART2_RX_BUF))			
	{
   
			i++;
		  printf("\r\n%d\r\n",i);
		  if(i==5)
			{
   
			LY_Printf("err");
			printf("\r\nAT指令输入有误,重新输入\r\n");
			USART2_RX_BUF[0]='\0';
			i=0;
			}
	}		
}
//检查WIFI模块是否在线
bool esp_wifi_on_line(char *at)
{
   
	printf("检查WIFI模块是否在线\r\n");	
	while(USART2_RX_BUF[0]=='\0')
	{
   
	}	
  
	delay_ms(1000);
  return esp8266_send_cmd(at,"OK",20);		//检查WIFI模块是否在线	
	
}

//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式
bool esp_work_pattern(char *at)
{
   
	printf("\r\n设置工作模式\r\n");	
	while(USART2_RX_BUF[0]=='\0')
	{
   
	}	
	
	delay_ms(1000);
	return esp8266_send_cmd(at,"OK",50);;	
}
//esp重启
bool esp_restart(char *at)
{
   
	printf("\r\nesp重启\r\n");	
	while(USART2_RX_BUF[0]=='\0')
	{
   
	}
	esp8266_send_cmd(at,"OK",20);	//延时4S等待重启成功
	delay_ms(1000);	
	delay_ms(1000);	
	delay_ms(1000);	
	delay_ms(1000);	
	USART2_RX_BUF[0]='\0';
	//Wifi模块重启	
	LY_Printf("OK");
	return 1;
}
//esp设置连接模式
bool esp_Connection_mode(char *at)
{
    
	printf("\r\n设置连接模式\r\n");	
	while(USART2_RX_BUF[0]=='\0')
	{
   
	}	
	return esp8266_send_cmd(at,"OK",20);   		//0:单连接,1:多连接		;	
}
//esp连接wifi
bool esp_link_WIFI(char *at)
{
    
	printf("\r\nesp连接wifi\r\n");	
	while(USART2_RX_BUF[0]=='\0')
	{
   
	}
	return esp8266_send_cmd(at,"WIFI GOT IP",300);									//连接目标路由器,并且获得IP;
  delay_ms(1000);	
	
}


/*********************************************************************************
* Function Name    : esp8266_send_cmd,向ESP8266发送命令
* Parameter		   : cmd:发送的命令字符串;ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
* Return Value     : 返回值:0,发送成功(得到了期待的应答结果);1,发送失败
* Function Explain : 
* Create Date      : 2021/6/5 by zzh
**********************************************************************************/
u8 esp8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
   
	u8 res=0; 
	USART3_RX_STA=0;
	delay_ms(1000);
	u3_printf("%s\r\n",cmd);	//发送命令
	printf("发送命令了-->%s\r\n",cmd);
	if(ack&&waittime)		//需要等待应答
	{
   
		while(--waittime)	//等待倒计时
		{
   
			delay_ms(10);
			if(USART3_RX_STA&0X8000)//接收到期待的应答结果
			{
   
			  u8 *a=	esp8266_check_cmd(ack);
				if(esp8266_check_cmd(ack))
				{
   
					printf("receive:%s\r\n",(u8*)ack);
					LY_Printf(ack);
					USART2_RX_BUF[0]='\0';
					break;//得到有效数据 
				}
					USART3_RX_STA=0;
			} 
		}
		if(waittime==0)res=1; 
	}
	return res;
} 


/*********************************************************************************
* Function Name    : esp8266_check_cmd,ESP8266发送命令后,检测接收到的应答
* Parameter		   : str:期待的应答结果
* Return Value     : 返回值:0,没有得到期待的应答结果;其他,期待应答结果的位置(str的位置)
* Function Explain : 
* Create Date      : 2021/6/5 by zzh
**********************************************************************************/
u8* esp8266_check_cmd(u8 *str)
{
   
	char *strx=0;
	if(USART3_RX_STA&0X8000)		//接收到一次数据了
	{
    
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
		strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
	} 
	return (u8*)strx;
}


/*********************************************************************************
* Function Name    : esp8266_quit_trans,ATK-ESP8266退出透传模式
* Parameter		   : 
* Return Value     : 返回值:0,退出成功;1,退出失败
* Function Explain : 
* Create Date      : 2021/6/5 by zzh
**********************************************************************************/
u8 esp8266_quit_trans(void)
{
   
	while((USART3->SR&0X40)==0);	//等待发送空
	USART3->DR='+';      
	delay_ms(15);					//大于串口组帧时间(10ms)
	while((USART3->SR&0X40)==0);	//等待发送空
	USART3->DR='+';      
	delay_ms(15);					//大于串口组帧时间(10ms)
	while((USART3->SR&0X40)==0);	//等待发送空
	USART3->DR='+';      
	delay_ms(500);					//等待500ms
	printf("退出看透传模式\r\n");
	return esp8266_send_cmd("AT","OK",20);//退出透传判断.
}


/*********************************************************************************
* Function Name    : get_current_weather,获取一次实时天气
* Parameter		   : 
* Return Value     : 返回:0---获取成功,1---获取失败
* Function Explain : 
* Create Date      : 2021/6/5 by zzh
**********************************************************************************/
u8 get_current_weather(void)
{
   
	u8 res;

	p=mymalloc(SRAMIN,40);							//申请40字节内存
	
	
	sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",WEATHER_SERVERIP,WEATHER_PORTNUM);    //配置目标TCP服务器
//	printf("send:AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",WEATHER_SERVERIP,WEATHER_PORTNUM);
	res = esp8266_send_cmd(p,"OK",200);//连接到目标TCP服务器

	delay_ms(300);
	
	printf("send:AT+CIPMODE=1\r\n");	
	esp8266_send_cmd("AT+CIPMODE=1","OK",100);      //传输模式为:透传	

	USART3_RX_STA=0;
	printf("send:AT+CIPSEND\r\n");	
	esp8266_send_cmd("AT+CIPSEND","OK",100);         //开始透传
	printf("start trans...\r\n");

	u3_printf("GET https://api.seniverse.com/v3/weather/now.json?key=SBE-txu7v25szUfOf&location=XiAn&language=en&unit=c\n\n");	
	delay_ms(20);//延时20ms返回的是指令发送成功的状态
	USART3_RX_STA=0;	//清零串口3数据
	delay_ms(1000);
	if(USART3_RX_STA&0X8000)		//此时再次接到一次数据,为天气的数据
	{
    
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
	} 
	printf("USART3_RX_BUF=%s\r\n",USART3_RX_BUF);
	
	cJSON_WeatherParse(USART3_RX_BUF, results);		//解析天气数据
	//打印结构体内内容
	printf("打印结构体内内容如下: \r\n");
	printf("%s \r\n"
  • 8
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
以下是一个基于Keil5和STM32F407VE芯片,使用ESP8266模块连接到知心天气API获取天气信息的代码示例: ```c #include "stm32f4xx.h" #include <string.h> #include <stdio.h> #define SSID "your_SSID" // WiFi名称 #define PASSWORD "your_PASSWORD" // WiFi密码 #define API_KEY "your_API_KEY" // 知心天气API Key #define CITY_ID "your_CITY_ID" // 城市ID #define ESP8266_USART USART3 char esp8266RxBuffer[256]; // 接收缓冲区 uint8_t esp8266RxIndex = 0; void USART3_IRQHandler(void) { if (USART_GetITStatus(ESP8266_USART, USART_IT_RXNE) != RESET) { char ch = USART_ReceiveData(ESP8266_USART); esp8266RxBuffer[esp8266RxIndex++] = ch; if (ch == '\n' && esp8266RxIndex > 2 && esp8266RxBuffer[esp8266RxIndex - 2] == '\r') { esp8266RxBuffer[esp8266RxIndex - 2] = '\0'; } } } void ESP8266_SendCommand(char *command) { esp8266RxIndex = 0; USART_SendData(ESP8266_USART, '\r'); USART_SendData(ESP8266_USART, '\n'); while (USART_GetFlagStatus(ESP8266_USART, USART_FLAG_TXE) == RESET); while (*command) { USART_SendData(ESP8266_USART, *command++); while (USART_GetFlagStatus(ESP8266_USART, USART_FLAG_TXE) == RESET); } USART_SendData(ESP8266_USART, '\r'); USART_SendData(ESP8266_USART, '\n'); while (USART_GetFlagStatus(ESP8266_USART, USART_FLAG_TXE) == RESET); } void ESP8266_WaitResponse(char *response, uint32_t timeout) { uint32_t startTime = HAL_GetTick(); while (HAL_GetTick() - startTime < timeout) { if (strstr(esp8266RxBuffer, response)) { return; } } } void ESP8266_Init(void) { USART_InitTypeDef USART_InitStruct; GPIO_InitTypeDef GPIO_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3); GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3); USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(ESP8266_USART, &USART_InitStruct); NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStruct); USART_ITConfig(ESP8266_USART, USART_IT_RXNE, ENABLE); USART_Cmd(ESP8266_USART, ENABLE); } void ESP8266_ConnectWiFi(void) { ESP8266_SendCommand("AT+CWJAP=\"" SSID "\",\"" PASSWORD "\""); ESP8266_WaitResponse("OK", 5000); } void ESP8266_GetWeather(char *weather) { char command[128]; sprintf(command, "AT+HTTPGET=\"http://api.thinkpage.cn/v3/weather/now.json?key=%s&location=%s&language=zh-Hans&unit=c\"", API_KEY, CITY_ID); ESP8266_SendCommand(command); ESP8266_WaitResponse("HTTP/1.1 200 OK", 10000); char *p = strstr(esp8266RxBuffer, "{\"results\":[{"); if (p) { strcpy(weather, p); } } int main(void) { char weather[1024]; ESP8266_Init(); ESP8266_ConnectWiFi(); ESP8266_GetWeather(weather); printf("Weather: %s\r\n", weather); while (1); } ``` 需要注意的是,该示例代码中的`your_SSID`、`your_PASSWORD`、`your_API_KEY`和`your_CITY_ID`需要替换为你自己的信息。此外,该示例代码中使用的是串口3连接ESP8266模块,如果你的连接方式不同,需要相应地修改代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安赫'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值