3703|6

155

帖子

1

TA的资源

一粒金砂(高级)

楼主
 

【平头哥Sipeed LicheeRV 86 Panel测评】十五、lvgl日历控件和显示天气 [复制链接]

 

本篇结合本人前两篇的HTTP请求天气数据(通过“心知天气”网站)和lvgl显示图片及时间,在案例主界面上增加了日历显示和实时天气显示,先直接上图。

 

15-1 日历显示效果

 

1lvgl日历控件

calendarlvgl提供的“Extra widgets”组件之一,需要注意的是8.0版本后有几个API的传参发生了变化,本例使用8.3版本,设置日期是需要同时传递“年、月、日”三个参数。

本例使用的API有:lv_calendar_create()lv_canlendar_set_today_date()lv_calendar_set_showed_date()lv_calendar_header_arrow_create()

lv_calendar_create()函数用于实例化calendar控件,传参是控件的父容器指针,本例使用“lv_scr_act()”即系统屏幕。

 

15-2 函数lv_calendar_create()说明

 

lv_canlendar_set_today_date()函数用于设置当前日期,本人使用发现lvgl是附带万年历功能的,只要设置好当天的年月日,就可以自动生成正确的日历排布。函数传参分别是控件指针和年月日数据。

关于年月日参数有两点注意事项。一是v7版本中,传参通过lv_calendar_date_t结构体,其包含年月日三个成员。二是如果使用了C time库的struct tm,注意其中年份需要加上“1900”,而月份则需要加“1”。

 

15-3 函数lv_calendar_set_today_date()说明

 

lv_calendar_set_showed_date()函数用于设置日历当前显示页,也就是设置当前月份。本人实验的效果是当天日期框会自动高亮,如果想设置多个高亮日期,可以使用函数lv_calendar_set_highlighted_dates()

 

15-4 函数lv_calendar_set_showed_date()lv_calendar_set_highlighted_dates()说明

 

lv_calendar_header_arrow_create()函数用于向日历控件顶部增加“左、右箭头”两个按钮用于日历翻页(一页是一月)。此外,还有函数lv_calendar_header_dropdown_create()则是设置两个下拉列表分别用于选择年份和月份。这两个函数都只用传递日历控件指针一个参数,且是8.1版本新增API

2、日历和天气显示案例

本案例的思路是:1)在应用启动时,获取当前时间(上篇中已经实现),然后将时间保存在全局量“struct tm today”中,并利用变量“today”来初始化日历控件的日期数据。2)上篇实现的时间显示案例,通过lvgl定时器,每秒获取本地数据,此处在定时器回调中再增加一个每到正分钟发送“Linux条件变量”。3)同时,应用启动时建立两个线程——lvgl线程和请求天气线程,请求天气线程等待条件变量到来,开启一次天气数据请求过程。

本例代码结合本人“十三、利用TCP封装HTTP包请求天气信息”和“十四、lvgl显示图片和本地时间”两篇创建的案例,这里只给出改变部分。

 

/* Includes ------------------------------------------------------- */
// 增加头文件,cJSON用于解析JSON格式的天气数据
#include "cJSON.h"

/* Private macro -------------------------------------------------- */
// 增加请求天气数据相关的宏定义
#define HTTP_IP                "116.62.81.138"
#define HTTP_PORT              80
#define NOW                    "now.json"
#define API_KEY                "SK0LJ8FI2TP0L-IsQ"
#define CITY                   "tianjin"
#define REQ_PACK               "GET https://api.thinkpage.cn/v3/weather/%s?key=%s&location=%s&language=en&unit=c\r\n\r\n"
#define N                      1024
// struct for weather data 建立结构体存储解析后的天气数据
typedef struct {
    char id[16];
    char name[32];
    char country[16];
    char path[64];
    char timezone[32];
    char tz_offset[16];
    char text[16];
    char code[4];
    char temp[8];
    char last_update[32];
} weather_t;

/* Global variables ----------------------------------------------- */
// 增加显示天气的标签控件定义
lv_obj_t *weather_label;  //pointer of weather label instance
// 增加日历控件定义
lv_obj_t  *calendar;      //pointer of calendar instance
// 定义today变量存储当前日期,用于设置日历
struct tm today;          //
// 请求天气的线程ID
pthread_t reqweather_tid; //request weather thread id
// 请求天气线程等待的条件变量(min_cond)
// Linux中需要互斥量包含条件变量的使用,所以定义cond_mutex
pthread_mutex_t cond_mutex;  //mutex for 1-min cond
pthread_cond_t  min_cond; //1-min cond
/* Private functions ---------------------------------------------- */
int main(void) {
// other code from previous demo
// main()函数中创建互斥量、条件变量、请求天气线程
//by author. create mutex for 1-min cond
    if(pthread_mutex_init(&cond_mutex, NULL) != 0) {
        errlog("initialize cond mutex error");
    }

//by author. create condition for 1-min
    if(pthread_cond_init(&min_cond, NULL) != 0) {
        errlog("initialize 1 minute condition error");
    }

//by author. create request weather thread
    if(pthread_create(&reqweather_tid, NULL, thread_reqweather, (void *)0) != 0) {
        errlog("create request weather thread error");
    }

//by author. wait for thread exit, this demo should never be here.
    pthread_join(lvgl_tid, &retval);
    printf("lvgl thread exit, return value: %s\n", (char *)retval);
    pthread_join(reqweather_tid, &retval);
    printf("request weather thread exit, return value: %s\n", (char *)retval);
    pthread_mutex_destroy(&lvgl_mutex);
    pthread_mutex_destroy(&cond_mutex);
    pthread_cond_destroy(&min_cond);
    return 0;
}

void aita_CreateMainUI(void) {
// other code from previous demo
// aita_CreateMainUI()被main()函数调用,初始化主界面。
    //by author. create the weather label
    weather_label = lv_label_create(sys_scr);
    lv_label_set_text(weather_label, "         ");
    lv_obj_align(weather_label, LV_ALIGN_TOP_LEFT, 200, 120);
    //by author. create the calendar
    calendar = lv_calendar_create(sys_scr);
    lv_obj_set_size(calendar, 235, 235);
    lv_obj_align(calendar, LV_ALIGN_BOTTOM_LEFT, 10, -50);
    lv_calendar_set_today_date(calendar, today.tm_year+1900, today.tm_mon+1, today.tm_mday);
    lv_calendar_set_showed_date(calendar, today.tm_year+1900, today.tm_mon+1);
    lv_calendar_header_arrow_create(calendar);
}

// 增加正分钟发送条件变量
void sec_timer_cb(lv_timer_t *timer) {
    aita_GetTime();
    lv_label_set_text(main_label, main_label_text);
    if(today.tm_sec == 0) {
        //by author. send condition signal per whole minute
        pthread_cond_signal(&min_cond);
    }
}
// 增加对today的赋值
void aita_GetTime(void) {
    time_t    tsec;
    struct tm *tlocal;
    tsec = time(NULL);
    tlocal = localtime(&tsec);
    today = *tlocal;
    memset(main_label_text, 0, 32);
    strftime(main_label_text, 32, "%Y-%m-%d %a %H:%M:%S", tlocal);
}

// 请求天气线程业务逻辑
void *thread_reqweather(void *arg) {
    int sockfd;
    struct sockaddr_in serveraddr;
    socklen_t addrlen = sizeof(serveraddr);
    char sendbuf[N] = "";
    char recvbuf[N] = "";
    weather_t weather = {0};
    char w_string[64] = "";

    while(1) {
        pthread_mutex_lock(&cond_mutex);
        pthread_cond_wait(&min_cond, &cond_mutex);
        pthread_mutex_unlock(&cond_mutex);     
    //create socket
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            errlog("socket error");
        }
    //connect to server of seniverse.com
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr(HTTP_IP);
        serveraddr.sin_port = htons(HTTP_PORT);
        if((connect(sockfd, (struct sockaddr*)&serveraddr, addrlen)) < 0) {
            errlog("connect error");
        }
    //build & send request package
        memset(sendbuf, 0, N);
        sprintf(sendbuf, REQ_PACK, NOW, API_KEY, CITY);
        if(send(sockfd, sendbuf, N, 0) < 0) {
            errlog("send error");
        }
    //waiting server response
        if(recv(sockfd, recvbuf, N, 0) < 0) {
            errlog("recv error");
        }
        printf("recv: %s\n", recvbuf);
    //parse & print data,下面两个函数来自于“十三”案例
        aita_ParseJsonNow(recvbuf, &weather);
        aita_PrintWeather(&weather);
        close(sockfd);
        memset(recvbuf, 0, N);
    //show weather string
        memset(w_string, 0, 64);
        sprintf(w_string, "weather:%s temperatur:%s", weather.text, weather.temp);
        pthread_mutex_lock(&lvgl_mutex);
        lv_label_set_text(weather_label, w_string);
        pthread_mutex_unlock(&lvgl_mutex);       
    }
}

 

另外,本例在lvgl工程中增加了cJSON.ccJSON.h文件,Makefile也做出了调整,具体如下所示。

 

15-5 Makefile的修改

 

 

最新回复

这是什么开发环境,还要自己弄makefile?   详情 回复 发表于 2022-4-27 22:35
点赞 关注
 
 

回复
举报

7047

帖子

11

TA的资源

版主

沙发
 

这个界面做得很美,给你点个赞赞,专门UI设计的吗?

点评

谢谢,我是大学老师,计算机专业嵌入式方向教学的,真没想到还有人夸我的审美。本人纯理工宅,美学修养负值。  详情 回复 发表于 2022-4-27 18:46
 
 
 

回复

155

帖子

1

TA的资源

一粒金砂(高级)

板凳
 
lugl4313820 发表于 2022-4-27 13:35 这个界面做得很美,给你点个赞赞,专门UI设计的吗?

谢谢,我是大学老师,计算机专业嵌入式方向教学的,真没想到还有人夸我的审美。本人纯理工宅,美学修养负值。

点评

人肯定长得也帅,那肯定不差的啦,以后还得向老师多多请教!  详情 回复 发表于 2022-4-27 21:05
 
 
 

回复

7047

帖子

11

TA的资源

版主

4
 
sonicfirr 发表于 2022-4-27 18:46 谢谢,我是大学老师,计算机专业嵌入式方向教学的,真没想到还有人夸我的审美。本人纯理工宅,美学修养负 ...

人肯定长得也帅,那肯定不差的啦,以后还得向老师多多请教!

点评

客气了!  详情 回复 发表于 2022-4-28 10:31
 
 
 

回复

7671

帖子

2

TA的资源

五彩晶圆(高级)

5
 

这是什么开发环境,还要自己弄makefile?

点评

VScode开发LVGL框架,用于Tina Linux系统,因为使用了WSL(Windows Linux子系统),所以可以在Win10环境做交叉编译。  详情 回复 发表于 2022-4-28 10:32
个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 
 

回复

155

帖子

1

TA的资源

一粒金砂(高级)

6
 
lugl4313820 发表于 2022-4-27 21:05 人肯定长得也帅,那肯定不差的啦,以后还得向老师多多请教!

客气了!

 
 
 

回复

155

帖子

1

TA的资源

一粒金砂(高级)

7
 
freebsder 发表于 2022-4-27 22:35 这是什么开发环境,还要自己弄makefile?

VScode开发LVGL框架,用于Tina Linux系统,因为使用了WSL(Windows Linux子系统),所以可以在Win10环境做交叉编译。

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表