知识点
《单片机—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);
lv_style_set_pad_right(&date_time_clock_style, 1);
lv_style_set_pad_top(&date_time_clock_style, 0);
lv_style_set_pad_bottom(&date_time_clock_style, 0);
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);
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);
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);
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);
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);
lv_obj_t *time_obj = lv_obj_create(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);
lv_obj_add_style(time_obj, &time_style, LV_STATE_DEFAULT);
static lv_clock_t lv_clock = { 0 };
lv_clock.time_label = lv_label_create(time_obj);
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_obj_t *date_obj = lv_obj_create(time_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);
lv_obj_add_style(date_obj, &date_style, LV_STATE_DEFAULT);
lv_clock.date_label = lv_label_create(date_obj);
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.weekday_label = lv_label_create(date_obj);
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_obj_align_to(lv_clock.time_label, lv_obj_get_parent(lv_clock.time_label), LV_ALIGN_CENTER, 0, 0);
lv_obj_align_to(lv_clock.date_label, lv_obj_get_parent(lv_clock.date_label), LV_ALIGN_TOP_MID, 2, 0);
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);
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;
}
week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7;
return week+1;
}
至于为什么1月和2月单独处理,还是去看推导过程吧。一句两句也说不清楚。
加个背景图
黑乎乎的背景虽然省电,但是也不够美观呢,所以来试着加个图片。 首先是图片要转化为代码中的c数组,用的这个工具。 下载地址 图片要事先转化好大小。 然后包含到图像当中。为了不被遮挡,再设置一下时间和日期控件的透明度,就可以达到下面的效果了 可以猜一下是谁啊
结束语
看到这么一条消息 这是希望大伙都牺牲在工作岗位上了。
|