stm32 + ESP8266 wifi获取网络时间和天气 stm32天气预报
大家遇到什么什么题,可以私聊我。
近期由于某些原因,玩了一下stm32+WiFi获取网络天气和网络时间。之前一直觉得这个东西会有点难度,其实,做完了才发现,其实那只是想象中的难而已。现在,将这几天的成果分享一下,做个学习记录,也分享给有需要的伙伴。
有关原文链接如下:
原文地址
在文末有改良好的代码,问题肯定是有的,但是比之前,好很多,有需要的朋友可以自己下载。
上面链接给的代码其实是有问题的,经过测试,发现三点不足:
1.RTC时钟,仅仅只是RTC时间;
2.程序运行一段时间后(三个小时内),100%会死机,因此基本可以判断出,程序是有问题的具体原因不详,貌似是堆栈溢出导致的;
3.天气更新情况,在没有死机的情况下,看似是在更新,其实从串口调试助手可以看到,人机交互界面并没有更新。
经过改善,满足了以下要求:
1.开机获取网络时间,之后将会由这个时间借助RTC继续运行;
2.在测试的三个小时内没有再出现死机的情况;
3.在测试的三个小时内,天气每隔一段时间都会自动更新,并体现在LCD屏幕上。
一、测试要求(只说我用到的)
1.硬件:
①stm32f103ZET6(我用的战舰板,请用RAM容量尽量大的芯片)②TFTLCD屏(我的是4.3寸)③ESP8266 WIFI串口模块(串口3)④Jlink(程序烧录)⑤串口线⑥路由器
2.软件
①keil5
②串口调试助手
二、相关设置
这里就不做过多的介绍,只做简单的说明,有疑问请参考上面给出的链接。
①WiFi串口模块固件为AT固件
②jlink需要安装对应的驱动,用于程序的调试和烧录
③串口也需要对应的驱动,用于输出调试信息
三、程序流程
其实简单点说,就几个步骤而已,我把他转换成几条AT指令,只需要按照下面步骤控制WiFi模块,就可以获取到网络天气和时间信息,如下:
1.首先来看看获取当前天气情况
①AT ack:OK //判断WiFi模块是否存在以及是否支持AT指令
②ATE0 ack: OK //取消回显,可要可不要,为了方便接下来演示,这句我就不写进去了
③AT+CWMODE=1 ack:OK //设置WiFi模块为STA模式
④AT+RST ack:OK //复位WiFi模块
⑥AT+CIPMUX=0 ack:OK //单连接模式
⑦AT+CWJAP="HUAWEI nova 5","b12345678" ack:WIFI GOT IP //连接热点,对应的是热点名和热点密码,注意,务必等待该条指令返回WIFI GOT IP后再发送下面的指令
⑧AT+CIPSTART="TCP","api.seniverse.com",80 ack:OK //建立TCP连接
⑨AT+CIPMODE=1 ack:OK //透传模式
⑩AT+CIPSEND ack:OK //AT+CIPMODE=1并且作为客户端模式下,进入透传模式(需要支持硬件流控,否则大量数据情况下会丢数据)模块收到指令后先换行返回”>”,然后会发送串口接收到的数据。
发送完上面的指令,并正确返回后,发送下面一串数据(不需要换行)
GET https://api.seniverse.com/v3/weather/now.json?key=SWaCmu3LmzT_kS21g&location=changsha&language=zh-Hans&unit=c
//发送获取天气信息的网址,记得前面的GET,不可少
最后,记得发送一条退出透传的指令,否则后面AT指令将无法发送:
+++(不需要换行,也不要有空格)
AT+CIPCLOSE ack:OK
为了方便大家查看,我保存了串口调试助手发送指令以及模块返回情况,如下图:
上图中,最后一行,就是发送指令联网后返回来的一串字符串,有些是乱码,乱码部分其实就是中文,只不多串口没有对应的协议,没办法解析而已。这一串就是当前天气情况,也是我们需要解析的部分,中文部分,我们是需要把它转换成utf8格式的(具体请看代码),整个解析过程代码(其实很简单的)如下:
//解析当前天气
void parse_now_weather(void)
{u16 i = 0,j = 0,line = 0;int len = 0;char gbkstr[50] = {0};Now_Weather *weather_Structure = mymalloc(SRAMIN,sizeof(Now_Weather));printf("jieshou->1dayjson = %s\r\n",USART3_RX_BUF);for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 'n' && USART3_RX_BUF[i+1] == 'a' && USART3_RX_BUF[i+2] == 'm' && USART3_RX_BUF[i+3] == 'e'){while(USART3_RX_BUF[i+7] != '"')weather_Structure->m_CityName[j++] = USART3_RX_BUF[7+(i++)];weather_Structure->m_CityName[j] = '\0';break;}}SwitchToGbk((const u8*)weather_Structure->m_CityName,strlen(weather_Structure->m_CityName),(u8 *)gbkstr,&len); //获取城市名称转换为gbk文件if(strstr(gbkstr,"衡阳") != NULL)LCD_ShowString(0,20,sizeof("hengyang")*8,16,16,"hengyang");else if(strstr(gbkstr,"长沙") != NULL) LCD_ShowString(0,140,sizeof("changsha")*8,16,16,"changsha");j = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 't' && USART3_RX_BUF[i+1] == 'e' && USART3_RX_BUF[i+2] == 'x' && USART3_RX_BUF[i+3] == 't'){while(USART3_RX_BUF[i+7] != '"')weather_Structure->m_Text[j++] = USART3_RX_BUF[7+(i++)];weather_Structure->m_Text[j] = '\0';break;}}memset(gbkstr,0,sizeof(gbkstr));if(flag == 1) line = 160;//长沙else if(flag == 2) line = 40;//衡阳SwitchToGbk((const u8*)weather_Structure->m_Text,strlen(weather_Structure->m_Text),(u8 *)gbkstr,&len);if(strstr(gbkstr,"阴") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"overcast ");else if(strstr(gbkstr,"多云") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"cloudy ");else if(strstr(gbkstr,"晴") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"fine day ");else if(strstr(gbkstr,"小雨") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"light rain ");else if(strstr(gbkstr,"中雨") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"moderate rain ");else if(strstr(gbkstr,"大雨") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"heavy rain ");else if(strstr(gbkstr,"雷阵雨") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"thunder shower");else if(strstr(gbkstr,"阵雨") != NULL)LCD_ShowString(88,line,sizeof("overcast ")*8,16,16,"shower ");j = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 't' && USART3_RX_BUF[i+1] == 'e' && USART3_RX_BUF[i+2] == 'm' && USART3_RX_BUF[i+3] == 'p'){while(USART3_RX_BUF[i+14] != '"')weather_Structure->m_Temp[j++] = USART3_RX_BUF[14+(i++)];weather_Structure->m_Temp[j] = '\0';break;}}if(flag == 1) line = 220;//长沙else if(flag == 2) line = 100;//衡阳LCD_ShowString(100,line,25,20,16,(u8*)weather_Structure->m_Temp); printf("wendu = %s\r\n",weather_Structure->m_Temp);j = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 'l' && USART3_RX_BUF[i+1] == 'a' && USART3_RX_BUF[i+2] == 's' && USART3_RX_BUF[i+3] == 't'){while(USART3_RX_BUF[i+14] != '"')weather_Structure->m_LastUpdataTime[j++] = USART3_RX_BUF[14+(i++)];weather_Structure->m_LastUpdataTime[j] = '\0';break;}}if(flag == 1) line = 140;else if(flag == 2)line = 20;LCD_ShowString(210,line,200,20,16,(u8*)weather_Structure->m_LastUpdataTime);printf("1day_updata_time = %s\r\n",(u8*)weather_Structure->m_LastUpdataTime);myfree(SRAMIN,weather_Structure);
}
2.未来三天天气情况:
和上面类似的,我就不演示了,直接上AT指令:
①AT ack:OK //判断WiFi模块是否存在以及是否支持AT指令
②ATE0 ack: OK //取消回显,可要可不要,为了方便接下来演示,这句我就不写进去了
③AT+CWMODE=1 ack:OK //设置WiFi模块为STA模式
④AT+RST ack:OK //复位WiFi模块
⑥AT+CIPMUX=0 ack:OK //单连接模式
⑦AT+CWJAP="HUAWEI nova 5","b12345678" ack:WIFI GOT IP //连接热点,对应的是热点名和热点密码,注意,务必等待该条指令返回WIFI GOT IP后再发送下面的指令
⑧AT+CIPSTART="TCP","api.seniverse.com",80 ack:OK //建立TCP连接
⑨AT+CIPMODE=1 ack:OK //透传模式
⑩AT+CIPSEND ack:OK //AT+CIPMODE=1并且作为客户端模式下,进入透传模式(需要支持硬件流控,否则大量数据情况下会丢数据)模块收到指令后先换行返回”>”,然后会发送串口接收到的数据。
完事之后,发送下面一串字符串,用于获取未来三天天气情况:
GET https://api.seniverse.com/v3/weather/daily.json?key=SWaCmu3LmzT_kS21g&location=changsha&language=zh-Hans&unit=c&start=0&days=5
最后,关闭透传,发送和上面一样的指令。
数据解析代码如下:
//解析3天天气
void parse_3days_weather(void)
{u16 i = 0,j = 0,line = 0;int len = 0;char gbkstr[50] = {0};Now_Weather *weather_Structure = mymalloc(SRAMIN,sizeof(Now_Weather));printf("jieshou->1dayjson = %s\r\n",USART3_RX_BUF);for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 'w' && USART3_RX_BUF[i+1] == 'i' && USART3_RX_BUF[i+2] == 'n' && USART3_RX_BUF[i+3] == 'd'){while(USART3_RX_BUF[i+17] != '"')weather_Structure->m_WindDir[j++] = USART3_RX_BUF[17+(i++)];weather_Structure->m_WindDir[j] = '\0';break;}}SwitchToGbk((const u8*)weather_Structure->m_WindDir,strlen(weather_Structure->m_WindDir),(u8 *)gbkstr,&len); //获取城市名称转换为gbk文件if(flag == 1) line = 200;//长沙else if(flag == 2) line = 80;//衡阳LCD_Fill(220,45,320,61,BLACK);if(strstr(gbkstr,"北") != NULL) {if(strstr(gbkstr,"西") != NULL) LCD_ShowString(0,line,sizeof("southerly ")*8,16,16,"Northwest wind ");else if(strstr(gbkstr,"东") != NULL) LCD_ShowString(0,line,sizeof("southerly ")*8,16,16,"Northeastern wind"); else LCD_ShowString(0,line,sizeof("southerly ")*8,16,16,"northerly ");}else if(strstr(gbkstr,"南") != NULL) {if(strstr(gbkstr,"西") != NULL) LCD_ShowString(0,line,sizeof("southerly ")*8,16,16,"Southwest wind ");else if(strstr(gbkstr,"东") != NULL) LCD_ShowString(0,line,sizeof("southerly ")*8,16,16,"Southeast wind ");else LCD_ShowString(0,line,sizeof("southerly ")*8,16,16,"southerly ");}j = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 's' && USART3_RX_BUF[i+1] == 'p' && USART3_RX_BUF[i+2] == 'e' && USART3_RX_BUF[i+3] == 'e'){while(USART3_RX_BUF[i+8] != '"')weather_Structure->m_WindSpeed[j++] = USART3_RX_BUF[8+(i++)];weather_Structure->m_WindSpeed[j] = '\0';break;}}LCD_ShowString(200,line,sizeof(weather_Structure->m_WindSpeed)*8,16,16,(u8 *)weather_Structure->m_WindSpeed); //显示风速km/hj = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 's' && USART3_RX_BUF[i+1] == 'c' && USART3_RX_BUF[i+2] == 'a' && USART3_RX_BUF[i+3] == 'l'){while(USART3_RX_BUF[i+8] != '"')weather_Structure->m_WindGrade[j++] = USART3_RX_BUF[8+(i++)];weather_Structure->m_WindGrade[j] = '\0';break;}}LCD_ShowString(160,line,sizeof(weather_Structure->m_WindGrade)*8,16,16,(u8 *)weather_Structure->m_WindGrade);j = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 'h' && USART3_RX_BUF[i+1] == 'u' && USART3_RX_BUF[i+2] == 'm' && USART3_RX_BUF[i+3] == 'i'){while(USART3_RX_BUF[i+11] != '"')weather_Structure->m_Humi[j++] = USART3_RX_BUF[11+(i++)];weather_Structure->m_Humi[j] = '\0';break;}}if(flag == 1) line = 220;//长沙else if(flag == 2) line = 100;//衡阳LCD_ShowString(160,line,sizeof(weather_Structure->m_Humi)*8,16,16,(u8 *)weather_Structure->m_Humi);j = 0;for(i = 0; i < strlen((char *)USART3_RX_BUF); i++){if(USART3_RX_BUF[i] == 'l' && USART3_RX_BUF[i+1] == 'a' && USART3_RX_BUF[i+2] == 's' && USART3_RX_BUF[i+3] == 't'){while(USART3_RX_BUF[i+14] != '"')weather_Structure->m_LastUpdataTime[j++] = USART3_RX_BUF[14+(i++)];weather_Structure->m_LastUpdataTime[j] = '\0';break;}}LCD_ShowString(0,300,200,20,12,(u8*)weather_Structure->m_LastUpdataTime);printf("1day_updata_time = %s\r\n",(u8*)weather_Structure->m_LastUpdataTime);myfree(SRAMIN,weather_Structure);
}
3.获取网络时间
套路类似的:
①AT ack:OK //判断WiFi模块是否存在以及是否支持AT指令
②ATE0 ack: OK //取消回显,可要可不要,为了方便接下来演示,这句我就不写进去了
③AT+CWMODE=1 ack:OK //设置WiFi模块为STA模式
④AT+RST ack:OK //复位WiFi模块
⑥AT+CIPMUX=0 ack:OK //单连接模式
⑦AT+CWJAP="HUAWEI nova 5","b12345678" ack:WIFI GOT IP //连接热点,对应的是热点名和热点密码,注意,务必等待该条指令返回WIFI GOT IP后再发送下面的指令
⑧AT+CIPSTART="TCP","cgi.im.qq.com",80 ack:OK //建立TCP连接
⑨AT+CIPMODE=1 ack:OK //透传模式
⑩AT+CIPSEND ack:OK //AT+CIPMODE=1并且作为客户端模式下,进入透传模式(需要支持硬件流控,否则大量数据情况下会丢数据)模块收到指令后先换行返回”>”,然后会发送串口接收到的数据。
发送完上面的指令后,发送下面一串字符
GET http://cgi.im.qq.com
最后一样,需要关闭透传模式。
数据解析格式如下:
//获取北京时间
u8 get_beijing_time(void)
{u8 *p;u8 res;u8 *resp;u8 *p_end;
// u8 ipbuf[16]; //IP缓存p=mymalloc(SRAMIN,40); //申请40字节内存resp=mymalloc(SRAMIN,10);p_end=mymalloc(SRAMIN,40);sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",TIME_SERVERIP,TIME_PORTNUM); //配置目标TCP服务器res = atk_8266_send_cmd(p,"OK",200);//连接到目标TCP服务器if(res==1){myfree(SRAMIN,p);return 1;}delay_ms(300);atk_8266_send_cmd("AT+CIPMODE=1","OK",100); //传输模式为:透传 printf("设备 %s\r\n",p);CLR_BUF();atk_8266_send_cmd("AT+CIPSEND","OK",100); //开始透传printf("start trans...\r\n");u3_printf("GET http://cgi.im.qq.com\n\n");delay_ms(20);CLR_BUF(); delay_ms(1000);if(USART3_RX_STA != 0){strncpy((char *)resp,"Date",5);USART3_RX_BUF[USART3_RX_STA] = 0;//printf("get_tim_srt:%s\r\n",USART3_RX_BUF);if(strstr((char*)USART3_RX_BUF,(char*)resp)) { strncpy((char *)resp,"GMT",4);p_end = (u8*)strstr((char*)USART3_RX_BUF,(char*)resp);p = p_end - 9; //printf("get_net_str %s\r\n",p);nwt.hour = ((*p - 0x30)*10 + (*(p+1) - 0x30) + 8) % 24; //GMT0-->GMT8nwt.min = ((*(p+3) - 0x30)*10 + (*(p+4) - 0x30)) % 60;nwt.sec = ((*(p+6) - 0x30)*10 + (*(p+7) - 0x30)) % 60;nwt.year = ((*(p-5) - 0x30)*1000 + (*(p-4) - 0x30)*100+ (*(p-3) - 0x30)*10+ (*(p-2) - 0x30)); nwt.date = ((*(p-12) - 0x30)*10 + (*(p-11) - 0x30)); if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Jan")) nwt.month=1; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Feb")) nwt.month=2; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Mar")) nwt.month=3; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Apr")) nwt.month=4; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "May")) nwt.month=5; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Jun")) nwt.month=6; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Jul")) nwt.month=7; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Aug")) nwt.month=8; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Sep")) nwt.month=9; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Oct")) nwt.month=10; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Nov")) nwt.month=11; else if ((u8*)strstr((char*)USART3_RX_BUF,(char*) "Dec")) nwt.month=12;CLR_BUF();printf("uddate:nettime!!!");RTC_Set(nwt.year,nwt.month ,nwt.date ,nwt.hour ,nwt.min,nwt.sec); }CLR_BUF(); } atk_8266_quit_trans();//退出透传atk_8266_send_cmd("AT+CIPCLOSE","OK",50); //关闭连接myfree(SRAMIN,p);myfree(SRAMIN,resp);myfree(SRAMIN,p_end);return 0;
}
最后附上代码,请自行下载,谢谢:
代码资料
stm32 + ESP8266 wifi获取网络时间和天气 stm32天气预报相关推荐
- esp32获取网络时间和天气
@[esp32获取网络时间和天气] esp32获取网络时间和天气 目录 一.库的获取 二.esp32连接wifi 三.oled显示 四.汉字或图片取模放在oled中显示 五.esp32获取网络时间 六 ...
- ESP32通过WIFI获取网络时间
title: ESP32通过WIFI获取网络时间 一.这里首先要知道esp32的wifi如何连接,才能获取到网络服务器的时间 不知道wifi怎么连接的这里有相关链接--esp32wifi连接网络 二. ...
- 【STM32训练—WiFi模块】第一篇、STM32驱动ESP8266WiFi模块获取网络时间
目录 第一部分.写在前面 1.硬件准备 2.相关的AT指令 3.参考博客 第二部分.电脑串口助手调试ESP8266模块获取网络时间 1.ESP8266获取时间的流程 2.具体实现步骤 第三部分.STM ...
- ESP8266+STM32获取网络时间、OLED显示时间图片视频。
学习过程不易,发文共享以下学习过程~ 先说说我的设计内容的组成: 目录 学习过程不易,发文共享以下学习过程~ 1. STM32控制ESP8266获取网络时间 第一步:电脑控制ESP8266获取时间数据 ...
- esp8266获取网络时间
esp8266获取网络时间 我们使用的手机都有 "使用网络上的时间,自动调整日期和时间" 的功能.如果我们自己做的电子时钟也有自动调整时间的功能,那就很方便,而且不怕时间不准了. ...
- ESP8266获取网络时钟、天气
硬件平台 正点原子ESP8266 前提 烧录到ESP8266的固件版本不要太老了,用比较新的(具体界限不清楚) 以安信可官网提供的AT固件举例,第5个不支持获取网络时间(AT指令不支持),我用的是第4 ...
- CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC
CUBEMX配置STM32实现FTP文件传输以及使用SNTP获取网络时间并写入RTC 引言 FTP代码库的移植 Cubemx配置SNTP以及RTC RTC配置方法 SNTP配置方法 FATFS载入RT ...
- Arduino ESP32 获取网络时间并同步本地RTC时钟
Arduino ESP32 获取网络时间并同步本地RTC时钟 相关篇<Arduino ESP32 最简单直接获取网络时间方法> 在 ArduinoESP32核心支持库当中已经包含相关的获取 ...
- 51单片机利用8266获取网络时间
51单片机利用8266获取网络时间 我现在是成都一所不出名的二本院校大三学生,第一次来到CSDN,趁有时间,把我之前做的项目,其中一个模块拿出来和大家分享,我也是小白,希望提出宝贵意见.OK,废话不多 ...
最新文章
- 2021年大数据Kafka(十二):❤️Kafka配额限速机制❤️
- 用好 Spring AOP,天降大锅从容应对!
- 宅家学习秘密武器!让时间从视频流和朋友圈中回到程序员的视野中吧!
- sql server操作案例
- docker项目部署 php_「Docker部署PHP+Vue项目」- 海风纷飞Blog
- 【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展
- Spring Security(02)——关于登录
- 加密狗工作原理和破解方法简介
- scrapy 官方中文文档地址
- kaptcha配置java_java之kaptcha验证码
- 【淘宝静态页面HTML部分】
- python定时发送qq消息_自动给qq好友发消息
- 微信文章排版技巧和相关排版工具
- java国际化之时区问题处理
- Python 小写数字转为大写
- 某版本瑞数解决方案-爬虫
- 【学习笔记】SQL数据库
- pygame教程实例(四)小球弹跳(事件)
- 国内5款优秀的WEB前端框架
- 小强升职记:时间管理故事书