【平头哥RVB2601创意应用开发】环境监测终端03-使用LVGL设计界面
[复制链接]
本篇文章介绍基于LVGL库在RVB2601开发板自带的OLED显示屏上设计界面。
RVB2601开发板内置了一款分辨率为128*64的单色OLED显示屏,并且基于此平台移植完成了开源的LVGL GUI库。此前并没有使用过LVGL GUI库,这次正好尝试一下,因此在网上一通搜索教程。正好找到了别人翻译好的使用手册,附在本文附件中,有需要的同学可以下载。
首先设计界面草稿。如下图所示,我计划在屏幕上显示5行信息。第一行,标题,直接使用标签显示即可。第二行,温度,左边字段不需要更新,右边字段需要定时刷新,也全部使用标签显示。第三行和第四行分别是湿度和噪音水平,和温度显示采用一样方法。第五行计划做一个指示条,用来动态指示噪音的实时幅度,这样查看起来比较直观。
图1、界面草图
实际设计的时候遇到各种问题。首先是如何显示中文,经查询得知要自己制作内置字库并添加,看了几个教程,很繁琐的样子,本人犯懒了,决定跳过这个中文显示,改用英文也是一样。
下一个问题是默认使用的英文字体是“LV_FONT_MONTSERRAT_14”比较大,如果显示5行看着太挤了,通过更改配置项使用“LV_FONT_MONTSERRAT_12”字体相对好一点。我还试了改成更小的字体,有点惨不忍睹,都不能分辨了,有点像大片上的火星文。具体修改方法如下图。
图2、修改字体
接下来实际编程显示文字。做标题显示的时候,看到LVGL支持滚动显示,为了体现咱的学习成果,把原计划的两个单词的标题改成了一句话,让它在最上面滚动显示,比较好玩。具体设置方式参见下面代码。
在设置温度显示的时候,需要显示浮点数,我按照常规的方式写代码发现不能正常显示,然后查阅资料发现应该是为了提高效率,默认设置成了不支持浮点模式。本来想查手册改成支持浮点模式,后面看到有人采用了更妙的方法解决了。就是先将浮点数格式化成字符串,然后再以字符串显示就没问题了,我按照此方法操作,顺利解决此问题,具体方法参照下面代码。
最后一个要实现的是噪音指示条。经过反复查阅手册,最终确定使用进度条“LV_BAR”控件设计。直接按照手册简单例程搞上去后,发现两端都是圆角,不是我喜欢了类型。然后一通大搜索,网络是个好东西,又被我找到解决方案了,感兴趣的朋友可以参考以下帖子。
https://www.csdn.net/tags/MtTaEg4sMjI1OTA0LWJsb2cO0O0O.html
经过我反复修改和调试,终于把界面框架搭建出来,显示效果如下图。
图3、界面框架
整个框架初始化代码如下。
lv_obj_t *pGui_label_temp;
lv_obj_t *pGui_label_humi;
lv_obj_t *pGui_label_noise;
lv_obj_t *pGui_bar_noise;
static void gui_label_create(void)
{
char cdata[10] = { 0 };
lv_obj_t *p_label_title = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(p_label_title, LV_LABEL_LONG_SROLL_CIRC); /*滚动显示*/
lv_obj_set_width(p_label_title, 160);
lv_label_set_text(p_label_title, "Hello EEWOLRD,This is a Environment Monitor based on RVB2601.");
lv_obj_align(p_label_title, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_t *p_label_temp = lv_label_create(lv_scr_act(), NULL);
lv_label_set_align(p_label_temp, LV_LABEL_ALIGN_LEFT);
lv_obj_set_pos(p_label_temp, 0, 12);
lv_obj_set_size(p_label_temp, 128, 64);
lv_label_set_text(p_label_temp, "Temperature:");
lv_obj_t *p_label_humi = lv_label_create(lv_scr_act(), NULL);
lv_label_set_align(p_label_humi, LV_LABEL_ALIGN_LEFT);
lv_obj_set_pos(p_label_humi, 0, 24);
lv_obj_set_size(p_label_humi, 128, 64);
lv_label_set_text(p_label_humi, "Humidity:");
lv_obj_t *p_label_noise = lv_label_create(lv_scr_act(), NULL);
lv_label_set_align(p_label_noise, LV_LABEL_ALIGN_LEFT);
lv_obj_set_pos(p_label_noise, 0, 36);
lv_obj_set_size(p_label_noise, 128, 64);
lv_label_set_text(p_label_noise, "Noise level:");
pGui_bar_noise = lv_bar_create(lv_scr_act(), NULL);
lv_obj_set_size(pGui_bar_noise, 120, 10);
lv_obj_align(pGui_bar_noise, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -1);
lv_bar_set_anim_time(pGui_bar_noise, 200);
lv_bar_set_range(pGui_bar_noise, 1, 100);
lv_bar_set_type(pGui_bar_noise, LV_BAR_TYPE_NORMAL);
lv_bar_set_value(pGui_bar_noise, 50, LV_ANIM_OFF);
lv_obj_set_style_local_radius(pGui_bar_noise, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, 0); /*Add a local style*/
lv_obj_set_style_local_bg_color(pGui_bar_noise, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLACK);
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, LV_STATE_DEFAULT, 0);//这里的参数0意思是进度条的指示器样式弧度为零,也就是直角。
lv_style_set_bg_color(&style, LV_STATE_DEFAULT, LV_COLOR_WHITE);//进度条背景颜色
lv_style_set_border_width(&style, LV_STATE_DEFAULT, 1); //进度条背景线条宽度
lv_style_set_border_color(&style, LV_STATE_DEFAULT, LV_COLOR_BLACK);//颜色
lv_style_set_pad_top(&style, LV_STATE_DEFAULT, 2);//指示器到背景四周的距离
lv_style_set_pad_bottom(&style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_left(&style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_right(&style, LV_STATE_DEFAULT, 2);
lv_obj_add_style(pGui_bar_noise, LV_BAR_TYPE_NORMAL, &style);//样式加到进度条中
//https://www.csdn.net/tags/MtTaEg4sMjI1OTA0LWJsb2cO0O0O.html
pGui_label_temp = lv_label_create(lv_scr_act(), NULL);
lv_label_set_align(pGui_label_temp, LV_LABEL_ALIGN_RIGHT);
lv_obj_set_pos(pGui_label_temp, 90, 12);
lv_obj_set_size(pGui_label_temp, 128, 64);
sprintf((char*)cdata, "%.1fC", 25.68);//格式化输出 浮点数转成字符串输出
lv_label_set_text_fmt(pGui_label_temp,"%s", (const char*)cdata);
pGui_label_humi = lv_label_create(lv_scr_act(), NULL);
lv_label_set_align(pGui_label_humi, LV_LABEL_ALIGN_RIGHT);
lv_obj_set_pos(pGui_label_humi, 90, 24);
lv_obj_set_size(pGui_label_humi, 128, 64);
sprintf((char*)cdata, "%.1f%%", 55.8);//格式化输出 浮点数转成字符串输出
lv_label_set_text_fmt(pGui_label_humi,"%s", (const char*)cdata);
pGui_label_noise = lv_label_create(lv_scr_act(), NULL);
lv_label_set_align(pGui_label_noise, LV_LABEL_ALIGN_RIGHT);
lv_obj_set_pos(pGui_label_noise, 90, 36);
lv_obj_set_size(pGui_label_noise, 128, 64);
lv_label_set_text_fmt(pGui_label_noise, "%ddB", 55);
}
static void gui_lvgl_task(void *arg)
{
lv_init();
/*Initialize for LittlevGL*/
oled_init();
/*Select display 1*/
// demo_create();
gui_label_create();
while (1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_task_handler();
aos_msleep(5);
lv_tick_inc(1);
}
}
由于我还没有调通各个参数的检测程序,这块只好先创建一个任务,制造了模拟数据,让界面先动起来,展示效果。代码如下。
struct Result_S
{
float temp;
float humi;
int noise;
}res_data;
static void res_update_task(void *arg)
{
int num_temp = 200;
char cdata[10] = { 0 };
while(1)
{
num_temp++;
if(num_temp>1000)
{
num_temp = 200;
}
res_data.temp = num_temp / 20.0;
res_data.humi = num_temp / 10.0;
res_data.noise = num_temp % 99;
sprintf((char*)cdata, "%.1fC", res_data.temp);//格式化输出 浮点数转成字符串输出
lv_label_set_text_fmt(pGui_label_temp,"%s", (const char*)cdata);
sprintf((char*)cdata, "%.1f%%", res_data.humi);//格式化输出 浮点数转成字符串输出
lv_label_set_text_fmt(pGui_label_humi,"%s", (const char*)cdata);
lv_label_set_text_fmt(pGui_label_noise, "%ddB", res_data.noise);
lv_bar_set_value(pGui_bar_noise, res_data.noise+1, LV_ANIM_OFF);
aos_msleep(500);
}
}
界面动态效果如下。等将来把检测参数调通,将结果赋给对应的变量就能完成正式的界面显示。
图4、动态显示效果
至此,环境监测终端界面显示设计完成,通过此次实操,基本了解使用LVGL设计UI的过程,为后边设计UI又增加了一个新思路。
LVGL Documentation.zip
(5.34 MB, 下载次数: 12)
|