桌面天气时钟【心知天气API、可获取实时时间、合成解码cJSON】

全套代码已经开源,可以通过CSDN资源链接获取
文中有基本代码讲解



一、需要的模块

1.C8T6

采用c8t6作为主控,搭载各种功能以及屏幕。
问题在于由于最小系统板内存小,后期添加功能不方便(内存小已经阉割了很多功能了,只有小部分字库和基础图片)请添加图片描述

2.esp32

在这里esp32主要用来联网获取实时天气,时间,地点等。天气获取主要通过心知天气,时间日期通过阿里云数据。请添加图片描述

3. 1.44寸TFT彩色屏幕

主要显示界面,显示天气时间等信息。请添加图片描述

4. 分光棱镜

可以模拟出全息投影的感觉,帅到爆! ! !
请添加图片描述请添加图片描述

二、准备工作

1.注册心知天气获取自己的API

心知天气官网链接:https://www.seniverse.com/

注册自己的控制台,并取得私钥,用来获取数据包。

点击【我的产品】

请添加图片描述

如图为【私钥】需要在Arduino的代码中修改。

请添加图片描述

2.了解合成cJSON数据包【让心知天气拥有时间数据】

- 获取天气数据

运行后esp32串口会下发一个心知天气的数据包:

{"results":[{"location":{"id":"私钥","name":"地点","country":"CN","path":"---","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"Overcast","code":"9","temperature":"19"},"last_update":"2022-07-18T10:40:06+08:00"}]}


该处使用CSDN的cJSON工具解析数据。

代码如下(示例):

{
  "results": [
    {
      "location": {
        "id": "私钥",
        "name": "地点",
        "country": "CN",
        "path": "---",
        "timezone": "Asia/Shanghai",
        "timezone_offset": "+08:00"
      },
      "now": {
        "text": "Sunny",
        "code": "0",
        "temperature": "29"
      },
      "last_update": "2022-08-01T16:40:06+08:00"
    }
  ]
}
如上图就是一个完整的数据包结构了,我们会在32中对数据进行解析保存,达到分级、分块调用的目的。

由于心知天气免费版只提供了基础的天气数据,没有时间日期等信息,所以我又使用了阿里云的数据,并把两个数据进行整合,合成新的数据包。

- 获取时间数据【合成数据包】

阿里云下发的数据不满足HTTP数据包的形式,所以曲线救国,我在代码中合成了新的数据包,
并把所以时间日期数据单独放在字符串中。

int Year,Mon,Day,Hour,Min,Wday;
struct tm timeInfo; //声明一个结构体
DynamicJsonDocument dat(1024);//建立一个新的数据包

//将时间数据对应在字符串中,方便合成新的cJSON数据包
const String MONTH_NAMES[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; //月份
const String DAY_NAMES[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                                "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
                                "21", "22", "23", "24", "25", "26", "27", "28", "29", "30","31"}; //日
const String HOUR_NAMES[] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
                                  "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
                                  "21", "22", "23", "24"};//时
const String MIN_NAMES[] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
                                "11", "12", "13","14", "15", "16", "17", "18", "19", "20",
                                "21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
                                "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
                                "41", "42", "43", "44", "45", "46", "47", "48", "49", "50",
                                "51", "52", "53", "54", "55", "56", "57", "58", "59", "60"}; //分
const String WDAY_NAMES[] = {"Sun.", "Mon.", "Tues.", "Wed.", "Thur.", "Fri.", "Sat."};                //星期

//location 心知天气的【location】数据
      dat["results"][0]["location"]["id"] = doc["results"][0]["location"]["id"].as<String>();
      dat["results"][0]["location"]["name"] = doc["results"][0]["location"]["name"].as<String>();
      dat["results"][0]["location"]["country"] = doc["results"][0]["location"]["country"].as<String>();
      dat["results"][0]["location"]["path"] = doc["results"][0]["location"]["path"].as<String>();
      dat["results"][0]["location"]["timezone"] = doc["results"][0]["location"]["timezone"].as<String>();
      dat["results"][0]["location"]["timezone_offset"] = doc["results"][0]["location"]["timezone_offset"].as<String>();
//now 心知天气【now】数据和时间结合 放在新的【now】结构体中
      dat["results"][0]["now"]["text"] = doc["results"][0]["now"]["text"].as<String>();  
      dat["results"][0]["now"]["code"] = doc["results"][0]["now"]["code"].as<String>();
      dat["results"][0]["now"]["temperature"] = doc["results"][0]["now"]["temperature"].as<String>();
      dat["results"][0]["now"]["mon"]=MONTH_NAMES[timeInfo.tm_mon ].c_str();
      dat["results"][0]["now"]["day"]=DAY_NAMES[timeInfo.tm_mday].c_str();
      dat["results"][0]["now"]["hour"]=HOUR_NAMES[timeInfo.tm_hour].c_str();
      dat["results"][0]["now"]["min"]=MIN_NAMES[timeInfo.tm_min].c_str();
      dat["results"][0]["now"]["wday"]=WDAY_NAMES[timeInfo.tm_wday].c_str();
      dat["results"][0]["last_update"]= doc["results"][0]["last_update"].as<String>();
      char json_string[1024];
      serializeJson(dat,json_string);//把所有数据放在新的【dat】中
      Serial.println(json_string);//输出

于是我们得到了新的数据包,包含了实时时间和日期信息

{"results":[{
"location":{"id":"私钥","name":"地点","country":"CN","path":"---",
"timezone":"Asia/Shanghai","timezone_offset":"+08:00"},
"now":{"text":"Sunny","code":"0","temperature":"27","mon":"Aug","day":"2","hour":"18","min":"47","wday":"Tues."},"last_update":"2022-08-02T18:40:06+08:00"}]}

再次使用CSDN的cJSON工具解析数据。

代码如下(示例):

{
  "results": [
    {
      "location": {
        "id": "私钥",
        "name": "地点",
        "country": "CN",
        "path": "---",
        "timezone": "Asia/Shanghai",
        "timezone_offset": "+08:00"
      },
      "now": {
        "text": "Sunny",
        "code": "0",
        "temperature": "27",
        "mon": "Aug",
        "day": "2",
        "hour": "18",
        "min": "47",
        "wday": "Tues."
      },
      "last_update": "2022-08-02T18:40:06+08:00"
    }
  ]
}

可以看到现在的数据包要远远大于之前,拥有了时间和日期数据。


3.使用stm32解析数据包

- 解析cJSON数据

#include "cJSON.h"

//对应子对象1结构体--Location
typedef struct
{
	char id[32];
	char name[32];
	char country[32];
	char path[64];
	char timezone[32];
	char timezone_offset[32];
}Location;
 
//对应子对象2结构体--Now
typedef struct
{
	char text[32];
	char code[32];
	char temperature[32];
	char mon[32];
	char day[32];
	char hour[32];
	char min[32];
	char wday[32];
}Now;
 
//用于保存服务器返回的天气数据
typedef struct
{
	Location location;		//子对象1
	Now now;				//子对象2
	char last_update[64];	//子对象3
}Results;
/*********************************************************************************
* Function Name    : cJSON_WeatherParse,解析天气数据
* Parameter		   : JSON:天气数据包  results:保存解析后得到的有用的数据
* Return Value     : 0:成功 其他:错误
* Function Explain : 
* Create Date      : 2017.12.6 by lzn
**********************************************************************************/
int cJSON_WeatherParse(char *JSON, Results *results)
{
	cJSON *json,*arrayItem,*object,*subobject,*item;
	
	json = cJSON_Parse(JSON); //解析JSON数据包
	if(json == NULL)		  //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
	{
		return 1;
	}
	else
	{
		if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL);
		//匹配字符串"results",获取数组内容
		{
			int size = cJSON_GetArraySize(arrayItem);     //获取数组中对象个数
			//printf("cJSON_GetArraySize: size=%d \r\n",size); 
			
			if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
			{
				/* 匹配子对象1 */
				if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
				{
					//printf("---------------------------------subobject1-------------------------------\r\n");
					if((item = cJSON_GetObjectItem(subobject,"id")) != NULL)
					//匹配子对象1成员"id"
					{
						memcpy(results[0].location.id,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) 
					//匹配子对象1成员"name"
					{
						memcpy(results[0].location.name,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)
					//匹配子对象1成员"country"
					{
						memcpy(results[0].location.country,item->valuestring,
						strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"path")) != NULL)  
					//匹配子对象1成员"path"
					{
						memcpy(results[0].location.path,item->valuestring,
						strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)
					//匹配子对象1成员"timezone"
					{
						memcpy(results[0].location.timezone,item->valuestring,
						strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)
					//匹配子对象1成员"timezone_offset"
					{
						memcpy(results[0].location.timezone_offset,item->valuestring,
						strlen(item->valuestring));
					}
				}
				/* 匹配子对象2 */
				if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
				{
					//printf("---------------------------------subobject2-------------------------------\r\n");
					if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)
					//匹配子对象2成员"text"
					{
						memcpy(results[0].now.text,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)
					//匹配子对象2成员"code"
					{
						memcpy(results[0].now.code,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL) 
					//匹配子对象2成员"temperature"
					{
						memcpy(results[0].now.temperature,item->valuestring,
						strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"mon")) != NULL) 
					//匹配子对象2成员"mon"
					{
						memcpy(results[0].now.mon,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"day")) != NULL) 
					//匹配子对象2成员"day"
					{
						memcpy(results[0].now.day,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"hour")) != NULL) 
					//匹配子对象2成员"hour"
					{
						memcpy(results[0].now.hour,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"min")) != NULL)
					 //匹配子对象2成员"min"
					{
						memcpy(results[0].now.min,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"wday")) != NULL) 
					//匹配子对象2成员"wday"
					{
						memcpy(results[0].now.wday,item->valuestring,strlen(item->valuestring));
					}
				}
				/* 匹配子对象3 */
				if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
				{
//printf("---------------------------------subobject3-------------------------------\r\n");
					memcpy(results[0].last_update,item->valuestring,strlen(subobject->valuestring));
				}
			} 
		}
	}
	cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
	return 0;
}

如上我们已经对数据包进行了解析。
然后进行分布调用。

//调用温度数据,结构基本不变
//只需要更改获取的数据结构体位置
memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
sprintf((char *)dtOLEDBuf,"%s^C",results[0].now.temperature);//更改这行代码获取其他数据。
LCD_ShowString(73,66,(u8 *)dtOLEDBuf,GRAYBLUE,BLACK,16,0);
USART_RX_STA=0;   
memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));

例如:
获取地点数据,只需要找不同,根据上面的代码,更改下面的

//地点
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s",results[0].location.name);//更改了这行的
					LCD_ShowString(60,100,(u8 *)dtOLEDBuf,CYAN,BLACK,16,0);	
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));

4.屏幕显示,由于分光棱镜的原理,需要反转屏幕。

根据原子哥的视频和芯片手册

在这里插入图片描述
请添加图片描述

我们只需要改变这行代码,就可以实现屏幕反转。使分光棱镜中的显示正向。

在这里插入图片描述

在初始化屏幕的初始化文件中改为
请添加图片描述

具体可以参考CSDN博主https://blog.csdn.net/qq1113512618/article/details/111937148的文章。

三、代码编写

32 main函数编写。

include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"

#include "oled.h"

#include "led.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"

#include "cJSON.h"

//子对象1结构体--Location
typedef struct
{
	char id[32];
	char name[32];
	char country[32];
	char path[64];
	char timezone[32];
	char timezone_offset[32];
}Location;
 
//子对象2结构体--Now
typedef struct
{
	char text[32];
	char code[32];
	char temperature[32];
	char mon[32];
	char day[32];
	char hour[32];
	char min[32];
	char wday[32];
}Now;
 
//用于保存服务器返回的天气数据
typedef struct
{
	Location location;		//子对象1
	Now now;				//子对象2
	char last_update[64];	//子对象3
}Results;


/*********************************************************************************
* Function Name    : cJSON_WeatherParse,解析天气数据
* Parameter		   : JSON:天气数据包  results:保存解析后得到的有用的数据
* Return Value     : 0:成功 其他:错误
* Function Explain : 
* Create Date      : 2017.12.6 by lzn
**********************************************************************************/
int cJSON_WeatherParse(char *JSON, Results *results)
{
	cJSON *json,*arrayItem,*object,*subobject,*item;
	
	json = cJSON_Parse(JSON); //解析JSON数据包
	if(json == NULL)		  //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
	{
		//printf("Error before: [%s] \r\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
		return 1;
	}
	else
	{
		if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); //匹配字符串"results",获取数组内容
		{
			int size = cJSON_GetArraySize(arrayItem);     //获取数组中对象个数
			//printf("cJSON_GetArraySize: size=%d \r\n",size); 
			
			if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
			{
				/* 匹配子对象1 */
				if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
				{
					//printf("---------------------------------subobject1-------------------------------\r\n");
					if((item = cJSON_GetObjectItem(subobject,"id")) != NULL)   //匹配子对象1成员"id"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].location.id,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) //匹配子对象1成员"name"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].location.name,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)//匹配子对象1成员"country"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].location.country,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"path")) != NULL)  //匹配子对象1成员"path"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].location.path,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)//匹配子对象1成员"timezone"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].location.timezone,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)//匹配子对象1成员"timezone_offset"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].location.timezone_offset,item->valuestring,strlen(item->valuestring));
					}
				}
				/* 匹配子对象2 */
				if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
				{
					//printf("---------------------------------subobject2-------------------------------\r\n");
					if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)//匹配子对象2成员"text"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.text,item->valuestring,strlen(item->valuestring));
					}
					
					
					if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)//匹配子对象2成员"code"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.code,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL) //匹配子对象2成员"temperature"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.temperature,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"mon")) != NULL) //匹配子对象2成员"mon"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.mon,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"day")) != NULL) //匹配子对象2成员"day"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.day,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"hour")) != NULL) //匹配子对象2成员"hour"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.hour,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"min")) != NULL) //匹配子对象2成员"min"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.min,item->valuestring,strlen(item->valuestring));
					}
					if((item = cJSON_GetObjectItem(subobject,"wday")) != NULL) //匹配子对象2成员"wday"
					{
						//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",item->type,item->string,item->valuestring);
						memcpy(results[0].now.wday,item->valuestring,strlen(item->valuestring));
					}
				}
				/* 匹配子对象3 */
				if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
				{
					//printf("---------------------------------subobject3-------------------------------\r\n");
					//printf("cJSON_GetObjectItem: type=%d, string is %s,valuestring=%s \r\n",subobject->type,subobject->string,subobject->valuestring);
					memcpy(results[0].last_update,item->valuestring,strlen(subobject->valuestring));
				}
			} 
		}
	}
	
	cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
	
	return 0;
}

int simple_atoi(char *source) //字符串转整形
{
	int length = strlen(source); //计算长度
	int sum = 0,i=0;
//for(int i=0;source[i]!='';i++) printf("source[%d]: %c",i,source[i]); 	//输出每个数字字符
	if(length!=1)
	{
		for(int i=0;i<length;i++)
		{
			sum += (source[i]-'0') * pow(10,(double)length-1-i); //字符转数字并合并
		}		
		return sum;
	}		
	else 
	{
		sum=source[0]-'0';
		return sum;
	}
}


int main(void)  
{ 
	u16 uart1Len;
	Results results[] = {{0}};
	u8 dtOLEDBuf[16];   			//OLED缓存器
	int weather=0;
	int day,x=0;
	char a;
	char Cooper[]={"Cooper"};
	//初始化
	//延时函数初始化 	 
	delay_init();
				  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	
	uart_init(115200);			//串口初始化为115200
	
	LED_Init();//LED初始化
	
	LCD_Init();//LCD初始化
	LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
	
	while(1) 
	{
		
Results results[] = {{0}};	
//串口1收到的信息
		if(USART_RX_STA&0x8000)
		{ 
			uart1Len=USART_RX_STA&0x3f;            			//得到此次接收到的数据长度   
			
			day=cJSON_WeatherParse(USART_RX_BUF, results);		//解析天气数据

		打印结构体内内容
		//			  ·("打印结构体内内容如下: \r\n");
		//			printf("%s \r\n",results[0].now.text);
		//			printf("%s \r\n",results[0].now.code);
		//			printf("%s \r\n",results[0].last_update);
		//清屏,重新显示屏幕内容
					LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
		//天气							
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s",results[0].now.code);
		//			printf("%s",results[0].now.code);
					weather=simple_atoi((char *)results[0].now.code);	
					switch(weather)
					{
							//晴天
							case 0:
							case 1:
							case 2:
							case 3:
								{
									LCD_ShowPicture(8,76,40,40,gImage_0);
									memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
									sprintf((char *)dtOLEDBuf,"%s",results[0].now.text);
									LCD_ShowString(70,82,(u8 *)dtOLEDBuf,LIGHTBLUE,BLACK,16,0);
								}break;
							//多云,阴天
							case 5:
							case 6:
							case 7:
							case 8:
							case 9:
								{
									LCD_ShowPicture(8,76,40,40,gImage_4);
									memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
									sprintf((char *)dtOLEDBuf,"%s",results[0].now.text);
									LCD_ShowString(70,82,(u8 *)dtOLEDBuf,LIGHTBLUE,BLACK,16,0);
								}break;
							//雨天
							case 10:
							case 11:
							case 12:
							case 13:
							case 14:
							case 15:
							case 16:
							case 17:
							case 18:
								{
									LCD_ShowPicture(8,76,40,40,gImage_14);
									memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
									sprintf((char *)dtOLEDBuf,"%s",results[0].now.text);
									LCD_ShowString(70,82,(u8 *)dtOLEDBuf,LIGHTBLUE,BLACK,16,0);
								}break;
							//雪天
							case 19:
							case 20:
							case 21:
							case 22:
							case 23:
							case 24:
							case 25:
								{
									LCD_ShowPicture(8,76,40,40,gImage_23);
									memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
									sprintf((char *)dtOLEDBuf,"%s",results[0].now.text);
									LCD_ShowString(70,82,(u8 *)dtOLEDBuf,LIGHTBLUE,BLACK,16,0);
								}break;	
							//其他
							default:
								{
									LCD_ShowPicture(8,76,40,40,gImage_4);
									memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
									sprintf((char *)dtOLEDBuf,"%s",results[0].now.text);
									LCD_ShowString(70,82,(u8 *)dtOLEDBuf,LIGHTBLUE,BLACK,16,0);
								}break;
						
					}		
//温度			(x,y)  x大→小    y 上小 下大
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s^C",results[0].now.temperature);
					LCD_ShowString(73,66,(u8 *)dtOLEDBuf,GRAYBLUE,BLACK,16,0);
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
//地点
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s",results[0].location.name);
					LCD_ShowString(60,100,(u8 *)dtOLEDBuf,CYAN,BLACK,16,0);	
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
//日期
		//月	
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s.",results[0].now.mon);
					LCD_ShowString(44,43,(u8 *)dtOLEDBuf,GRAYBLUE,BLACK,16,0);	
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
		//日
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%sth.",results[0].now.day);
					LCD_ShowString(4,43,(u8 *)dtOLEDBuf,GRAYBLUE,BLACK,16,0);	
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
		//周
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s",results[0].now.wday);
					LCD_ShowString(84,15,(u8 *)dtOLEDBuf,CYAN,BLACK,16,0);	
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
		//时
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s:",results[0].now.hour);
					LCD_ShowString(2,10,(u8 *)dtOLEDBuf,WHITE,BLACK,32,0);	
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
					
		//分
					memset(dtOLEDBuf, 0, sizeof(dtOLEDBuf));
					sprintf((char *)dtOLEDBuf,"%s",results[0].now.min);
					LCD_ShowString(50,10,(u8 *)dtOLEDBuf,WHITE,BLACK,32,0);					
					USART_RX_STA=0;   
					memset(USART_RX_BUF, 0, sizeof(USART_RX_BUF));
//分号(时分之间)
				LCD_ShowChar(33,8,':',YELLOW,BLACK,32,0);			
//划线		
				LCD_DrawLine(0,62,128,62,YELLOW);
//画圆圈
				x++;
				if(x==10)
				{
					x=0;
					LCD_ShowString(80,43,Cooper,YELLOW,BLACK,16,0);
				}
				Draw_Circle(103,44,x,LIGHTGREEN);
		}
        delay_ms(5);	
	}  
}

esp32代码编写

#include <Arduino.h>
#include <WiFi.h>
 
#include <ArduinoJson.h>
#include <HTTPClient.h>
#define NTP1 "ntp1.aliyun.com"
#define NTP2 "ntp2.aliyun.com"
#define NTP3 "ntp3.aliyun.com"

//填写WIFI入网信息
const char * ID = "自己WIFI名称";
const char * PASSWORD = "WIFI密码";

const String MONTH_NAMES[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; //月份
const String DAY_NAMES[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                                "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
                                "21", "22", "23", "24", "25", "26", "27", "28", "29", "30","31"}; //日
const String HOUR_NAMES[] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
                                  "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
                                  "21", "22", "23", "24"};//时
const String MIN_NAMES[] = {"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
                                "11", "12", "13","14", "15", "16", "17", "18", "19", "20",
                                "21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
                                "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
                                "41", "42", "43", "44", "45", "46", "47", "48", "49", "50",
                                "51", "52", "53", "54", "55", "56", "57", "58", "59", "60"}; //分
const String WDAY_NAMES[] = {"Sun.", "Mon.", "Tues.", "Wed.", "Thur.", "Fri.", "Sat."};                //星期

//天气相关参数
String API = "上文提到的私钥";
String WeatherURL = "";
String CITY = "自己所在城市的代码";
String url_xinzhi = "";
String Weather = "0";
String Temperature = "0";
String Name = "0";
 
long sum = 0;
 
/* 创建实例 */
 
HTTPClient http;
 
String GitURL(String api,String city)
{
  url_xinzhi =  "https://api.seniverse.com/v3/weather/now.json?key=";
  url_xinzhi += api;
  url_xinzhi += "&location=";
  url_xinzhi += city;
  url_xinzhi += "&language=en&unit=c";
  return url_xinzhi;
}
 
void ParseWeather(String url)
{  
  int Year,Mon,Day,Hour,Min,Wday;
  struct tm timeInfo; //声明一个结构体
  DynamicJsonDocument doc(1024); //分配内存,动态
  DynamicJsonDocument dat(1024);
  http.begin(url);
 
  int httpGet = http.GET();
  if(httpGet > 0)
  {
    //Serial.printf("HTTPGET is %d",httpGet);
    
    if(httpGet == HTTP_CODE_OK)
    {

       if (!getLocalTime(&timeInfo))
      { //一定要加这个条件判断,否则内存溢出
        //    Serial.println("Failed to obtain time");
        return;
      }
      String date = WDAY_NAMES[timeInfo.tm_wday];
      //  Serial.println(date.c_str());
      // sprintf_P(buff1, PSTR("%04d-%02d-%02d %s"), timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday, WDAY_NAMES[timeInfo.tm_wday].c_str());
      String shuju = String(timeInfo.tm_year + 1900); //年
      shuju += "-";
      shuju += timeInfo.tm_mon + 1; //月
      shuju += "-";
      shuju += timeInfo.tm_mday; //日
      shuju += " ";
      shuju += timeInfo.tm_hour; //时
      shuju += ":";
      shuju += timeInfo.tm_min;
      shuju += ":";
      shuju += timeInfo.tm_sec;
      shuju += " ";
      shuju += WDAY_NAMES[timeInfo.tm_wday].c_str(); //星期
      String json = http.getString();
      deserializeJson(doc, json);
//location
      dat["results"][0]["location"]["id"] = doc["results"][0]["location"]["id"].as<String>();
      dat["results"][0]["location"]["name"] = doc["results"][0]["location"]["name"].as<String>();
      dat["results"][0]["location"]["country"] = doc["results"][0]["location"]["country"].as<String>();
      dat["results"][0]["location"]["path"] = doc["results"][0]["location"]["path"].as<String>();
      dat["results"][0]["location"]["timezone"] = doc["results"][0]["location"]["timezone"].as<String>();
      dat["results"][0]["location"]["timezone_offset"] = doc["results"][0]["location"]["timezone_offset"].as<String>();
//now
      dat["results"][0]["now"]["text"] = doc["results"][0]["now"]["text"].as<String>();  
      dat["results"][0]["now"]["code"] = doc["results"][0]["now"]["code"].as<String>();
      dat["results"][0]["now"]["temperature"] = doc["results"][0]["now"]["temperature"].as<String>();
      dat["results"][0]["now"]["mon"]=MONTH_NAMES[timeInfo.tm_mon ].c_str();
      dat["results"][0]["now"]["day"]=DAY_NAMES[timeInfo.tm_mday].c_str();
      dat["results"][0]["now"]["hour"]=HOUR_NAMES[timeInfo.tm_hour].c_str();
      dat["results"][0]["now"]["min"]=MIN_NAMES[timeInfo.tm_min].c_str();
      dat["results"][0]["now"]["wday"]=WDAY_NAMES[timeInfo.tm_wday].c_str();
      dat["results"][0]["last_update"]= doc["results"][0]["last_update"].as<String>();
      char json_string[1024];
      serializeJson(dat,json_string);
      Serial.println(json_string);
    }
    else
    {
      Serial.printf("ERROR1!!");
    }
  }
  else
  {
    Serial.printf("ERROR2!!");
  }
  http.end();
}
void setup() 
{
  Serial.begin(115200);
 
  //==================wifi连接==================
  
//  Serial.println("WiFi:");
//  Serial.println(ID);
//  Serial.println("PASSWORLD:");
//  Serial.println(PASSWORD);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ID,PASSWORD);
  
  while(WiFi.status()!=WL_CONNECTED)
  {
    delay(500);
//    Serial.println("Connecting...");
  }
 
//  Serial.println("Connect OK!");
  //==================wifi连接==================
  WeatherURL = GitURL(API,CITY); 
  configTime(8 * 3600, 0, NTP1, NTP2, NTP3);
}
 
void loop() 
{
  // Serial.println("连接成功!");
  delay(20000);
}

esp32代码中所需的心知天气城市代码文档:城市代码

桌面天气全套文件:全套文件
包括源码以及图形库,字库等,word文档解答了遇到的问题。


总结

以上就是今天要讲的内容,本文介绍了桌面天气时钟的开发过程。
成品照片过几天会上传,屏幕由于操作失误烧掉了,重新购买了=-=


如果大家觉得还算有用的话
悄悄告诉你们一个催更小技巧
点赞、收藏、关注,可以加速更新嗷!!!


  • 7
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜猫喷发胶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值