IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> stm32 获取解析并显示天气 -> 正文阅读

[嵌入式]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、效果图

在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 19:22:29  更:2022-08-19 19:23:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 12:56:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码