本帖最后由 xinmeng_wit 于 2022-5-1 21:20 编辑
一、介绍
上一篇帖子已经对TK499单片机和开发板进行了大致的介绍,并且基于TK499开发板进行了LVGL的开源图形库的移植。
具体详细信息可以参考帖子:【自选开发板活动】基于国产单片机TK499的GUI图形库LVGL移植
TK499开发板显著的特征除了分辨率为800*480的显示屏以外,还带有板载的wifi模块:esp8266。
正是因为有esp8266的存在,这款开发板具有很多无线通讯方面的可玩性。
这一篇帖子将使用esp8266与外网进行连接并获取实时天气信息并显示在LCD屏上。
二、功能实现
1、软硬件使用情况
- 开发环境:Keil MDK5.26.2
- 使用到的硬件资源:UART1、UART2、timer3、timer8、ADC
- esp8266配置为sta模式TCP client
以上用到的硬件资源中,UART1作为调试串口使用,打印关键信息便于调试;
UART2与esp8266连接;
timer3配置为1ms的中断,用于lvgl调度和单片机时基
timer8用于串口的超时定时器
ADC用于触摸,该单片机不需要外加触摸芯片,自带有触摸功能,是使用ADC的四个通道实现的。
2、esp8266使用到的指令
esp8266设置为STA模式
加入无线网络
是否启用多连接
连接到指定的服务器
设置为透传
3、天气数据的请求与解析
要获取天气信息就需要向天气网站请求天气数据,然后进行解析。
常用的天气网站有很多,比如大家熟悉的心知天气,还有YY天气;
我这篇使用的是YY天气,网址:http://www.yytianqi.com/
数据请求格式:
返回的数据格式:
显然,YY天气返回的数据是JSON格式的。
对于JSON格式的解析,有很多开源库可以很方便的解析出来,例如比较常用的cJSON库。
因为这段JSON数据非常简单,我这里就直接手动解析了,不想折腾开源库了。
4、代码实现
以上原理性的东西大概都说了,现在就开始骂代码的了。
下面对主要功能模块进行讲解。
主函数主要hi对各个模块进行初始化,然后显示一些初始化的界面:
int main(void)
{
uint32_t i;
RemapVtorTable();
SystemClk_HSEInit(RCC_PLLMul_20);//启动PLL时钟,12MHz*20=240MHz
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//2:2,全局性函数,仅需设置一次
UartInit(UART1,115200); //配置串口1,波特率为460800
TIM3_Config(1000,240);//1ms interrupt,use for LVGL period update
TIM8_Config(1000,240);//1ms,use for esp8266
lv_init();//初始化LVGL库
lv_port_disp_init();//LVGL显示相关的初始化
lv_port_indev_init();//LVGL触摸相关的初始化
welcome2_windows_init();//欢迎界面初始化
welcome_windows_show(welcome_label2,"www.21ic.com\r\nxinmeng_wit");//显示欢迎界面
Delay_nms ( 3000 );
lv_obj_del(welcome_label2);
welcome_windows_init();
welcome_windows_show(welcome_label1,"Initializing...");
//TIM10_Config(2000,240);//10ms
printf("Welcome to use HJR TK499!\r\n");
Delay_nms ( 200 );//等待esp8266上电完成
Uart2Init(115200);
ESP8266_Tcp_mode_Test();//sta TCP client
//test_demo();
//test_demo2();
//lv_demo_widgets();
while(1)//无限循环
{
char temp[50];
lv_task_handler();
if(uart2_rec_flag != 0)//需要接收uart2返回
{
printf("uart2_rec_flag:%d\r\n",uart2_rec_flag);
Delay_nms(1000);
weather_str[weather_cnt] = '\0';
printf("%d\r\n",weather_cnt);
printf("%s\r\n",(char *)&weather_str[0]);
//welcome_windows_show(welcome_label1,(char *)&weather_str[0]);
weather_data_analysis((char *)&weather_str[0]);
weather_cnt = 0;
uart2_rec_flag = 0;
}
}
}
天气信息的解析是最重要的部分,主要解析五个元素:
具体解析过程详见代码:
#include "lvgl.h"
#include "string.h"
#include "weather.h"
#include "gui_app.h"
t_weather_type weather_data;
//城市代码转换为城市的拼音
static void city_code_to_city(char *city_code, char *des)
{
if((city_code[0] != 'C') || (city_code[1] != 'H'))
{
return;
}
if((city_code[2] == '0') && (city_code[3] == '1'))
{
memcpy(des,"Beijing",sizeof("Beijing"));
}
else if((city_code[2] == '0') && (city_code[3] == '2'))
{
memcpy(des,(char *)"Shanghai",sizeof("Shanghai"));
printf("code:%s,%d\n",city_code,sizeof("Shanghai"));
}
else if((city_code[2] == '0') && (city_code[3] == '3'))
{
memcpy(des,"Tianjin",sizeof("Tianjin"));
}
else if((city_code[2] == '0') && (city_code[3] == '4'))
{
memcpy(des,"Chongqing",sizeof("Chongqing"));
}
}
//天气代码转换为天气英文
static void numtq_to_tq(char *num_code, char *des)
{
uint16_t temp = 0;
uint16_t len;
len = strlen(num_code);
if(len == 2)
{
temp = (num_code[0] - '0')* 10 + (num_code[1] - '0');//代码转为为数字
}
else if(len == 3)
{
temp = (num_code[0] - '0') * 100 + (num_code[1] - '0') * 10 + (num_code[2] - '0');//代码转为为数字
}
if(temp > 100)//超出范围,数据无效
{
return;
}
switch(temp)
{
case 0://晴
memcpy(des,"Sunny",sizeof("Sunny"));
break;
case 1://多云
memcpy(des,"Cloudy",sizeof("Cloudy"));
break;
case 2://阴
memcpy(des,"Overcast",sizeof("Overcast"));
break;
case 3://阵雨
memcpy(des,"1Shower",sizeof("1Shower"));
break;
case 4://雷阵雨
memcpy(des,"Thundershower",sizeof("Thundershower"));
break;
case 5://雷阵雨伴有冰雹
memcpy(des,"Thundershower with hail",sizeof("Thundershower with hail"));
break;
case 6://雨夹雪
memcpy(des,"1Sleet",sizeof("1Sleet"));
break;
case 7://小雨
memcpy(des,"Light rain",sizeof("Light rain"));
break;
case 8://中雨
memcpy(des,"Moderate rain",sizeof("Moderate rain"));
break;
case 9://大雨
memcpy(des,"Heavy rain",sizeof("Heavy rain"));
break;
case 10://暴雨
memcpy(des,"Storm",sizeof("Storm"));
break;
case 11://大暴雨
memcpy(des,"Heavy storm",sizeof("Heavy storm"));
break;
case 12://特大暴雨
memcpy(des,"Severe storm",sizeof("Severe storm"));
break;
case 13://阵雪
memcpy(des,"Snow flurry",sizeof("Snow flurry"));
break;
case 14://小雪
memcpy(des,"Light snow",sizeof("Light snow"));
break;
case 15://中雪
memcpy(des,"Moderate snow",sizeof("Moderate snow"));
break;
case 16://大雪
memcpy(des,"Heavy snow",sizeof("Heavy snow"));
break;
case 17://暴雪
memcpy(des,"Snowstorm",sizeof("Snowstorm"));
break;
case 18://雾
memcpy(des,"Fog",sizeof("Fog"));
break;
case 19://冻雨
memcpy(des,"Ice rain",sizeof("Ice rain"));
break;
case 20://沙尘暴
memcpy(des,"Duststorm",sizeof("Duststorm"));
break;
case 21://小到中雨
memcpy(des,"Light to moderate rain",sizeof("Light to moderate rain"));
break;
case 22://中到大雨
memcpy(des,"Moderate to heavy rain",sizeof("Moderate to heavy rain"));
break;
case 23://大到暴雨
memcpy(des,"Heavy rain to storm",sizeof("Heavy rain to storm"));
break;
case 24://暴雨到大暴雨
memcpy(des,"Storm to heavy storm",sizeof("Storm to heavy storm"));
break;
case 25://暴雨到特大暴雨
memcpy(des,"Heavy to severe storm",sizeof("Heavy to severe storm"));
break;
case 26://小到中雪
memcpy(des,"1Light to moderate snow",sizeof("1Light to moderate snow"));
break;
case 27://中到大雪
memcpy(des,"Moderate to heavy snow",sizeof("Moderate to heavy snow"));
break;
case 28://大到暴雪
memcpy(des,"Heavy snow to snowstorm",sizeof("Heavy snow to snowstorm"));
break;
case 29://浮尘
memcpy(des,"Dust",sizeof("Dust"));
break;
case 30://扬沙
memcpy(des,"Sand",sizeof("Sand"));
break;
case 31://强沙尘暴
memcpy(des,"Sandstorm",sizeof("Sandstorm"));
break;
case 32://浓雾
memcpy(des,"Dense fog",sizeof("Dense fog"));
break;
case 49://强浓雾
memcpy(des,"Heavy dense fog",sizeof("Heavy dense fog"));
break;
case 53://霾
memcpy(des,"Haze",sizeof("Haze"));
break;
case 54://中度霾
memcpy(des,"Moderate haze",sizeof("Moderate haze"));
break;
case 55://重度霾
memcpy(des,"Severe haze",sizeof("Severe haze"));
break;
case 56://严重霾
memcpy(des,"Hazardous haze",sizeof("Hazardous haze"));
break;
case 57://大雾
memcpy(des,"heavy fog",sizeof("heavy fog"));
break;
case 58://特强浓雾
memcpy(des,"Extra-heavy dense fog",sizeof("Extra-heavy dense fog"));
break;
case 99://无
memcpy(des,"Unknown",sizeof("Unknown"));
break;
case 100://刮风
memcpy(des,"Windy",sizeof("Windy"));
break;
default:
break;
}
}
//风力代码转换为风力英文
static void numfl_to_fl(char *num_code, char *des)
{
uint16_t temp = 0;
temp = num_code[0] - '0';
switch(temp)
{
case 0:
memcpy(des,"breeze",sizeof("breeze"));
break;
case 1:
memcpy(des,"3~4",sizeof("3~4"));
break;
case 2:
memcpy(des,"4~5",sizeof("4~5"));
break;
case 3:
memcpy(des,"5~6",sizeof("5~6"));
break;
case 4:
memcpy(des,"6~7",sizeof("6~7"));
break;
case 5:
memcpy(des,"7~8",sizeof("7~8"));
break;
case 6:
memcpy(des,"8~9",sizeof("8~9"));
break;
case 7:
memcpy(des,"9~10",sizeof("9~10"));
break;
case 8:
memcpy(des,"10~11",sizeof("10~11"));
break;
case 9:
memcpy(des,"11~12",sizeof("11~12"));
break;
default:
break;
}
}
void weather_data_analysis(char* str)
{
uint16_t index = 0;
char* temp;
char temp_str[50];
char temp_str2[50];
//判断是否收到了正确的天气数据帧
if(strstr(str,"Sucess") == NULL)
{
return;
}
//解析城市id
temp = strstr(str,"cityId");
index = temp - str;
memcpy(&weather_data.cityid[0],temp + CITY_ID_OFFSET,CITY_ID_SIZE);
weather_data.cityid[CITY_ID_SIZE] = '\0';//添加字符串结束符
city_code_to_city(&(weather_data.cityid[0]), temp_str2);//代码转换为城市拼音
printf("%s\r\n",&(weather_data.cityid[0]));
sprintf(temp_str,"city : %s",temp_str2);
weather_windows_show(city_label,temp_str);
//解析气温
temp = strstr(str,"qw");
index = temp - str;
memcpy(&weather_data.air_temperature[0],temp + QW_OFFSET,QW_SIZE);
weather_data.air_temperature[QW_SIZE] = 'C';
weather_data.air_temperature[QW_SIZE + 1] = '\0';//添加字符串结束符
sprintf(temp_str,"temp : %s",&(weather_data.air_temperature[0]));
weather_windows_show(temp_label,temp_str);
//解析湿度
temp = strstr(str,"sd");
index = temp - str;
memcpy(&weather_data.humidity[0],temp + SD_OFFSET,SD_SIZE);
weather_data.humidity[SD_SIZE] = '%';
weather_data.humidity[SD_SIZE + 1] = '\0';//添加字符串结束符
sprintf(temp_str,"humi : %s",&(weather_data.humidity[0]));
weather_windows_show(humi_label,temp_str);
//解析天气编码
temp = strstr(str,"numtq");
index = temp - str;
memcpy(&weather_data.weather_num[0],temp + TQ_NUM_OFFSET,TQ_NUM_SIZE);
weather_data.weather_num[TQ_NUM_SIZE] = '\0';//添加字符串结束符
numtq_to_tq(&(weather_data.weather_num[0]), temp_str2);//天气代码转换为天气英文
sprintf(temp_str,"weather : %s",temp_str2);
weather_windows_show(weather_label,temp_str);
//解析风力编码
temp = strstr(str,"numfl");
index = temp - str;
memcpy(&weather_data.wind_power[0],temp + FL_NUM_OFFSET,FL_NUM_SIZE);
weather_data.wind_power[FL_NUM_SIZE] = '\0';//添加字符串结束符
numfl_to_fl(&(weather_data.wind_power[0]), temp_str2);
sprintf(temp_str,"wind : %s",temp_str2);
weather_windows_show(wind_label,temp_str);
//解析更新时间
temp = strstr(str,"lastUpdate");
index = temp - str;
memcpy(&weather_data.update_time[0],temp + UPDATE_TIME_OFFSET,UPDATE_TIME_SIZE);
weather_data.update_time[UPDATE_TIME_SIZE] = '\0';//添加字符串结束符
sprintf(temp_str,"lastUpdate : %s",&(weather_data.update_time[0]));
weather_windows_show(update_label,temp_str);
}
其它相关的都比较简单,不在这里详细讲解,如有疑问,可以线上或向下详细沟通。
三、效果图片
视频演示
|