【平头哥Sipeed LicheeRV 86 Panel测评】十五、lvgl日历控件和显示天气
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="宋体">本篇结合本人前两篇的</font><font face="Times New Roman">HTTP</font><font face="宋体">请求天气数据(通过“心知天气”网站)和</font><font face="Times New Roman">lvgl</font><font face="宋体">显示图片及时间,在案例主界面上增加了日历显示和实时天气显示,先直接上图。</font></span></span></span></span></span></p><p style="text-indent:24.0000pt; text-align:justify"> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p style="text-align: center;"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">图</font><font face="Times New Roman">15-1 </font><font face="宋体">日历显示效果</font></span></span></span></span></span></p>
<p align="center" style="text-align:center"> </p>
<h2 style="text-align:justify"><span style="font-size:14pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-weight:bold"><b><span style="font-size:14.0000pt"><span style="font-family:宋体"><span style="font-weight:bold"><font face="Times New Roman">1</font><font face="宋体">、</font><font face="Times New Roman">lvgl</font><font face="宋体">日历控件</font></span></span></span></b></span></span></span></span></h2>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="Times New Roman">calendar</font><font face="宋体">是</font><font face="Times New Roman">lvgl</font><font face="宋体">提供的“</font><font face="Times New Roman">Extra widgets</font><font face="宋体">”组件之一,需要注意的是</font><font face="Times New Roman">8.0</font><font face="宋体">版本后有几个</font><font face="Times New Roman">API</font><font face="宋体">的传参发生了变化,本例使用</font><font face="Times New Roman">8.3</font><font face="宋体">版本,设置日期是需要同时传递“年、月、日”三个参数。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="宋体">本例使用的</font><font face="Times New Roman">API</font><font face="宋体">有:</font><font face="Times New Roman">lv_calendar_create()</font><font face="宋体">、</font><font face="Times New Roman">lv_canlendar_set_today_date()</font><font face="宋体">、</font><font face="Times New Roman">lv_calendar_set_showed_date()</font><font face="宋体">和</font><font face="Times New Roman">lv_calendar_header_arrow_create()</font><font face="宋体">。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="Times New Roman">lv_calendar_create()</font><font face="宋体">函数用于实例化</font><font face="Times New Roman">calendar</font><font face="宋体">控件,传参是控件的父容器指针,本例使用“</font><font face="Times New Roman">lv_scr_act()</font><font face="宋体">”即系统屏幕。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p style="text-align: center;"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">图</font><font face="Times New Roman">15-2 </font><font face="宋体">函数</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Times New Roman">lv_calendar_create()</font><font face="宋体">说明</font></span></span></span></span></span></p>
<p align="center" style="text-align:center"> </p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="Times New Roman">lv_canlendar_set_today_date()</font><font face="宋体">函数用于设置当前日期,本人使用发现</font><font face="Times New Roman">lvgl</font><font face="宋体">是附带万年历功能的,只要设置好当天的年月日,就可以自动生成正确的日历排布。函数传参分别是控件指针和年月日数据。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="宋体">关于年月日参数有两点注意事项。一是</font><font face="Times New Roman">v7</font><font face="宋体">版本中,传参通过</font><font face="Times New Roman">lv_calendar_date_t</font><font face="宋体">结构体,其包含年月日三个成员。二是如果使用了</font><font face="Times New Roman">C time</font><font face="宋体">库的</font><font face="Times New Roman">struct tm</font><font face="宋体">,注意其中年份需要加上“</font><font face="Times New Roman">1900</font><font face="宋体">”,而月份则需要加“</font><font face="Times New Roman">1</font><font face="宋体">”。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p style="text-align: center;"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">图</font><font face="Times New Roman">15-3 </font><font face="宋体">函数</font><font face="Times New Roman">lv_calendar_set_today_date()</font><font face="宋体">说明</font></span></span></span></span></span></p>
<p align="center" style="text-align:center"> </p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="Times New Roman">lv_calendar_set_showed_date()</font><font face="宋体">函数用于设置日历当前显示页,也就是设置当前月份。本人实验的效果是当天日期框会自动高亮,如果想设置多个高亮日期,可以使用函数</font><font face="Times New Roman">lv_calendar_set_highlighted_dates()</font><font face="宋体">。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p style="text-align: center;"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">图</font><font face="Times New Roman">15-4 </font><font face="宋体">函数</font><font face="Times New Roman">lv_calendar_set_showed_date()</font><font face="宋体">和</font><font face="Times New Roman">lv_calendar_set_highlighted_dates()</font><font face="宋体">说明</font></span></span></span></span></span></p>
<p align="center" style="text-align:center"> </p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="Times New Roman">lv_calendar_header_arrow_create()</font><font face="宋体">函数用于向日历控件顶部增加“左、右箭头”两个按钮用于日历翻页(一页是一月)。此外,还有函数</font><font face="Times New Roman">lv_calendar_header_dropdown_create()</font><font face="宋体">则是设置两个下拉列表分别用于选择年份和月份。这两个函数都只用传递日历控件指针一个参数,且是</font><font face="Times New Roman">8.1</font><font face="宋体">版本新增</font><font face="Times New Roman">API</font><font face="宋体">。</font></span></span></span></span></span></p>
<h2 style="text-align:justify"><span style="font-size:14pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-weight:bold"><b><span style="font-size:14.0000pt"><span style="font-family:宋体"><span style="font-weight:bold"><font face="Times New Roman">2</font><font face="宋体">、日历和天气显示案例</font></span></span></span></b></span></span></span></span></h2>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="宋体">本案例的思路是:</font><font face="Times New Roman">1</font><font face="宋体">)在应用启动时,获取当前时间(上篇中已经实现),然后将时间保存在全局量“</font><font face="Times New Roman">struct tm today</font><font face="宋体">”中,并利用变量“</font><font face="Times New Roman">today</font><font face="宋体">”来初始化日历控件的日期数据。</font><font face="Times New Roman">2</font><font face="宋体">)上篇实现的时间显示案例,通过</font><font face="Times New Roman">lvgl</font><font face="宋体">定时器,每秒获取本地数据,此处在定时器回调中再增加一个每到正分钟发送“</font><font face="Times New Roman">Linux</font><font face="宋体">条件变量”。</font><font face="Times New Roman">3</font><font face="宋体">)同时,应用启动时建立两个线程——</font><font face="Times New Roman">lvgl</font><font face="宋体">线程和请求天气线程,请求天气线程等待条件变量到来,开启一次天气数据请求过程。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="宋体">本例代码结合本人</font>“十三、利用<font face="Times New Roman">TCP</font><font face="宋体">封装</font><font face="Times New Roman">HTTP</font><font face="宋体">包请求天气信息”和“十四、</font><font face="Times New Roman">lvgl</font><font face="宋体">显示图片和本地时间”两篇创建的案例,这里只给出改变部分。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<pre>
<code>/* 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;
char name;
char country;
char path;
char timezone;
char tz_offset;
char text;
char code;
char temp;
char last_update;
} 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 = "";
char recvbuf = "";
weather_t weather = {0};
char w_string = "";
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);
}
}</code></pre>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<p style="text-indent:24.0000pt; text-align:justify"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:12.0000pt"><span style="font-family:宋体"><font face="宋体">另外,本例在</font><font face="Times New Roman">lvgl</font><font face="宋体">工程中增加了</font><font face="Times New Roman">cJSON.c</font><font face="宋体">和</font><font face="Times New Roman">cJSON.h</font><font face="宋体">文件,</font><font face="Times New Roman">Makefile</font><font face="宋体">也做出了调整,具体如下所示。</font></span></span></span></span></span></p>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<p class="imagemiddle" style="text-align: center;"></p>
<p style="text-align: center;"><span style="font-size:12pt"><span style="125%"><span style="font-family:"Times New Roman""><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">图</font><font face="Times New Roman">15-5 Makefile</font><font face="宋体">的修改</font></span></span></span></span></span></p>
<p align="center" style="text-align:center"> </p>
<p style="text-indent:24.0000pt; text-align:justify"> </p>
<p>这个界面做得很美,给你点个赞赞,专门UI设计的吗?</p>
lugl4313820 发表于 2022-4-27 13:35
这个界面做得很美,给你点个赞赞,专门UI设计的吗?
<p>谢谢,我是大学老师,计算机专业嵌入式方向教学的,真没想到还有人夸我的审美。本人纯理工宅,美学修养负值。<img height="52" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/titter.gif" width="48" /></p>
sonicfirr 发表于 2022-4-27 18:46
谢谢,我是大学老师,计算机专业嵌入式方向教学的,真没想到还有人夸我的审美。本人纯理工宅,美学修养负 ...
<p>人肯定长得也帅,那肯定不差的啦,以后还得向老师多多请教!</p>
<p>这是什么开发环境,还要自己弄makefile?</p>
lugl4313820 发表于 2022-4-27 21:05
人肯定长得也帅,那肯定不差的啦,以后还得向老师多多请教!
<p>客气了!</p>
freebsder 发表于 2022-4-27 22:35
这是什么开发环境,还要自己弄makefile?
<p>VScode开发LVGL框架,用于Tina Linux系统,因为使用了WSL(Windows Linux子系统),所以可以在Win10环境做交叉编译。</p>
页:
[1]