气象站"/>
基于STM32的家庭气象站
本文同步发布于个人博客
项目地址
Maskbugzero/ESP8266-Weather-2021
一个关于STM32+ESP8266+DHT11的家庭气象站。
硬件资源
- 战舰V3\精英STM32F103开发板
- ALIENTEK 2.8/3.5/4.3/7寸TFTLCD模块(通过FSMC驱动.FSMC_NE4接LCD片选/A10接RS)
- 按键KEY0(PE4)/KEY1(PE3)/KEY_UP(PA0.也称之为WK_UP)
- ESP8266-12S WIFI模块1个
- DHT11模块1个
实现功能
- 微信小程序配网
- 室内温湿度测量及显示
- 室外天气数据获取及显示
- 时间显示及网络校准
连接方式
- 模块与带有无线网卡的电脑或其他wifi设备连接:采用wifi连接
- 模块与开发板连接:TTL串口方式
ATK-ESP8266 WIFI模块与精英板连接方式
TXD<------------>PB11
RXD<------------>PB10
GND<------------>GND
VCC<------------>3.3V\5V
DHT11模块与精英板连接方式
Data<------------>PE11
主要代码
外设初始化
初始化外设时,若DHT11工作不正常则显示屏无法正常显示。
LED_Init(); //初始化与LED连接的硬件接口KEY_Init(); //初始化按键LCD_Init(); //初始化LCD RTC_Init();while(DHT11_Init()) //DHT11初始化 {printf("DHT11 出错!\r\n");delay_ms(200);}W25QXX_Init(); //初始化W25Q128tp_dev.init(); //初始化触摸屏usart3_init(115200); //初始化串口3 my_mem_init(SRAMIN); //初始化内部内存池exfuns_init(); //为fatfs相关变量申请内存 f_mount(fs[0],"0:",1); //挂载SD卡 f_mount(fs[1],"1:",1); //挂载FLASH.
微信小程序配网
源码:
//一键配网设置
u8 atk_8266_wifi_config(void)
{int i;while(atk_8266_send_cmd("AT","OK",20))//检查WIFI模块是否在线{atk_8266_quit_trans();//退出透传atk_8266_send_cmd("AT+CIPMODE=0","OK",200); //关闭透传模式 printf("未检测到模块!!!");delay_ms(800);printf("尝试连接模块..."); } u3_printf("AT+RESTORE"); //恢复出厂设置delay_ms(1000); //延时3S等待恢复成功delay_ms(1000);delay_ms(1000);printf("恢复出厂设置完成"); atk_8266_send_cmd("AT+RST","OK",20); //软重启delay_ms(1000); //延时3S等待重启成功delay_ms(1000);delay_ms(1000);delay_ms(1000);printf("软重启完成");while(atk_8266_send_cmd("ATE0","OK",20));//关闭回显atk_8266_send_cmd("AT+CWMODE=1","OK",50); //设置WIFI STA模式atk_8266_send_cmd("AT+CWAUTOCONN=1","OK",20); //使能上电自动连接APdelay_ms(300);atk_8266_send_cmd("AT+CWSTARTSMART=3","OK",20); //支持ESP-Touch和Airkiss智能配网printf("智能配网已开启 等待30s\r\n");while(i<=30){delay_ms(1000); //延时30S等待配网成功i++;}
// while(atk_8266_check_cmd("smartconfig connected wifi")); //连接目标路由器,并且获得IP
// delay_ms(300);atk_8266_send_cmd("AT+CWSTOPSMART","OK",20); //释放快连所占的内存return 0;
}
数据解析
天气数据
源码:(以当天天气数据为例,近3天天气数据类似)
//解析当前天气
u8 parse_now_weather(void)
{cJSON *root;cJSON *pSub;cJSON *arrayItem;cJSON *pItem;cJSON *pSubItem;cJSON *pChildItem;char *pr,*utf8str,*gbkstr;u8 size = 0;int len;u8 res;u8 temperature;root = mymalloc(SRAMIN,sizeof(cJSON));pSub = mymalloc(SRAMIN,sizeof(cJSON));pItem = mymalloc(SRAMIN,sizeof(cJSON));pSubItem = mymalloc(SRAMIN,sizeof(cJSON));pChildItem = mymalloc(SRAMIN,sizeof(cJSON));arrayItem = mymalloc(SRAMIN,sizeof(cJSON));pr = mymalloc(SRAMIN,1000);utf8str = mymalloc(SRAMIN,50);gbkstr = mymalloc(SRAMIN,50);memset(pr,0,1000);memset(gbkstr,0,50);memset(utf8str,0,50);file = mymalloc(SRAMIN,sizeof(FIL));res=f_open(file,(const TCHAR*)APP_ASCII_5427,FA_READ);//打开文件if(res==FR_OK){asc2_5427 = mymalloc(SRAMIN,file->fsize);if(asc2_5427 != NULL){res = f_read(file,asc2_5427,file->fsize,&br);}f_close(file);}printf("jieshou->1dayjson = %s\r\n",USART3_RX_BUF);root = cJSON_Parse((const char*)USART3_RX_BUF);if(root != NULL){pSub = cJSON_GetObjectItem(root,"results");if(pSub != NULL){
// size = cJSON_GetArraySize(pSub);arrayItem = cJSON_GetArrayItem(pSub,0); pr = cJSON_Print(arrayItem); //获取jsom数组pItem = cJSON_Parse(pr); //对数组,进行升级。if(pItem != NULL){pSubItem = cJSON_GetObjectItem(pItem,"location");if(pSubItem != NULL){pChildItem = cJSON_GetObjectItem(pSubItem,"name");if(pChildItem != NULL){utf8str = pChildItem->valuestring;SwitchToGbk((const u8*)utf8str,strlen(utf8str),(u8 *)gbkstr,&len); //获取城市名称转换为gbk文件Show_Str(0,0,lcddev.width,lcddev.height,(u8 *)gbkstr,16,0); //显示城市名称。}}memset(utf8str,0,50); //解决阴华memset(gbkstr,0,50);pSubItem = cJSON_GetObjectItem(pItem,"now");if(pSubItem != NULL){pChildItem = cJSON_GetObjectItem(pSubItem,"text"); //获取天气信息。多云if(pChildItem != NULL){utf8str = pChildItem->valuestring;SwitchToGbk((const u8*)utf8str,strlen(utf8str),(u8 *)gbkstr,&len);Show_Str(220,25,lcddev.width,lcddev.height,(u8 *)gbkstr,16,0); //显示多云}memset(utf8str,0,50);memset(gbkstr,0,50);pChildItem = cJSON_GetObjectItem(pSubItem,"code"); //获取气象代码if(pChildItem != NULL){gbkstr = pChildItem->valuestring;show_weather_icon((u8 *)gbkstr,0); //根据气象代码,更新图片}memset(gbkstr,0,50);pChildItem = cJSON_GetObjectItem(pSubItem,"temperature"); //获取温度信息if(pChildItem != NULL){gbkstr = pChildItem->valuestring;temperature = str2int((u8 *)gbkstr);gui_show_num(140,22,2,RED,54,temperature,0x80);printf("wendu = %d\r\n",temperature);}}pSubItem = cJSON_GetObjectItem(pItem,"last_update");if(pSubItem != NULL) {gbkstr =pSubItem->valuestring;LCD_ShowString(0,92,200,20,12,(u8*)gbkstr);printf("1day_updata_time = %s\r\n",(u8*)gbkstr);}}cJSON_Delete(pItem);}}cJSON_Delete(root);myfree(SRAMIN,root);myfree(SRAMIN,pSub);myfree(SRAMIN,pItem);myfree(SRAMIN,pSubItem);myfree(SRAMIN,pChildItem);myfree(SRAMIN,arrayItem);myfree(SRAMIN,pr);myfree(SRAMIN,utf8str);myfree(SRAMIN,gbkstr);myfree(SRAMIN,file);myfree(SRAMIN,asc2_5427);return 0;
}
时间数据获取和校准
源码:
u8 get_beijing_time(void)
{u8 *p;u8 res;u8 *resp;u8 *p_end;// u8 ipbuf[16]; //IP缓存p=mymalloc(SRAMIN,40); //申请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); //传输模式为:透传
// atk_8266_get_wanip(ipbuf);//获取WAN IPUSART3_RX_STA=0;atk_8266_send_cmd("AT+CIPSEND","OK",100); //开始透传printf("start trans...\r\n");u3_printf("GET /?app=life.time&appkey=58173&sign=4e67ab8533b30580e584c8b9f0a6cc50&format=json\n\n"); delay_ms(20);//延时20ms返回的是指令发送成功的状态
// atk_8266_at_response(1);USART3_RX_STA=0; //清零串口3数据delay_ms(1000);
// atk_8266_at_response(0);if(USART3_RX_STA&0X8000) //此时再次接到一次数据,为时间的数据{ USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符} resp="datetime_2";p_end = (u8*)strstr((char*)USART3_RX_BUF,(char*)resp);p = p_end-11; //确定串口数据中时间的起止位,如"datetime_1":"2021-03-31 20:09:07","datetime_2":"2021 中nwt.hour = ((*p - 0x30)*10 + (*(p+1) - 0x30)); nwt.min = ((*(p+3) - 0x30)*10 + (*(p+4) - 0x30));nwt.sec = ((*(p+6) - 0x30)*10 + (*(p+7) - 0x30));nwt.year = ((*(p-11) - 0x30)*1000 + (*(p-10) - 0x30)*100+ (*(p-9) - 0x30)*10+ (*(p-8) - 0x30)); nwt.month = ((*(p-6) - 0x30)*10 + (*(p-5) - 0x30));nwt.date = ((*(p-3) - 0x30)*10 + (*(p-2) - 0x30));
//使用指针方法获取时分秒年月日 RTC_Set(nwt.year,nwt.month ,nwt.date ,nwt.hour ,nwt.min,nwt.sec); //使用RTC函数设置时间 printf("nwt.year = %d\r\n",nwt.year);printf("nwt.month = %d\r\n",nwt.month);printf("nwt.date = %d\r\n",nwt.date);printf("nwt.hour = %d\r\n",nwt.hour);printf("nwt.min = %d\r\n",nwt.min);printf("nwt.sec = %d\r\n",nwt.sec);// 打印时分秒年月日数据// parse_now_time();// Cjson方法解析时间数据atk_8266_quit_trans();//退出透传atk_8266_send_cmd("AT+CIPCLOSE","OK",50); //关闭连接myfree(SRAMIN,p);return 0;
}
实验现象
注意事项
- 4.3寸和7寸屏需要比较大电流,USB供电可能不足,请用外部电源适配器(推荐外接12V 1A电源)。
- 本例程在LCD_Init函数里面(在ILI93xx.c),用到了printf,如果不初始化串口1,将导致液晶无法显示!!
- 字库更新时,需自备标准SD卡一张(即大卡,也可以用TF卡+卡套),并拷贝光盘:SD卡根目录文件里面的所有内容到SD卡根目录,然后将SD卡插到开发板。
- 对于战舰V3开发板,P8需要用跳线短接:PB10(TX)与GBC_RX,PB11(RX)与GBC_TX。
- 如果触摸屏不准,请按住KEY0不放,然后按复位,松开复位,进入触摸屏校准。此时松开KEY0,执行校准,即可对屏幕进行校准。
更多推荐
基于STM32的家庭气象站
发布评论