STM大家好,我是杂烩君。
前两篇文章我们分享了:
这篇文章我们分享:天气预报小助手V1.2(软件+硬件结合)
1、作品介绍
首先,看一下作品的演示视频:
温馨提示:因为是进行人机对话演示,所以应打开音量观看哈。
这是一个智能的天气预报系统。显示屏上显示各种天气指标及实时显示时间日期等。可以使用触摸屏输入城市名称搜索天气,也可以使用语音搜索天气。
1.1 系统功能
作品包含的的功能有:
(1)实时天气显示,温湿度显示,日历显示;
(2)收音机功能;
(3)人机对话功能。
系统框图如下:

1.2 系统GUI界面
(1)主界面

你没有看错,就是99℃,就是星期八。但这不是系统出错,而是本人故意设置的初始值,每当开机收到天气数据之后就可以看出有明显的变化。
(2)菜单界面

(3)wifi设置界面

点击文本框会进入键盘界面,输入WiFi信息之后返回,再点击Add
按钮即可发送WiFi名称与密码给控制器,控制器控制WiFi模块连接WiFi热点。
(4)收音机界面

通过点击下方频率点跳到相应频率,再通过左右按钮调节频率至所需频率。
2、作品实现
2.1 天气数据获取及解析
2.1.1 天气数据从哪来?
天气数据可以从一些专门做天气预报的网站获取,如心知天气、和风天气等。本人选择的是心知天气
https://www.seniverse.com/
网站首页如下:

我们是通过其API密钥
才能获取得到其天气数据,而只有注册的用户才拥有API密钥,所以必须得注册,可以点击右上角进行注册。
2.1.2 天气数据是什么格式?
登录心知天气
网站之后,点击菜单导航中的数据->常规数据
即可查看API文档
。在API文档页面的左侧可看到一些可查看的条目,如:

可点击天气实况
查看其相关说明,可以看到其天气数据格式如下图所示:

这就是JSON格式的数据,不了解JSON的朋友可查看上一篇笔记:例说嵌入式实用知识之JSON数据
2.1.3 如何解析得到有用的数据?
从上图中的JSON格式天气数据包中我们可以看出:我们需要用到的数据就是冒号后面的字符串数据
,这些数据是我们需要获取并显示到屏幕上的数据。
那么,我们该怎么从这一堆JSON格式数据中解析出冒号后面的字符串呢?并且,这个系统是基于单片机的天气预报系统。而单片机使用C语言进行编程开发的,所以我们得使用C语言对这些JSON天气数据包进行解析。
其实,有一个专门解析JSON数据包的第三方C语言库。我们可以使用这个库进行解析,这个CJSON库的下载链接为:
链接:https://pan.baidu.com/s/1DQynsdlNyIvsVXmf4W5b8Q 提取码:ww4z
只要把cJSON.c
与cJSON.h
放到工程主程序所在目录,然后在主程序中包含头文件JSON.h
即可引入该库。如:

下面给出一个实例:
测试代码:
/*----------------------------------------------------------------------------------------
Program Explain:解析JSON天气数据包now.json(天气实况)
Create Date:2017.12.6 by lzn
----------------------------------------------------------------------------------------*/
//1、数据来源:心知天气(api.seniverse.com)
//2、获取方法:GET https://api.seniverse.com/v3/weather/now.json?key=2owqvhhd2dd9o9f9&location=beijing&language=zh-Hans&unit=c
//3、返回的数据范例见文件test.txt
#include <stdio.h>#include <string.h>#include <stdlib.h>#include "cJSON.h"
//函数声明
int cJSON_WeatherParse(char *JSON);
/*********************************************************************************
* Function Name : main主函数
* Parameter : NULL
* Return Value : 0
* Function Explain :
* Create Date : 2017.12.6 by lzn
**********************************************************************************/
int main(int argc, char **argv)
{
FILE *fp;
char *data;
int len;
int i;
if((fp = fopen("now.txt","rb")) == NULL)
{
printf("Open error!\n");
return 1;
}
fseek(fp, 0, SEEK_END); //文件指针指向文件末尾
len = ftell(fp); //求文件长度
fseek(fp, 0, SEEK_SET); //文件指针指向文件开头
data = (char*)malloc(len+1);
fread(data, len, 1, fp);
fclose(fp);
//printf("read file %s complete, len=%d.\n","now.txt",len);
cJSON_WeatherParse(data); //解析天气数据
free(data);
system("pause");
return 0;
}
/*********************************************************************************
* Function Name : cJSON_WeatherParse,解析天气数据
* Parameter : JSON:天气数据包 results:保存解析后得到的有用的数据
* Return Value : 0:成功 其他:错误
* Function Explain :
* Create Date : 2017.12.6 by lzn
**********************************************************************************/
int cJSON_WeatherParse(char *JSON)
{
cJSON *json,*arrayItem,*object,*subobject,*item;
json = cJSON_Parse(JSON); //解析JSON数据包
if(json == NULL) //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
return 1;
}
else
{
if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); //匹配字符串"results",获取数组内容
{
int size = cJSON_GetArraySize(arrayItem); //获取数组中对象个数
//printf("cJSON_GetArraySize: size=%d\n",size);
if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
{
/* 匹配子对象1 */
if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
{
printf("\n-------------------------------location-----------------------------\n");
//匹配子对象1成员"id"
if((item = cJSON_GetObjectItem(subobject,"id")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象1成员"name"
if((item = cJSON_GetObjectItem(subobject,"name")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象1成员"country"
if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象1成员"timezone"
if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象1成员"timezone_offset"
if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
}
/* 匹配子对象2 */
if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
{
printf("---------------------------------now-------------------------------\n");
//匹配子对象2成员"text"
if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"code"
if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"temperature"
if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"feels_like"
if((item = cJSON_GetObjectItem(subobject,"feels_like")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"pressure"
if((item = cJSON_GetObjectItem(subobject,"pressure")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"humidity"
if((item = cJSON_GetObjectItem(subobject,"humidity")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"visibility"
if((item = cJSON_GetObjectItem(subobject,"visibility")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"wind_direction"
if((item = cJSON_GetObjectItem(subobject,"wind_direction")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"wind_speed"
if((item = cJSON_GetObjectItem(subobject,"wind_speed")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"wind_scale"
if((item = cJSON_GetObjectItem(subobject,"wind_scale")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"clouds"
if((item = cJSON_GetObjectItem(subobject,"clouds")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
//匹配子对象2成员"dew_point"
if((item = cJSON_GetObjectItem(subobject,"dew_point")) != NULL)
{
printf("%s : %s\n",item->string,item->valuestring);
}
}
/* 匹配子对象3 */
if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
{
printf("----------------------------last_update----------------------------\n");
printf("%s : %s\n\n",subobject->string,subobject->valuestring);
}
}
}
}
cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
return 0;
}
这个测试程序会去读取我们工程目录下的 now.txt
件,所以事先我们需要把JSON格式的天气预报数据复制到该文件中:

把 now.txt
里面的数据读出并保存到data
指向的动态内存中。然后再把data
中的数据传入我们事先编写好的解析天气数据的函数int cJSON_WeatherParse(char *JSON)
中进行解析,最后把解析之后的数据给到该函数的返回值即可。
解析函数里主要用到以下函数: 1、cJSON_Parse函数
cJSON*cJSON_Parse(const char *value);
该函数用来解析JSON数据包,并按照cJSON结构体的结构序列化整个数据包。
2、cJSON_GetObjectItem函数
cJSON_GetObjectItem(cJSON *object,const char *string);
该函数可从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。
3、cJSON_GetArraySize函数
cJSON_GetArraySize(const cJSON *array);
该函数可获取数组中元素个数。
4、cJSON_GetArrayItem函数
cJSON_GetArrayItem(const cJSON *array, int index);
该函数可获取数组中的内容。
5、cJSON_Delete函数
cJSON_Delete(cJSON *c);
该函数用来释放cJSON_Parse
函数内部申请的堆内存。
我们的解析函数主要运用多次cJSON_GetObjectItem
来匹配各对象成员,然后取出各个键值对的值valuestring
。
该程序的运行结果如下:
