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"