本帖最后由 小浪先生 于 2024-9-30 15:24 编辑
1.工程搭建
工程搭建我遇到的问题,估计大家都会遇到,在我往期的帖子里可以看到。我是利用helloword工程一点点搭建的,对理解工程框架很有帮助,有问题可以留言探讨。以下是我往期的帖子:
环境搭建
查找AiPI-Eyes-R1/R2 特定的 boot2及验证固件
2.工程框架
天气时钟工程大致可以分为三部分,
1.连接wifi;
2.请求api,获取天气;
3.GUI界面显示
2.1连接WiFi
连接wifi和http请求部分我是参考的这篇文章【教程贴】M61-32S系列连接Wifi 且发送HTTP请求。连接wifi部分不需要改动,http请求部分,确实会像这位博主所说的,会有卡死的的几率,我查阅资料发现,使用的recv函数是死等待,请求没有返回时,程序会跑飞,我在recv前面加入了下面几行代码设置了超时时间,算是暂时解决了这个问题,我这边跑程序一两个小时没有卡死,还需进一步验证测试。
// 设置recv超时时间
struct timeval tv_out;
tv_out.tv_sec = 5;
tv_out.tv_usec = 0;
2.2获取天气
天气api是采用的新知天气api获取近3天的天气,前面http请求获取的数据是json数据,利用开源的cJSON库进行解析。cJSON库下载链接。
网上很多人说,在cJSON库解析过程中,很容易卡死,那是因为没有及时删除cJSON对象。每次解析完都要删除,不然解析次数多了就会卡死。
cJSON_Delete(root); /*每次调用cJSON_Parse函数后,都要释放内存*/
解析代码如下:
int weather_info_parse(char *weather_data_buf)
{
// 对接收到的数据作相应的处理
uint8_t i, j;
uint8_t result_array_size = 0;
uint8_t daily_array_size = 0;
cJSON *root = NULL;
cJSON *item = NULL;
cJSON *results_root = NULL;
cJSON *daily_root = NULL;
root = cJSON_Parse(weather_data_buf);
if (!root)
{
// ESP_LOGI(TAG, "Error before: [%s]\n", cJSON_GetErrorPtr());
LOG_I("Error before: [%s]\r\n", cJSON_GetErrorPtr());
cJSON_Delete(root); /*每次调用cJSON_Parse函数后,都要释放内存*/
return -1;
}
// ESP_LOGI(TAG, "%s\r\n", cJSON_Print(root)); /*将完整的数据以JSON格式打印出来*/
cJSON *Presult = cJSON_GetObjectItem(root, "results"); /*results 的键值对为数组,*/
result_array_size = cJSON_GetArraySize(Presult); /*求results键值对数组中有多少个元素*/
// ESP_LOGI(TAG, "Presult array size is %d\n",result_array_size);
for (i = 0; i < result_array_size; i++)
{
cJSON *item_results = cJSON_GetArrayItem(Presult, i);
char *sresults = cJSON_PrintUnformatted(item_results);
results_root = cJSON_Parse(sresults);
if (!results_root)
{
// ESP_LOGI(TAG, "Error before: [%s]\n", cJSON_GetErrorPtr());
LOG_I("Error before: [%s]\r\n", cJSON_GetErrorPtr());
cJSON_Delete(root); /*每次调用cJSON_Parse函数后,都要释放内存*/
return -1;
}
/*-------------------------------------------------------------------*/
cJSON *Plocation = cJSON_GetObjectItem(results_root, "location");
item = cJSON_GetObjectItem(Plocation, "id");
user_sen_config.id = cJSON_Print(item);
// ESP_LOGI(TAG, "id:%s\n", user_sen_config.id); /*逐个打印*/
item = cJSON_GetObjectItem(Plocation, "name");
user_sen_config.name = cJSON_Print(item);
// ESP_LOGI(TAG, "name:%s\n", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "country");
user_sen_config.country = cJSON_Print(item);
// ESP_LOGI(TAG, "country:%s\n", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "path");
user_sen_config.path = cJSON_Print(item);
// ESP_LOGI(TAG, "path:%s\n", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "timezone");
user_sen_config.timezone = cJSON_Print(item);
// ESP_LOGI(TAG, "timezone:%s\n", cJSON_Print(item));
item = cJSON_GetObjectItem(Plocation, "timezone_offset");
user_sen_config.timezone_offset = cJSON_Print(item);
// ESP_LOGI(TAG, "timezone_offset:%s\n", cJSON_Print(item));
/*-------------------------------------------------------------------*/
cJSON *Pdaily = cJSON_GetObjectItem(results_root, "daily");
daily_array_size = cJSON_GetArraySize(Pdaily);
// ESP_LOGI(TAG, "Pdaily array size is %d\n",daily_array_size);
for (j = 0; j < daily_array_size; j++)
{
cJSON *item_daily = cJSON_GetArrayItem(Pdaily, j);
char *sdaily = cJSON_PrintUnformatted(item_daily);
daily_root = cJSON_Parse(sdaily);
if (!daily_root)
{
LOG_I("Error before: [%s]\r\n", cJSON_GetErrorPtr());
return -1;
}
item = cJSON_GetObjectItem(daily_root, "date");
user_sen_config.day_config[j].date = item->valuestring; // cJSON_Print(item)
item = cJSON_GetObjectItem(daily_root, "text_day");
user_sen_config.day_config[j].text_day = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "code_day");
user_sen_config.day_config[j].code_day = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "text_night");
user_sen_config.day_config[j].text_night = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "code_night");
user_sen_config.day_config[j].code_night = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "high");
user_sen_config.day_config[j].high = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "low");
user_sen_config.day_config[j].low = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "rainfall");
user_sen_config.day_config[j].rainfall = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "precip");
user_sen_config.day_config[j].precip = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_direction");
user_sen_config.day_config[j].wind_direction = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_direction_degree");
user_sen_config.day_config[j].wind_direction_degree = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_speed");
user_sen_config.day_config[j].wind_speed = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "wind_scale");
user_sen_config.day_config[j].wind_scale = cJSON_Print(item);
item = cJSON_GetObjectItem(daily_root, "humidity");
user_sen_config.day_config[j].humidity = cJSON_Print(item);
cJSON_Delete(daily_root); /*每次调用cJSON_Parse函数后,都要释放内存*/
}
/*-------------------------------------------------------------------*/
item = cJSON_GetObjectItem(results_root, "last_update");
user_sen_config.last_update = cJSON_Print(item);
cJSON_Delete(results_root); /*每次调用cJSON_Parse函数后,都要释放内存*/
}
cJSON_Delete(root); /*每次调用cJSON_Parse函数后,都要释放内存*/
return 0;
}
2.3GUI界面设计
在配置完工程所需的LVGL配置后,你可能会发现,自己配置的LVGL程序并不能执行,而且..\AiPi-Open-Kits\aithinker_Ai-M6X_SDK\examples下的lvgl示例也不能正确执行,不要怀疑自己,自己配置可能是没问题的。具体解决方法参考小安派R2工程移植LVGL后不运行【暂时解决】我之前写的这篇帖子。
GUI设计是利用NXP的GUI Guider进行设计的,这里介绍一下怎么移植他的文件,当你程序配置好LVGL组件并能正常执行demo后,将GUI工程中的custom和generated文件夹放入自己的工程中,在Cmake.List文件中配置好路径,可能generated文件夹中的images文件夹中的生成的图片可能会报错,只需要将\lgvl\lvgl.h改为lvgl.h即可。
在mian.c中加入头文件
// lvgl
#include "gui_guider.h"
#include "events_init.h"
在mian函数中实例化对象
setup_ui(&guider_ui);
events_init(&guider_ui);
就可以正常显示通过GUI Guider设计的界面了,我这里是用的FreeRTOS的任务调用的lvgl处理函数:
void lvgl_task(void *pvParameters)
{
while (1)
{
// LOG_I("lvgl_task is runing...\r\n");
lv_task_handler();
vTaskDelay(1);
// bflb_mtimer_delay_ms(1);
}
}
下面是我用GUI Guider设计,很简单的一个界面。
3.结果展示