> 文档中心 > 单片机---HLK-W801图形框架LVGL下开发(一)

单片机---HLK-W801图形框架LVGL下开发(一)


知识点

《单片机—HLK-W801并口驱动ST7789》
《单片机—HLK-W801驱动触摸屏》
《单片机—HLK-W801图形框架LVGL移植》

简单介绍

根据前面的知识点内容,一步一步走了过来,实现了lvgl在HLK801上的运行,还是挺让人欣慰的,没有遇到让人半途而废的坑,这就和减肥一个道理,坚持下来,以后还能多吃点。
在这里插入图片描述
在前面的基础上,这次来学习一下绘制一个简单的界面,做一个简单的时钟显示。其实市面上很多类似的智能wifi时钟,都是在这个基础上实现的,能够通过网络同步时间,并且能够获得天气信息并显示出来。
今天就做个简单的RTC时钟,学习一下界面的绘制。

界面绘制

代码参考自LVGL8制作简易时钟
在这里插入图片描述
修改了全屏的黑色背景,其他部分没有修改。因为背景太白,有点伤眼。
在这里插入图片描述

界面部分

void lvgl_clock_start(){    static lv_style_t date_time_clock_style; // 最外层对象样式    lv_style_reset(&date_time_clock_style); // 重置样式    lv_style_init(&date_time_clock_style); // 初始化样式      lv_style_set_radius(&date_time_clock_style, 0); // 设置样式圆角,去掉圆角    lv_style_set_bg_opa(&date_time_clock_style, LV_OPA_100); // 设置样式背景透明度,完全不透    lv_style_set_border_width(&date_time_clock_style, 0); // 设置样式边框宽度    lv_style_set_bg_color(&date_time_clock_style, lv_color_black()); // 设置样式背景颜色,黑色    lv_style_set_pad_left(&date_time_clock_style, 1); // 设置样式左边padding填充宽度    lv_style_set_pad_right(&date_time_clock_style, 1); // 设置样式右边padding填充宽度    lv_style_set_pad_top(&date_time_clock_style, 0); // 设置样式顶部padding填充宽度    lv_style_set_pad_bottom(&date_time_clock_style, 0); // 设置样式底部padding填充宽度     static lv_style_t time_style; // 时间对象样式    lv_style_reset(&time_style);    lv_style_init(&time_style);    lv_style_set_bg_opa(&time_style, LV_OPA_COVER);    lv_style_set_border_width(&time_style, 0);    lv_style_set_radius(&time_style, 5);    lv_style_set_bg_color(&time_style, lv_palette_main(LV_PALETTE_BLUE));    lv_style_set_pad_left(&time_style, 0);    lv_style_set_pad_right(&time_style, 0);    lv_style_set_pad_top(&time_style, 0);    lv_style_set_pad_bottom(&time_style, 0);     static lv_style_t date_style; // 日期对象样式    lv_style_reset(&date_style);    lv_style_init(&date_style);    lv_style_set_bg_opa(&date_style, LV_OPA_COVER);    lv_style_set_border_width(&date_style, 0);    lv_style_set_radius(&date_style, 5);    lv_style_set_bg_color(&date_style, lv_palette_main(LV_PALETTE_BLUE));    lv_style_set_pad_left(&date_style, 0);    lv_style_set_pad_right(&date_style, 0); /* Time font */    static lv_style_t time_label_style; // 时间标签样式    lv_style_reset(&time_label_style); // 重置样式    lv_style_init(&time_label_style); // 初始化样式    lv_style_set_text_color(&time_label_style , lv_color_white()); // 设置标签样式文本颜色    lv_style_set_text_font(&time_label_style, &lv_font_montserrat_32); // 设置字体风格    lv_style_set_text_opa(&time_label_style, LV_OPA_COVER); // 设置字体透明度    lv_style_set_bg_opa(&time_label_style, LV_OPA_0); // 设置样式背景透明度 /* Date font */    static lv_style_t date_label_style; // 日期标签样式    lv_style_reset(&date_label_style);    lv_style_init(&date_label_style);    lv_style_set_text_opa(&date_label_style, LV_OPA_COVER);    lv_style_set_bg_opa(&date_label_style, LV_OPA_0);    lv_style_set_text_color(&date_label_style , lv_color_white());    lv_style_set_text_font(&date_label_style, &lv_font_montserrat_16); /* Week font */    static lv_style_t week_lable_style; // 日期标签样式    lv_style_reset(&week_lable_style);    lv_style_init(&week_lable_style);    lv_style_set_text_opa(&week_lable_style, LV_OPA_COVER);    lv_style_set_bg_opa(&week_lable_style, LV_OPA_0);    lv_style_set_text_color(&week_lable_style, lv_color_white());    lv_style_set_text_font(&week_lable_style, &lv_font_montserrat_16); /* Time & Date */    lv_obj_t *time_date_obj = lv_obj_create(lv_scr_act()); // 基于屏幕创建时间日期对象    if (time_date_obj == NULL)    { printf("[%s:%d] time_date_obj create failed\n", __FUNCTION__, __LINE__); return;    } lv_obj_set_size(time_date_obj, 320, 240); // 设置对象大小    lv_obj_center(time_date_obj); // 对象居屏幕中间显示lv_obj_add_style(time_date_obj, &date_time_clock_style, LV_STATE_DEFAULT); //给time_date_obj对象添加样式     /*Time display*/    lv_obj_t *time_obj = lv_obj_create(time_date_obj); // 基于time_date_obj对象创建时间对象    if (time_obj == NULL)    { printf("[%s:%d] time_obj create failed\n", __FUNCTION__, __LINE__); return;    }     lv_obj_set_size(time_obj, 158, 100); // 设置对象大小    lv_obj_align_to(time_obj, time_date_obj, LV_ALIGN_LEFT_MID, 0, 0); // 设置time_obj对象基于time_date_obj对象左边中间对齐    lv_obj_add_style(time_obj, &time_style, LV_STATE_DEFAULT);  // 给time_obj对象添加样式     static lv_clock_t lv_clock = { 0 };     lv_clock.time_label = lv_label_create(time_obj); // 基于time_obj对象创建时间显示标签对象 lv_clock.time_label    if (lv_clock.time_label == NULL)    { printf("[%s:%d] time_label create failed\n", __FUNCTION__, __LINE__); return ;    }     lv_obj_add_style(lv_clock.time_label, &time_label_style, LV_STATE_DEFAULT); // 给对象 lv_clock.time_label添加样式     /*Date display*/    lv_obj_t *date_obj = lv_obj_create(time_date_obj); // 基于time_date_obj对象创建date_obj对象    if (date_obj == NULL)    { printf("[%s:%d] date_obj create failed\n", __FUNCTION__, __LINE__); return ;    }    lv_obj_set_size(date_obj, 158, 100); // 设置对象大小    lv_obj_align_to(date_obj, time_date_obj, LV_ALIGN_RIGHT_MID, 0, 0); //设置date_obj对象基于time_date_obj对象右边中部对齐    lv_obj_add_style(date_obj, &date_style, LV_STATE_DEFAULT); // 给date_obj对象添加样式     lv_clock.date_label = lv_label_create(date_obj); // 基于date_obj对象创建lv_clock.date_label日期显示对象    if (lv_clock.date_label == NULL)    { printf("[%s:%d] date_label create failed\n", __FUNCTION__, __LINE__); return ;    }    lv_obj_add_style(lv_clock.date_label, &date_label_style, LV_STATE_DEFAULT); // 给lv_clock.date_label对象添加样式     /*Week display*/    lv_clock.weekday_label = lv_label_create(date_obj); // 基于date_obj对象创建星期显示lv_clock.weekday_label对象    if (lv_clock.weekday_label == NULL)    { printf("[%s:%d] weekday_label create failed\n", __FUNCTION__, __LINE__); return;    }    lv_obj_add_style(lv_clock.weekday_label, &week_lable_style, LV_STATE_DEFAULT); // 给对象lv_clock.weekday_label添加样式     // 设置时间标签lv_clock.time_label对象基于父对象居中对齐    lv_obj_align_to(lv_clock.time_label, lv_obj_get_parent(lv_clock.time_label), LV_ALIGN_CENTER, 0, 0);     // 设置时间标签lv_clock.date_label对象基于父对象顶部中间对齐    lv_obj_align_to(lv_clock.date_label, lv_obj_get_parent(lv_clock.date_label), LV_ALIGN_TOP_MID, 2, 0);    // 设置时间标签lv_clock.weekday_label对象基于父对象底部中间对齐    lv_obj_align_to(lv_clock.weekday_label, lv_obj_get_parent(lv_clock.weekday_label), LV_ALIGN_BOTTOM_MID, -2, 0);     lv_timer_t* task_timer = lv_timer_create(clock_date_task_callback, 200, (void *)&lv_clock); // 创建定时任务,200ms刷新一次    if (task_timer == NULL)    { printf("[%s:%d] lv_timer_create failed\n", __FUNCTION__, __LINE__);    }}

RTC部分

前面的代码创建了定时任务,来定时获取时间并显示,这里我们只是简单的使用了一下HLK-W801的RTC模块,用来实时获取时间并显示。
简单也要学习一下,知识源自于demo。

在这里插入图片描述

RTC初始化,这里定义了时钟的初始化,内部初始化了RTC的时间,然后启动了RTC

static void RTC_Init(void){hpmu.Instance = PMU;hpmu.ClkSource = PMU_CLKSOURCE_32RC;HAL_PMU_Init(&hpmu);}static void CLOCK_Init(void){RTC_TimeTypeDef time;RTC_Init();time.Year = 122;time.Month = 3;time.Date = 10;time.Hours = 15;time.Minutes = 37;time.Seconds = 10;HAL_PMU_RTC_Start(&hpmu, &time);}

然后我们在定时任务的回调函数中使用了时间的获取。

static void clock_date_task_callback(lv_timer_t *timer){    static const char *week_day[7] = { "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" };    static struct tm *time_info;RTC_TimeTypeDef time;HAL_PMU_RTC_GetTime(&hpmu, &time);    int year = (time.Year + 1900);    int month = time.Month;    int day = time.Date;    int weekday = CaculateWeekDay(year,month,day);    int hour =time.Hours;    int minutes = time.Minutes;    int second = time.Seconds;     if (timer != NULL && timer->user_data != NULL)    { lv_clock_t * clock = (lv_clock_t *)(timer->user_data); if (clock->time_label != NULL) {     lv_label_set_text_fmt(clock->time_label, "%02d:%02d:%02d", hour, minutes, second);     lv_obj_align_to(clock->time_label, lv_obj_get_parent(clock->time_label), LV_ALIGN_CENTER, 0, 0); }  if (clock->date_label != NULL) {     lv_label_set_text_fmt(clock->date_label, "%d-%02d-%02d", year, month, day);     lv_obj_align_to(clock->date_label, lv_obj_get_parent(clock->date_label), LV_ALIGN_TOP_MID, 2, 0); }   if (clock->weekday_label != NULL)  {     lv_label_set_text_fmt(clock->weekday_label, "%s", week_day[weekday]);     lv_obj_align_to(clock->weekday_label, lv_obj_get_parent(clock->weekday_label), LV_ALIGN_BOTTOM_MID, -2, 0);  }    }}

就基本完成了时间的显示。

星期???

这里就有一个神奇的知识了,如何知道某年某月某日,是星期几?
有人说很简单,百度一下就行了。
在这里插入图片描述
现在世界各国通用一星期七天的制度。这个制度最早由君士坦丁大帝(Constantine the Great)制定。他在公元321年3月7日正式宣布7天为1周,这个制度一直沿用至今。一周7天的英文名称是Sunday(星期天)、Monday(星期一)、Tuesday(星期二)、Wednesday(星期三)、Thursday(星期四)、Friday(星期五)、Saturday(星期六)。
在这里插入图片描述

可是算了一下,那天是周一……。
试想一下:
大帝:今天开始实行星期制,一周七天,那么今天是第一天实行,就是星期一吧。
大臣:……星期一不是第二天吗?为啥今天不是星期天。
大帝:就你话多,来人呐~
大臣:
在这里插入图片描述
我们现在用的计算星期的算法,是根据一个公式《使用基姆拉尔森计算公式》得出来的,这里有推导过程《C语言根据日期(年,月,日)判断星期几(使用基姆拉尔森计算公式)》
这个公式也是有前提的,就是0年1月1日是星期1。感觉这个定义就比较能接受,比君士坦大帝那个常规 一点。
在这里插入图片描述
那么具体算法的话,

static int CaculateWeekDay(int y, int m, int d) //年月日换算成星期几{int week = 0;if (m==1 || m==2) {m=(m==1?13:14);y=y-1;//此处表示把1,2月计算到上一年的13,14月}week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;return week+1;}

至于为什么1月和2月单独处理,还是去看推导过程吧。一句两句也说不清楚。
在这里插入图片描述

加个背景图

黑乎乎的背景虽然省电,但是也不够美观呢,所以来试着加个图片。
首先是图片要转化为代码中的c数组,用的这个工具。
下载地址
在这里插入图片描述
图片要事先转化好大小。
然后包含到图像当中。为了不被遮挡,再设置一下时间和日期控件的透明度,就可以达到下面的效果了
在这里插入图片描述
可以猜一下是谁啊
在这里插入图片描述

结束语

好久没有烧烤了,孩子们玩的还挺开心,毕竟城里长大的孩子,哪有这种玩火的经历
在这里插入图片描述