stm32 获取解析并显示天气

所用开发板:OneNET NB-IoT 开发板 V2.1
需要ESP8266
需要注册心知天气账号(自行百度)

1、头文件

#ifndef __SHOW_WEATHER_H
#define __SHOW_WEATHER_H

#include "OLED.h"
#include <string.h>
#include <stdlib.h>
#include "usart.h"
#include "delay.h"
#include "led.h"


extern char usart2Buf[512];
extern int usart2Len;

extern char usart1Buf[512];
extern int usart1Len;

//映射汉字及其编号
struct cn_and_num{
	char cn[4];
	int num;
};

void init_cnnum(struct cn_and_num *cnnum,int len);//初始化汉字代号映射表

//将汉字转化其在字库中的位置
void change_cn_num(int *cn_num,char *cn_buf,int cn_buf_len,
										struct cn_and_num *cnnum,int cnnum_len);

void show_wether(int *cn_num,int temp,char *time);//输出格式化后的数据到oled

void data_parsing(char *tmp,int len,char *time_buf,
											char *cn_buf,int *wendu);//对获得的天气数据进行解析

void get_city_weather(int type);//初始化wifi模块、根据编号获取对应城市的天气

//若连接好wifi以后仅需调用这个
void show_city_weather(int type,int *check);//根据编号打印获取城市天气并输出到oled
/*
	type :
			0 初始化
			1 成都
			2 南充
			3 拉萨
			4 石家庄
			5 乌鲁木齐
*/

#endif

usart.h
delay.h
led.h
OLED.h

2、具体实现

2.1、说明

  • 解析步骤

获取原始数据 --> 解析提取 --> 获取汉字在字库的位置 --> 显示
显示核心函数:OLED_ShowCN(uint8_t x,uint8_t y,uint8_t index)
即根据汉字在字库中的位置 index来显示汉字

  • 原始数据

在这里插入图片描述

  • 解析后的数据

=================
南充abc阴abc
34
2022-08-08 10:46
=================
心知天气返回的数据为UTF-8编码(每个汉字3个字节)
把城市和天气放一起是为了方便后面显示 abc为分割标志

2.2、让keil能够编译UTF-8的数据

在这里插入图片描述在这里插入图片描述

–locale=english

2.3、未解决的问题

使用AT+RST命令后必须重置开发板否则会卡死
也就是AT+RST命令和天气查询不能共存

2.4、代码

#include "show_weather.h"

static int loop_i;
static int loop_j;
static int loop_b;

/* 初始化汉字与其代号的映射表
 */
void init_cnnum(struct cn_and_num *cnnum,int len){
	
	loop_i = 0;
	loop_j = 18;
	strncpy(cnnum[loop_i].cn,"成",3);
	cnnum[loop_i].cn[3] = 0;//收尾处理
	cnnum[loop_i].num = loop_j;//成 在字库的位置为18
	
	loop_i++;
	loop_j++;
	strncpy(cnnum[loop_i].cn,"都",3);
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;

  loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"拉");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"萨");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"石");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"家");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"庄");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"南");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	
		loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"充");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
			loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"乌");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
		loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"鲁");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
			loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"木");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	
		loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"齐");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"晴");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"阴");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"多");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"云");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;

	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"转");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"大");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"小");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"到");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"暴");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"雨");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"中");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;	
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"获");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"取");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"失");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
	loop_j++;
	strcpy(cnnum[loop_i].cn,"败");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = loop_j;
	
	loop_i++;
  strcpy(cnnum[loop_i].cn,"abc");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = -1;
	
	loop_i++;
  strcpy(cnnum[loop_i].cn,"abc");
	cnnum[loop_i].cn[3] = 0;
	cnnum[loop_i].num = -1;
	
	loop_i = 0;
	loop_j = 0;
}




/*
 *汉字转化:将汉字转化其在字库中的位置
 *cn_num 保存有 城市名和天气 的数字代号 以-1隔开
 *如:18 19 -1 30 -1 代表: 成 都 晴
 *
 *cn_buf 需要转化的汉字集合 格式:城市名abc天气abc
 *cn_buf_len:cn_buf大小
 *
 *cnnum 保存汉字及其数字代号
 *cnnum_len cnnum大小
*/

void change_cn_num(int *cn_num,char *cn_buf,int cn_buf_len,
											struct cn_and_num *cnnum,int cnnum_len){
		
	int head,tail;//动态改变遍历位置,减小时间开销
		head = 0;
		for(loop_i=0;loop_i<cn_buf_len/3;loop_i++){
			tail = cnnum_len+1;
			for(loop_j = head;loop_j<tail;loop_j++){
				if(cnnum[loop_j].num == -1){//映射表结尾
					loop_j = 0;//从头开始找
					tail = head;//到上一个字结束
				}
				//一个汉字占3个字节
				else if(strncmp(cn_buf+loop_i*3,"abc",3) == 0){//分割位
					cn_num[loop_i] = -1;
					head = loop_j;
					break;
				}
				else if(strncmp(cnnum[loop_j].cn,cn_buf+loop_i*3,3) == 0){
					cn_num[loop_i] = cnnum[loop_j].num;
					head = loop_j;//从这个字后面开始找
					break;
				}
			}
	}
}


/*
 *天气显示
 *cn_num 保存有 城市名和天气 的数字代号 以-1隔开
 *如:18 18 -1 20 -1 代表: 成 都 晴
 *
 *temp 温度
 *time 更新时间
*/
void show_wether(int *cn_num,int temp,char *time){
	
	
	//城市
	OLED_Clear();
	OLED_ShowCN(0,0,13);
	OLED_ShowCN(16,0,14);
	OLED_ShowChar(1,5,':');
	
	for(loop_i = 0;loop_i<30;loop_i++){
		if(cn_num[loop_i] == -1){
			loop_j = loop_i +1;
			break;
		}
		OLED_ShowCN(42+loop_i*16,0,cn_num[loop_i]);
	}
	
	//天气
	OLED_ShowCN(0,2,15);
	OLED_ShowCN(16,2,16);
	OLED_ShowChar(2,5,':');
	for(loop_i = loop_j;loop_i<30;loop_i++){
		
		if(cn_num[loop_i] == -1){
			break;
		}
		OLED_ShowCN(42+(loop_i-loop_j)*16,2,cn_num[loop_i]);
	}
	
	//温度
	OLED_ShowCN(0,4,11);
	OLED_ShowCN(16,4,17);
	OLED_ShowChar(3,5,':');
	OLED_ShowNum(3,6,temp,2);
	
	
	//更新时间;
	OLED_ShowString(4,1,time);
	
}

/* 数据解析 
 * tmp 需要解析的数据 len tmp的数据长度
 * time_buf 更新天气时的时间
 * cn_buf 城市+天气 示例 成都abc晴abc
 * wendu 温度
 */

void data_parsing(char *tmp,int len,char *time_buf,
										char *cn_buf,int *wendu){
											
											
											
	char temp_buf[3];
	int temp;//温度
	
	memset(temp_buf,0,3);
	OLED_weather_loading(30,0);
	
	//从name 前开始
	for(loop_i = 46;loop_i< len - 10;loop_i++){
			//获取城市名
			//strncmp(tmp+loop_i,"name",4);
			if(tmp[loop_i] == 'n' && tmp[loop_i+1] == 'a' &&
									tmp[loop_i+2] == 'm' && tmp[loop_i+3] == 'e'){
					loop_j = loop_i + 7;
					loop_b = 0;
					while ( tmp[loop_j] != '\"' && loop_b<20){
							cn_buf[loop_b] = tmp[loop_j];
							loop_b++;
							loop_j++;
						OLED_weather_loading(31,loop_b%99);
					}
					//添加分割标记
					cn_buf[loop_b] = 'a';
					loop_b++;
					cn_buf[loop_b] = 'b';
					loop_b++;
					cn_buf[loop_b] = 'c';
					loop_b++;
					cn_buf[loop_b] = 0;//收尾处理
			}
			//获取天气
			else if(tmp[loop_i] == 't' && tmp[loop_i+1] == 'e' &&
									tmp[loop_i+2] == 'x' && tmp[loop_i+3] == 't'){
					loop_j = loop_i + 7;
					while ( tmp[loop_j] != '\"'&& loop_b<40){
							cn_buf[loop_b] = tmp[loop_j];
							loop_b++;
							loop_j++;
						OLED_weather_loading(32,loop_b%99);
					}
					cn_buf[loop_b] = 'a';
					loop_b++;
					cn_buf[loop_b] = 'b';
					loop_b++;
					cn_buf[loop_b] = 'c';
					loop_b++;
					cn_buf[loop_b] = 0;
					
					UsartPrintf(USART1, cn_buf);//向串口1发解析后的数据
			}
									
			//获取温度
			else if(tmp[loop_i] == 't' && tmp[loop_i+1] == 'u' &&
							tmp[loop_i+2] == 'r' && tmp[loop_i+3] == 'e'){

					loop_j = loop_i + 7;
					loop_b = 0;
					while ( tmp[loop_j] != '\"'&& loop_b<3){
							temp_buf[loop_b] = tmp[loop_j];
							loop_b++;
							loop_j++;
						OLED_weather_loading(33,loop_b%99);
					}
					temp_buf[loop_b] = '\0';//收尾处理
					
					//这里用atoi会出错
					//0的ASCII码是 48
					temp = (temp_buf[0] - 48)*10 + temp_buf[1] - 48;
					*wendu = temp;
					UsartPrintf(USART1, temp_buf);
			}
							
			//获取时间
			else if(tmp[loop_i] == 'd' && tmp[loop_i+1] == 'a' &&
								tmp[loop_i+2] == 't' && tmp[loop_i+3] == 'e') {
					loop_j = loop_i + 12;
					loop_b = 0;
					while ( tmp[loop_j] != '+'&& tmp[loop_j] != '}' && loop_b<16){
							time_buf[loop_b] = tmp[loop_j];

							loop_b++;
							loop_j++;
					OLED_weather_loading(34,loop_b%99);
					}
					time_buf [5] = ' ';//把横线转为空格
					time_buf [loop_b] = 0;
					
					UsartPrintf(USART1, time_buf);
					OLED_weather_loading(34,loop_b);	
					break;
			}
				OLED_weather_loading(30,loop_i%99);				
	}
	
}

/* 获取对应城市的天气 */

void get_city_weather(int city){
	
	char conn_server[] = "AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80\r\n";//连接服务器

	switch(city){
		case 0://初始化
		{
			unsigned char query_weather[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SpKydYpilyEAHrt6C&location=nanchong&language=zh-Hans&unit=c\r\n";//南充
			
			//配置wifi 从串口2
			OLED_weather_loading(2,1);
			Usart_SendString(USART2,(unsigned char *)"+++",3);//退出透传
			Delay_ms(1000);

			OLED_weather_loading(2,2);
			Usart_SendString(USART2,(unsigned char *)"+++",3);//退出透传
			Delay_ms(1000);
			
			OLED_weather_loading(2,3);
			Usart_SendString(USART2,(unsigned char *)"+++",3);//退3次就能成功
			Delay_ms(500);

//       	重置会出错			
//			usart2Len = 0;
//			OLED_weather_loading(2,41);
//			UsartPrintf(USART2,"AT+RST\r\n");//重置
//			Delay_ms(5000);	
//			usart2Len = 0;
			
			OLED_weather_loading(2,42);
			Usart_SendString(USART2, (unsigned char *)"AT+CIPMUX=0\r\n",sizeof("AT+CIPMUX=0\r\n"));//禁止多连接
			Delay_ms(500);
			
			OLED_weather_loading(2,5);
			Usart_SendString(USART2,(unsigned char *)conn_server,strlen(conn_server));//连接心知天气服务器
			Delay_ms(500);
			
			OLED_weather_loading(2,6);
			Usart_SendString(USART2, (unsigned char *)"AT+CIPMODE=1\r\n",sizeof("AT+CIPMODE=1\r\n"));//使能穿透模式
			Delay_ms(500);
			
			OLED_weather_loading(2,7);
			Usart_SendString(USART2, (unsigned char *)"AT+CIPSEND\r\n",sizeof("AT+CIPSEND\r\n"));//给服务器发消息测试
			Delay_ms(500);
			
			usart2Len = 0;//保证接收的是天气原始数据
			Usart_SendString(USART2,(unsigned char *)query_weather,sizeof(query_weather));//查询天气数据
			OLED_weather_loading(25,0);
			break;
		}
		case 1:
		{
			unsigned char query_weather[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SpKydYpilyEAHrt6C&location=chengdu&language=zh-Hans&unit=c\r\n";//查询成都天气
			usart2Len = 0;
			Usart_SendString(USART2,(unsigned char *)query_weather,sizeof(query_weather));//查询天气数据
			OLED_weather_loading(25,1);
			break;
		}
		case 2:
		{
			unsigned char query_weather[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SpKydYpilyEAHrt6C&location=nanchong&language=zh-Hans&unit=c\r\n";//南充
			usart2Len = 0;
			Usart_SendString(USART2,query_weather,sizeof(query_weather));//查询天气数据
			OLED_weather_loading(25,2);
			break;
		}
		case 3:
		{
			unsigned char query_weather[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SpKydYpilyEAHrt6C&location=lasa&language=zh-Hans&unit=c\r\n";//拉萨
			usart2Len = 0;
			Usart_SendString(USART2,query_weather,sizeof(query_weather));//查询天气数据
			OLED_weather_loading(25,3);
			break;
		}
		case 4:
		{
			unsigned char query_weather[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SpKydYpilyEAHrt6C&location=shijiazhuang&language=zh-Hans&unit=c\r\n";//石家庄
			usart2Len = 0;
			Usart_SendString(USART2,query_weather,sizeof(query_weather));//查询天气数据
			OLED_weather_loading(25,4);
			break;
		}
		case 5:
		{
			unsigned char query_weather[] = "GET https://api.seniverse.com/v3/weather/now.json?key=SpKydYpilyEAHrt6C&location=wulumuqi&language=zh-Hans&unit=c\r\n";//乌鲁木齐
			usart2Len = 0;
			Usart_SendString(USART2,query_weather,sizeof(query_weather));//查询天气数据
			OLED_weather_loading(25,5);
			break;
		}
		default:
		break;
	}
	Delay_ms(500);
}


/* 获取并打印对应城市的天气 */

void show_city_weather(int type,int *check){
	
	//给个默认值
	char data_tmp[300] =  "{\"results\":[{\"location\":{\"id\":\"WM6N2PM3WY2K\",\"name\":\"获取失败\",\"country\":\"CN\",\"path\":\"xx,xx,xx,xx\",\"timezone\":\"Asia/Shanghai\",\"timezone_offset\":\"+08:00\"},\"now\":{\"text\":\"获取失败\",\"code\":\"0\",\"temperature\":\"0\"},\"last_update\":\"0000-00-00T00:00:00+00:00\"}]}";
	
	int temp;//温度
	char time_buf[20];//时间
	char cn_buf[50];//需要转换的汉字集合
	
	int cn_num[40];//保存汉字编号
	struct cn_and_num cnnum[128];//映射汉字及其编号
	
	OLED_weather_loading(1,0);
	memset(cnnum,0,sizeof(cnnum));//初始化汉字代码映射表
	memset(cn_num,-1,sizeof(cn_num));//初始化汉字编号
	memset(cn_buf,0,sizeof(cn_buf));//初始化解析后的汉字集合
	
	init_cnnum(cnnum,128);
	
	Delay_ms(500);
	get_city_weather(type);
	OLED_weather_loading(1,1);
	Delay_ms(500);
	
	if(strncmp(usart2Buf,"{\"results\":",10) == 0){
		
		memset(data_tmp,0,sizeof(data_tmp));
		strncpy(data_tmp,usart2Buf,strlen(usart2Buf));
		OLED_weather_loading(1,2);
		usart2Len = 0;//及时清零
	}
	//UsartPrintf(USART1, data_tmp);

	//天气数据解析
	data_parsing(data_tmp,strlen(data_tmp),time_buf,cn_buf,&temp);
	OLED_weather_loading(1,3);
	
	//汉字转代号
	change_cn_num(cn_num,cn_buf,sizeof(cn_buf),cnnum,30);
	OLED_weather_loading(1,4);
	
	//打印
	show_wether(cn_num,temp,time_buf);
	*check = 0;
//	GPIO_SetBits(GPIOA,GPIO_Pin_5);
	return ;
}

2.5、效果图

在这里插入图片描述

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32是一款微控制器,我们可以使用它来解析心知天气API的网络数据。首先,我们需要确保STM32连接到互联网,并且具备网络访问的能力。我们可以通过使用WIFI模块或以太网模块等外部设备来实现这一点。 接下来,我们需要在STM32上编写程序来访问心知天气API,并获取返回的数据。我们可以使用STM32的网络编程库来实现这一点,例如lwIP(Lightweight IP)库。通过lwIP库,我们可以建立TCP/IP连接,发送HTTP请求到心知天气API,并接收并读取返回的数据。 在程序中,我们需要设置正确的API网址和参数,例如城市ID、API密钥等。我们还需要设置相应的HTTP头部,如User-Agent、Content-Type等。 一旦我们成功与API建立连接并发送请求,我们就可以等待心知天气API的响应。返回的数据可能是JSON格式的,所以我们需要解析这些数据。在STM32中,我们可以使用JSON解析库来解析返回的JSON数据,并提取所需的天气信息,如温度、湿度、空气质量等。 最后,我们可以将解析的数据通过STM32的串口、LCD屏幕或其他输出设备显示出来,以提供给用户或其他相关设备使用。 总之,通过编写合适的程序,配置正确的API参数,并使用网络编程库和JSON解析库,我们可以在STM32上成功解析心知天气API的网络数据。这样,我们就可以获取准确的天气信息,并在STM32上进行相关的处理和显示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值