基于STM32和ESP8266的天气预报系统

基于STM32和ESP8266的天气预报系统

本章将介绍一个关于STM32+ESP8266的练手小项目,项目来源地址在下面:

http://www.openedv.com/forum.php?mod=viewthread&tid=229818&highlight=%CC%EC%C6%F8

项目的源码地址请见文章最后。

一、实验环境要求

1.1硬件要求

● STM32单片机

● ESP8266WIFI模块

● LCD屏幕

● SD卡,安装文件系统

1.2软件环境要求

● Keil5

● 程序烧录软件

● 固件烧录软件

● 串口调试助手

二、系统示意图

系统整体示意图:

在这里插入图片描述

为增加学习兴趣,附上实验结果图:

在这里插入图片描述

三、程序流程图

程序流程图主要是主程序的流程图,如下:
在这里插入图片描述
在流程图中,单片机的初始化主要是一些硬件的初始化,主要有中断、串口、按键、LCD等等一些初始化,具体内容参考程序,这里即将不会介绍了。

四、ESP8266配置

4.1 AT固件烧录

由于本项目STM32单片机与WIFI模块之间是通过串口3发送AT指令来实现配置,因此需要烧录AT固件,固件相关资源见文章最后。

硬件连接示意图:
在这里插入图片描述

烧录步骤如下:
先打开烧录软件,软件在文的末尾提供:
在这里插入图片描述
然后对烧录软件进行配置,这一步很关键,按照下图进行配置:
在这里插入图片描述
固件是bin文件:
在这里插入图片描述

4.2 ESP8266配置函数atk_8266_wifista_config()

函数的具体内容参看下图:

在这里插入图片描述
主要通过发送AT指令来配置ESP8266,主要做了以下工作:

● 检查ESP8266硬件连接是否正常;

atk_8266_send_cmd("AT","OK",20)

● 配置wifi为STA模式;

atk_8266_send_cmd("AT+CWMODE=1","OK",50)

● 连接路由器。

atk_8266_send_cmd("AT+CIPMUX=0","OK",20);   //0:单连接;1:多连接
sprintf((char*)p,"AT+CWJAP=\"%s\",\"%s\"",wifista_ssid,wifista_password);//传输路由器参数
while(atk_8266_send_cmd(p,"WIFI GOT IP",300));	//连接路由器				

五、获取天气

5.1获取天气函数get_current_weather()

函数在工程的weather.c文件中。

//获取实时天气
//成功返回0,失败返回1
u8 get_current_weather(void)
{
	u8 *p;
	u8 res;
	p=mymalloc(SRAMIN,40);							
	sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",WEATHER_SERVERIP,WEATHER_PORTNUM);    //配置服务器IP和PORT,建立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);      //´开启透传模式

	USART3_RX_STA=0;
	atk_8266_send_cmd("AT+CIPSEND","OK",100);         //开始透传
	printf("start trans...\r\n");
	//发送get请求:网站密钥+目的城市
	u3_printf("GET https://api.seniverse.com/v3/weather/now.json?key=“修改处:你的自密钥”&location=“修改处:目的城市拼音”&language=zh-Hans&unit=c\n\n");	
	delay_ms(20);

	USART3_RX_STA=0;	
	delay_ms(1000);

	if(USART3_RX_STA&0X8000)		//接收天气数据
	{ 
		USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
	} 
	parse_now_weather();     //CJSON解析

	
	atk_8266_quit_trans();//退出透传
	atk_8266_send_cmd("AT+CIPCLOSE","OK",50);         //关闭TCP连接
	myfree(SRAMIN,p);
	return 0;
}

分析如下:

建立TCP连接,连接天气服务器

	sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",WEATHER_SERVERIP,WEATHER_PORTNUM);    //配置服务器IP和PORT,建立TCP连接
	res = atk_8266_send_cmd(p,"OK",200);//发送TCP连接命令

开启透传模式

	atk_8266_send_cmd("AT+CIPMODE=1","OK",100);      //´开启透传模式
	atk_8266_send_cmd("AT+CIPSEND","OK",100);         //开始透传

发送get请求

u3_printf("GET https://api.seniverse.com/v3/weather/now.json?key=“修改处:你的自密钥”&location=“修改处:目的城市拼音”&language=zh-Hans&unit=c\n\n");	

parse_now_weather()解析天气

parse_now_weather();     //CJSON解析

下一节将介绍这个函数。

关闭透传

atk_8266_quit_trans();//退出透传

断开TCP连接

atk_8266_send_cmd("AT+CIPCLOSE","OK",50);         //关闭TCP连接

说明:我用的是知心天气服务平台,密钥可以自己去知心网站申请。

5.2 CJSON解析

服务器发送给我们的数据是以CJSON格式,保存在USART3_RX_BUF缓存中,我们需要对其进行解析。

CJSON具体学习内容参考:
https://blog.csdn.net/Mculover666/article/details/103796256

我们只用到两个相关的API:

CJSON主要用到的相关的API:

extern cJSON *cJSON_Parse(const char *value);//从给定的json字符串中得到cjson对象

extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);//根据下标获取cjosn对象数组中的对象

extern char  *cJSON_Print(cJSON *item);//从cjson对象中获取有格式的json对象

extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);//根据键获取对应的值(cjson对象)

extern void   cJSON_Delete(cJSON *c);//删除cjson对象,释放链表占用的内存空间

从知心天气服务器获取的数据格式如下:

{
  "results": [
    {
      "location": {
        "id": "C23NB62W20TF",
        "name": "西雅图",
        "country": "US",
        "path": "西雅图,华盛顿州,美国",
        "timezone": "America/Los_Angeles",
        "timezone_offset": "-07:00"
      },
      "now": {
        "text": "多云", //天气现象文字
        "code": "4", //天气现象代码
        "temperature": "14", //温度,单位为c摄氏度或f华氏度
        "feels_like": "14", //体感温度,单位为c摄氏度或f华氏度
        "pressure": "1018", //气压,单位为mb百帕或in英寸
        "humidity": "76", //相对湿度,0~100,单位为百分比
        "visibility": "16.09", //能见度,单位为km公里或mi英里
        "wind_direction": "西北", //风向文字
        "wind_direction_degree": "340", //风向角度,范围0~360,0为正北,90为正东,180为正南,270为正西
        "wind_speed": "8.05", //风速,单位为km/h公里每小时或mph英里每小时
        "wind_scale": "2", //风力等级,请参考:http://baike.baidu.com/view/465076.htm
        "clouds": "90", //云量,单位%,范围0~100,天空被云覆盖的百分比 #目前不支持中国城市#
        "dew_point": "-12" //露点温度,请参考:http://baike.baidu.com/view/118348.htm #目前不支持中国城市#
      },
      "last_update": "2015-09-25T22:45:00-07:00" //数据更新时间(该城市的本地时间)
    }
  ]
}

程序中与天气解析相关的程序:

u8 parse_now_weather(void)
{
	//....
	root = cJSON_Parse((const char*)USART3_RX_BUF);   //获取json对象
	if(root != NULL)
	{
		pSub = cJSON_GetObjectItem(root,"results");  //获取 results 对应的值
		if(pSub != NULL)
		{
			arrayItem = cJSON_GetArrayItem(pSub,0);  //根据下标获取josn对象数组中的对象
			pr = cJSON_Print(arrayItem);   
			pItem = cJSON_Parse(pr);        //获取json对象
			if(pItem != NULL)
			{
				/*-------------------------------获取城市名称---------------------------*/
				pSubItem = cJSON_GetObjectItem(pItem,"location"); // 根据 location 键获取对应的值(cjson对象)
				if(pSubItem != NULL)
				{
					pChildItem = cJSON_GetObjectItem(pSubItem,"name");// 根据 name 键获取对应的值(cjson对象)
					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);         //显示城市名称
					}
				}
				/*-------------------------------获取天气信息---------------------------*/
				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);    //显示天气现象文字
					}

					
					pChildItem = cJSON_GetObjectItem(pSubItem,"code");    //获取天气代码         
					if(pChildItem != NULL)
					{
						gbkstr = pChildItem->valuestring;
						show_weather_icon((u8 *)gbkstr,0);        //根据天气代码,显示天气图片                     
					}

					
					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);
		}
	}
	
	//...
	
	return 0;
}

通过以上解析函数就能够得到,从服务器发送过来的天气信息,获取三天信息跟以上步骤雷同,就不再赘述了。

六、资源获取

第一次写项目博客,经验不足,描述不全,希望以后提高。

最后附上工程源码,提供给大家学习:

https://github.com/caosongwang/ESP8266

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值