|
近期由于某些原因,玩了一下stm32+WiFi獲取網(wǎng)絡(luò)天氣和網(wǎng)絡(luò)時間。之前一直覺得這個東西會有點難度,其實,做完了才發(fā)現(xiàn),其實那只是想象中的難而已。現(xiàn)在,將這幾天的成果分享一下,做個學(xué)習(xí)記錄,也分享給有需要的伙伴。
有關(guān)原文鏈接如下:https://blog.csdn.net/weixin_43952192/article/details/106877400
在文末有改良好的代碼,問題肯定是有的,但是比之前,好很多,有需要的朋友可以自己下載。
上面鏈接給的代碼其實是有問題的,經(jīng)過測試,發(fā)現(xiàn)三點不足:1.RTC時鐘,僅僅只是RTC時間;2.程序運行一段時間后(三個小時內(nèi)),100%會死機(jī),因此基本可以判斷出,程序是有問題的具體原因不詳,貌似是堆棧溢出導(dǎo)致的;3.天氣更新情況,在沒有死機(jī)的情況下,看似是在更新,其實從串口調(diào)試助手可以看到,人機(jī)交互界面并沒有更新。
經(jīng)過改善,滿足了以下要求:1.開機(jī)獲取網(wǎng)絡(luò)時間,之后將會由這個時間借助RTC繼續(xù)運行;2.在測試的三個小時內(nèi)沒有再出現(xiàn)死機(jī)的情況;3.在測試的三個小時內(nèi),天氣每隔一段時間都會自動更新,并體現(xiàn)在LCD屏幕上。
一、測試要求(只說我用到的)
1.硬件:①stm32f103ZET6(我用的戰(zhàn)艦板,請用容量盡量大的模塊)②TFTLCD屏(我的是4.3寸)③ESP8266 WIFI串口模塊(串口3)④Jlink(程序燒錄)⑤串口線⑥路由器
2.軟件①keil5②串口調(diào)試助手
二、相關(guān)設(shè)置
**這里就不做過多的介紹,只做簡單的說明,有疑問請參考上面給出的鏈接。①WiFi串口模塊固件為AT固件②jlink需要安裝對應(yīng)的驅(qū)動,用于程序的調(diào)試和燒錄③串口也需要對應(yīng)的驅(qū)動,用于輸出調(diào)試信息
三、程序流程
其實簡單點說,就幾個步驟而已,我把他轉(zhuǎn)換成幾條AT指令,只需要按照下面步驟控制WiFi模塊,就可以獲取到網(wǎng)絡(luò)天氣和時間信息,如下:1.首先來看看獲取當(dāng)前天氣情況①AT ack:OK //判斷WiFi模塊是否存在以及是否支持AT指令②ATE0 ack: OK //取消回顯,可要可不要,為了方便接下來演示,這句我就不寫進(jìn)去了③AT+CWMODE=1 ack:OK //設(shè)置WiFi模塊為STA模式④AT+RST ack:OK //復(fù)位WiFi模塊⑥AT+CIPMUX=0 ack:OK //單連接模式⑦AT+CWJAP=“HUAWEI nova 5”,“b12345678” ack:WIFI GOT IP //連接熱點,對應(yīng)的是熱點名和熱點密碼,注意,務(wù)必等待該條指令返回WIFI GOT IP后再發(fā)送下面的指令⑧AT+CIPSTART=“TCP”,“api.seniverse.com”,80 ack:OK //建立TCP連接⑨AT+CIPMODE=1 ack:OK //透傳模式⑩AT+CIPSEND ack:OK //AT+CIPMODE=1并且作為客戶端模式下,進(jìn)入透傳模式(需要支持硬件流控,否則大量數(shù)據(jù)情況下會丟數(shù)據(jù))模塊收到指令后先換行返回”>”,然后會發(fā)送串口接收到的數(shù)據(jù)。
發(fā)送完上面的指令,并正確返回后,發(fā)送下面一串?dāng)?shù)據(jù)(不需要換行)- GET https://api.seniverse.com/v3/weather/now.json?key=SWaCmu3LmzT_kS21g&location=changsha&language=zh-Hans&unit=c
復(fù)制代碼 //發(fā)送獲取天氣信息的網(wǎng)址,記得前面的GET,不可少
最后,記得發(fā)送一條退出透傳的指令,否則后面AT指令將無法發(fā)送:AT+CIPCLOSE ack:OK
為了方便大家查看,我保存了串口調(diào)試助手發(fā)送指令以及模塊返回情況,如下圖:
1.png (61.27 KB, 下載次數(shù): 95)
下載附件
2020-11-24 16:20 上傳
上圖中,最后一行,就是發(fā)送指令聯(lián)網(wǎng)后返回來的一串字符串,有些是亂碼,亂碼部分其實就是中文,只不多串口沒有對應(yīng)的協(xié)議,沒辦法解析而已。這一串就是當(dāng)前天氣情況,也是我們需要解析的部分,中文部分,我們是需要把它轉(zhuǎn)換成utf8格式的(具體請看代碼),整個解析過程代碼(其實很簡單的)如下:
//解析當(dāng)前天氣
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); //獲取城市名稱轉(zhuǎn)換為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 //取消回顯,可要可不要,為了方便接下來演示,這句我就不寫進(jìn)去了③AT+CWMODE=1 ack:OK //設(shè)置WiFi模塊為STA模式④AT+RST ack:OK //復(fù)位WiFi模塊⑥AT+CIPMUX=0 ack:OK //單連接模式⑦AT+CWJAP=“HUAWEI nova 5”,“b12345678” ack:WIFI GOT IP //連接熱點,對應(yīng)的是熱點名和熱點密碼,注意,務(wù)必等待該條指令返回WIFI GOT IP后再發(fā)送下面的指令⑧AT+CIPSTART=“TCP”,“api.seniverse.com”,80 ack:OK //建立TCP連接⑨AT+CIPMODE=1 ack:OK //透傳模式⑩AT+CIPSEND ack:OK //AT+CIPMODE=1并且作為客戶端模式下,進(jìn)入透傳模式(需要支持硬件流控,否則大量數(shù)據(jù)情況下會丟數(shù)據(jù))模塊收到指令后先換行返回”>”,然后會發(fā)送串口接收到的數(shù)據(jù)。
完事之后,發(fā)送下面一串字符串,用于獲取未來三天天氣情況:- GET https://api.seniverse.com/v3/weather/daily.json?key=SWaCmu3LmzT_kS21g&location=changsha&language=zh-Hans&unit=c&start=0&days=5
復(fù)制代碼 最后,關(guān)閉透傳,發(fā)送和上面一樣的指令。
數(shù)據(jù)解析代碼如下:
//解析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); //獲取城市名稱轉(zhuǎn)換為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); //顯示風(fēng)速km/h
j = 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.獲取網(wǎng)絡(luò)時間套路類似的:①AT ack:OK //判斷WiFi模塊是否存在以及是否支持AT指令②ATE0 ack: OK //取消回顯,可要可不要,為了方便接下來演示,這句我就不寫進(jìn)去了③AT+CWMODE=1 ack:OK //設(shè)置WiFi模塊為STA模式④AT+RST ack:OK //復(fù)位WiFi模塊⑥AT+CIPMUX=0 ack:OK //單連接模式⑦AT+CWJAP=“HUAWEI nova 5”,“b12345678” ack:WIFI GOT IP //連接熱點,對應(yīng)的是熱點名和熱點密碼,注意,務(wù)必等待該條指令返回WIFI GOT IP后再發(fā)送下面的指令⑧AT+CIPSTART=“TCP”,“cgi.im.qq.com”,80 ack:OK //建立TCP連接⑨AT+CIPMODE=1 ack:OK //透傳模式⑩AT+CIPSEND ack:OK //AT+CIPMODE=1并且作為客戶端模式下,進(jìn)入透傳模式(需要支持硬件流控,否則大量數(shù)據(jù)情況下會丟數(shù)據(jù))模塊收到指令后先換行返回”>”,然后會發(fā)送串口接收到的數(shù)據(jù)。
發(fā)送完上面的指令后,發(fā)送下面一串字符GET http://cgi.im.qq.com
最后一樣,需要關(guān)閉透傳模式。
數(shù)據(jù)解析格式如下:
//獲取北京時間
u8 get_beijing_time(void)
{
u8 *p;
u8 res;
u8 *resp;
u8 *p_end;
// u8 ipbuf[16]; //IP緩存
p=mymalloc(SRAMIN,40); //申請40字節(jié)內(nèi)存
resp=mymalloc(SRAMIN,10);
p_end=mymalloc(SRAMIN,40);
sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",TIME_SERVERIP,TIME_PORTNUM); //配置目標(biāo)TCP服務(wù)器
res = atk_8266_send_cmd(p,"OK",200);//連接到目標(biāo)TCP服務(wù)器
if(res==1)
{
myfree(SRAMIN,p);
return 1;
}
delay_ms(300);
atk_8266_send_cmd("AT+CIPMODE=1","OK",100); //傳輸模式為:透傳
printf("設(shè)備 %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-->GMT8
nwt.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); //關(guān)閉連接
myfree(SRAMIN,p);
myfree(SRAMIN,resp);
myfree(SRAMIN,p_end);
return 0;
}
最后附上代碼,請自行下載,謝謝。
51hei.png (9.33 KB, 下載次數(shù): 111)
下載附件
2020-11-24 16:27 上傳
全部資料51hei下載地址:
程序源碼-天氣+時間GUI.7z
(6.76 MB, 下載次數(shù): 440)
2020-11-24 16:28 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|
評分
-
查看全部評分
|