目录
简介
本篇主要会教大家如何利用LVGL的各个控件来生成我们精美的GUI界面,并且教会大家如何的去进行界面的切换、和将任务获取到的传感器数值显示到我们的屏幕上面,最后告诉大家如何将我们的按键移植进去我们的LVGL当中。
生成GUI界面
我们在每次使用LVGL做项目之前,我们都会利用模拟器来进行模拟,模拟出我们需要显示出的界面,之后在移植进去我们的项目当中,我们使用的模拟器是 CodeBlocks 。
我这里已经给大家模拟好了,大家打开即可,如下所示:
我们这里有五个界面,分别是主菜单、菜单、血氧、心率、血压。所以我们分别注释对应页面的代码试一下:
这些都是我们手撮的,我们把源码放给大家看一下,如下所示:
#include "my_gui.h"
#include "lvgl.h"
#include <stdio.h>
/* 获取当前活动屏幕的宽高 */
#define scr_act_width() lv_obj_get_width(lv_scr_act())
#define scr_act_height() lv_obj_get_height(lv_scr_act())
/* 获取当前活动屏幕的宽高 */
#define scr_act_width() lv_obj_get_width(lv_scr_act())
#define scr_act_height() lv_obj_get_height(lv_scr_act())
/**
* @brief 主界面
* @param 无
* @return 无
*/
const char * ui_Days[7] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
char *blue_state = "ON";
lv_group_t * group_main;
lv_obj_t * ui_MainPage;
lv_obj_t *Temp_img;
lv_obj_t *Temp_label;
lv_style_t Temp_label_style;
lv_obj_t *Time_label;
lv_style_t Time_label_style;
lv_style_t Date_label_style;
lv_obj_t *Date_label;
lv_obj_t *Blue_img;
lv_obj_t *Blue_label;
lv_style_t Blue_label_style;
lv_obj_t *Humi_img;
lv_obj_t *Humi_label;
lv_style_t Humi_label_style;
lv_obj_t *Step_bar;
lv_anim_t Step_anim;
lv_obj_t *Step_bar_label;
lv_timer_t * ui_MainPageTimer;
// need to be destroyed when the page is destroyed
static void MainPage_timer_cb(lv_timer_t * timer)
{
char buf[128];
uint32_t tmp;
}
/ FUNCTIONS
void Ui_MainPage_Init(void)
{
char buf[64];
ui_MainPage = lv_obj_create(lv_scr_act());
lv_obj_set_size(ui_MainPage, 128, 160); // 设置页面占满整个屏幕
lv_obj_clear_flag(ui_MainPage, LV_OBJ_FLAG_SCROLLABLE); // 禁止页面滚动
//lv_scr_load(ui_MainPage);
/* 显示日期和时钟 */
Date_label = lv_label_create(ui_MainPage);
lv_style_init(&Date_label_style);
lv_style_set_text_font(&Date_label_style, &lv_font_montserrat_14);
lv_style_set_text_color(&Date_label_style, lv_color_hex(0xd81e06));
lv_obj_add_style(Date_label, &Date_label_style, LV_PART_MAIN);
lv_obj_align(Date_label, LV_ALIGN_TOP_MID, 0, 0);
sprintf(buf, "%02d-%02d %s",1,15,ui_Days[2]);
lv_label_set_text(Date_label, buf);
Time_label = lv_label_create(ui_MainPage);
lv_style_init(&Time_label_style);
lv_style_set_text_font(&Time_label_style, &lv_font_montserrat_20);
lv_style_set_text_color(&Time_label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(Time_label, &Time_label_style, LV_PART_MAIN);
lv_obj_align(Time_label, LV_ALIGN_TOP_MID, 0, 25);
sprintf(buf, "%02d:%02d:%02d", 12,23,48);
lv_label_set_text(Time_label, buf);
/* 显示步数条 */
static lv_style_t Step_bar_style;
lv_style_init(&Step_bar_style);
lv_style_set_bg_opa(&Step_bar_style, LV_OPA_COVER);
lv_style_set_bg_color(&Step_bar_style, lv_palette_main(LV_PALETTE_BLUE));
Step_bar = lv_bar_create(ui_MainPage);
lv_obj_add_style(Step_bar, &Step_bar_style, LV_PART_INDICATOR);
lv_obj_set_size(Step_bar, 110, 10);
lv_obj_align(Step_bar, LV_ALIGN_CENTER, 0, 10);
lv_bar_set_range(Step_bar, 0, 10000);
lv_bar_set_value(Step_bar,4864,LV_ANIM_OFF);
Step_bar_label = lv_label_create(ui_MainPage);
lv_label_set_text(Step_bar_label, "Step: 4864");
static lv_style_t Step_label_style;
lv_style_init(&Step_label_style);
lv_style_set_text_font(&Step_label_style, &lv_font_montserrat_14); // 设置字体
lv_obj_add_style(Step_bar_label, &Step_label_style, LV_PART_MAIN);
lv_obj_align_to(Step_bar_label, Step_bar, LV_ALIGN_OUT_TOP_LEFT, 0, 0);
/* 显示温度照片和数据 */
LV_IMG_DECLARE(img_temp_32);
Temp_img = lv_img_create(ui_MainPage);
lv_img_set_src(Temp_img, &img_temp_32);
lv_obj_align(Temp_img, LV_ALIGN_BOTTOM_MID, -45, -10);
lv_obj_set_size(Temp_img, 32, 32);
Temp_label = lv_label_create(ui_MainPage);
lv_style_init(&Temp_label_style);
lv_style_set_text_font(&Temp_label_style, &lv_font_montserrat_14);
lv_style_set_text_color(&Temp_label_style, lv_color_hex(0xff0000));
lv_obj_add_style(Temp_label, &Temp_label_style, LV_PART_MAIN);
lv_obj_align_to(Temp_label,Temp_img, LV_ALIGN_OUT_BOTTOM_MID,5,0);
sprintf(buf,"%d",23);
lv_label_set_text(Temp_label, buf);
/* 显示湿度照片和数据 */
LV_IMG_DECLARE(img_humi_32);
Humi_img = lv_img_create(ui_MainPage);
lv_img_set_src(Humi_img, &img_humi_32);
lv_obj_align(Humi_img, LV_ALIGN_BOTTOM_MID, 0, -10);
lv_obj_set_size(Humi_img, 32, 32);
Humi_label = lv_label_create(ui_MainPage);
lv_style_init(&Humi_label_style);
lv_style_set_text_font(&Humi_label_style, &lv_font_montserrat_14);
lv_style_set_text_color(&Humi_label_style, lv_color_hex(0xff0000));
lv_obj_add_style(Humi_label, &Humi_label_style, LV_PART_MAIN);
lv_obj_align_to(Humi_label,Humi_img, LV_ALIGN_OUT_BOTTOM_MID, 5, 0);
sprintf(buf, "%d",69);
lv_label_set_text(Humi_label, buf);
/* 显示蓝牙照片和状态 */
LV_IMG_DECLARE(img_blue_32);
Blue_img = lv_img_create(ui_MainPage);
lv_img_set_src(Blue_img, &img_blue_32);
lv_obj_align(Blue_img, LV_ALIGN_BOTTOM_MID, 45,-10);
lv_obj_set_size(Blue_img, 32, 32);
Blue_label = lv_label_create(ui_MainPage);
lv_style_init(&Blue_label_style);
lv_style_set_text_font(&Blue_label_style, &lv_font_montserrat_14);
lv_style_set_text_color(&Blue_label_style, lv_color_hex(0xff0000));
lv_obj_add_style(Blue_label, &Blue_label_style, LV_PART_MAIN);
lv_obj_align_to(Blue_label,Blue_img, LV_ALIGN_OUT_BOTTOM_MID, 5, 0);
sprintf(buf, "%s", blue_state);
lv_label_set_text(Blue_label, buf);
//lv_obj_add_event_cb(ui_MainPage, Key_SwitchPage_event_handler, LV_EVENT_ALL, NULL);
/* 创建主页定时器刷新传感器数据 */
ui_MainPageTimer = lv_timer_create(MainPage_timer_cb, 100, NULL);
}
/**
* @brief 菜单界面
* @param 无
* @return 无
*/
LV_FONT_DECLARE(lv_font_Chinese_SiYuan_Light_18);
lv_group_t * group_menu;
lv_obj_t * ui_MenuPage;
/* 心率相关全局变量 */
lv_obj_t * ui_Menu_Heart_btn;
lv_obj_t * ui_Menu_Heart_img;
lv_obj_t * ui_Menu_Heart_Label;
/* 血氧相关全局变量 */
lv_obj_t * ui_Menu_Blood_Oxy_btn;
lv_obj_t * ui_Menu_Blood_Oxy_img;
lv_obj_t * ui_Menu_Blood_Oxy_Label;
/* 血压相关全局变量 */
lv_obj_t * ui_Menu_BloodPressure_btn;
lv_obj_t * ui_Menu_BloodPressure_img;
lv_obj_t * ui_Menu_BloodPressure_Label;
/* 蓝牙相关全局变量 */
lv_obj_t * ui_Menu_BlueTooth_blue_sw;
lv_obj_t * ui_Menu_BlueTooth_btn;
lv_obj_t * ui_Menu_BlueTooth_img;
lv_obj_t * ui_Menu_BlueTooth_Label;
/* 关于相关全局变量 */
lv_obj_t * ui_Menu_About_btn;
lv_obj_t * ui_Menu_About_img;
lv_obj_t * ui_Menu_About_Label;
void ui_event_MenuHeart_Handler(lv_event_t * e)
{
// 获取触发事件的对象
lv_obj_t *obj = lv_event_get_target(e);
if (obj == ui_Menu_Heart_btn)
{
}
}
void ui_event_MenuBlood_Oxy_Handler(lv_event_t * e)
{
// 获取触发事件的对象
lv_obj_t *obj = lv_event_get_target(e);
if (obj == ui_Menu_Blood_Oxy_btn)
{
}
}
void ui_event_BloodPressure_Handler(lv_event_t * e)
{
// 获取触发事件的对象
lv_obj_t *obj = lv_event_get_target(e);
if (obj == ui_Menu_BloodPressure_btn)
{
}
}
void ui_event_BlueTooth_Handler(lv_event_t * e)
{
// 获取触发事件的对象
lv_obj_t *obj = lv_event_get_target(e);
}
void ui_event_About_Handler(lv_event_t * e)
{
// 获取触发事件的对象
lv_obj_t *obj = lv_event_get_target(e);
}
void Key_Enter_event_handler(lv_event_t * e)
{
}
void Ui_MenuPage_Init(void)
{
char buf[64];
ui_MenuPage = lv_obj_create(lv_scr_act());
lv_obj_set_size(ui_MenuPage, 128, 160); // 设置页面占满整个屏幕
lv_obj_set_style_bg_color(ui_MenuPage, lv_color_hex(0xF5F5F5), LV_PART_MAIN | LV_STATE_DEFAULT); // 浅灰色背景
lv_obj_set_style_bg_opa(ui_MenuPage, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_scroll_dir(ui_MenuPage, LV_DIR_VER); // 仅允许垂直滚动
/* 显示心率图标按钮 */
ui_Menu_Heart_btn = lv_btn_create(ui_MenuPage);
lv_obj_set_width(ui_Menu_Heart_btn, 32);
lv_obj_set_height(ui_Menu_Heart_btn, 32);
lv_obj_align(ui_Menu_Heart_btn, LV_ALIGN_TOP_LEFT, -8, 10);
lv_obj_add_flag(ui_Menu_Heart_btn, LV_OBJ_FLAG_CLICKABLE); // Flags
lv_obj_set_style_radius(ui_Menu_Heart_btn, 32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui_Menu_Heart_btn, lv_color_hex(0xFF8080), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui_Menu_Heart_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_event_cb(ui_Menu_Heart_btn, ui_event_MenuHeart_Handler, LV_EVENT_CLICKED, NULL);
LV_IMG_DECLARE(img_heart_Blood_32);
ui_Menu_Heart_img = lv_img_create(ui_Menu_Heart_btn);
lv_img_set_src(ui_Menu_Heart_img, &img_heart_Blood_32);
lv_obj_set_width(ui_Menu_Heart_img, LV_SIZE_CONTENT); /// 1
lv_obj_set_height(ui_Menu_Heart_img, LV_SIZE_CONTENT); /// 1
lv_obj_set_align(ui_Menu_Heart_img, LV_ALIGN_CENTER);
static lv_style_t ui_Menu_Heart_Label_style;
ui_Menu_Heart_Label = lv_label_create(ui_MenuPage);
lv_style_init(&ui_Menu_Heart_Label_style);
lv_style_set_text_font(&ui_Menu_Heart_Label_style, &lv_font_Chinese_SiYuan_Light_18);
lv_style_set_text_color(&ui_Menu_Heart_Label_style, lv_color_hex(0x000000ff));
lv_obj_add_style(ui_Menu_Heart_Label, &ui_Menu_Heart_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Menu_Heart_Label, LV_ALIGN_TOP_LEFT, 35, 15);
lv_label_set_text(ui_Menu_Heart_Label, "心率");
/* 显示血氧图标按钮 */
ui_Menu_Blood_Oxy_btn = lv_btn_create(ui_MenuPage);
lv_obj_set_width(ui_Menu_Blood_Oxy_btn, 32);
lv_obj_set_height(ui_Menu_Blood_Oxy_btn, 32);
lv_obj_align(ui_Menu_Blood_Oxy_btn, LV_ALIGN_TOP_LEFT, -8, 60);
lv_obj_add_flag(ui_Menu_Blood_Oxy_btn, LV_OBJ_FLAG_CLICKABLE); /// Flags
lv_obj_set_style_radius(ui_Menu_Blood_Oxy_btn, 32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui_Menu_Blood_Oxy_btn, lv_color_hex(0xFF8080), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui_Menu_Blood_Oxy_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_event_cb(ui_Menu_Blood_Oxy_btn, ui_event_MenuBlood_Oxy_Handler, LV_EVENT_CLICKED, NULL);
LV_IMG_DECLARE(img_blood_oxy_32);
ui_Menu_Blood_Oxy_img = lv_img_create(ui_Menu_Blood_Oxy_btn);
lv_img_set_src(ui_Menu_Blood_Oxy_img, &img_blood_oxy_32);
lv_obj_set_width(ui_Menu_Blood_Oxy_img, LV_SIZE_CONTENT);
lv_obj_set_height(ui_Menu_Blood_Oxy_img, LV_SIZE_CONTENT);
lv_obj_set_align(ui_Menu_Blood_Oxy_img, LV_ALIGN_CENTER);
static lv_style_t ui_Menu_Blood_Oxy_Label_style;
ui_Menu_Blood_Oxy_Label = lv_label_create(ui_MenuPage);
lv_style_init(&ui_Menu_Blood_Oxy_Label_style);
lv_style_set_text_font(&ui_Menu_Blood_Oxy_Label_style, &lv_font_Chinese_SiYuan_Light_18);
lv_style_set_text_color(&ui_Menu_Blood_Oxy_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Menu_Blood_Oxy_Label, &ui_Menu_Blood_Oxy_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Menu_Blood_Oxy_Label, LV_ALIGN_TOP_LEFT, 35, 65);
lv_label_set_text(ui_Menu_Blood_Oxy_Label, "血氧");
/* 显示血压图标按钮 */
ui_Menu_BloodPressure_btn = lv_btn_create(ui_MenuPage);
lv_obj_set_width(ui_Menu_BloodPressure_btn, 32);
lv_obj_set_height(ui_Menu_BloodPressure_btn, 32);
lv_obj_align(ui_Menu_BloodPressure_btn, LV_ALIGN_TOP_LEFT, -8, 110);
lv_obj_add_flag(ui_Menu_BloodPressure_btn, LV_OBJ_FLAG_CLICKABLE); // Flags
lv_obj_set_style_radius(ui_Menu_BloodPressure_btn, 32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui_Menu_BloodPressure_btn, lv_color_hex(0xFF8080), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui_Menu_BloodPressure_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_event_cb(ui_Menu_BloodPressure_btn, ui_event_BloodPressure_Handler, LV_EVENT_CLICKED, NULL);
LV_IMG_DECLARE(img_bloodpressure_32);
ui_Menu_BloodPressure_img = lv_img_create(ui_Menu_BloodPressure_btn);
lv_img_set_src(ui_Menu_BloodPressure_img, &img_bloodpressure_32);
lv_obj_set_width(ui_Menu_BloodPressure_img, LV_SIZE_CONTENT);
lv_obj_set_height(ui_Menu_BloodPressure_img, LV_SIZE_CONTENT);
lv_obj_set_align(ui_Menu_BloodPressure_img, LV_ALIGN_CENTER);
static lv_style_t ui_Menu_BloodPressure_Label_style;
ui_Menu_BloodPressure_Label = lv_label_create(ui_MenuPage);
lv_style_init(&ui_Menu_BloodPressure_Label_style);
lv_style_set_text_font(&ui_Menu_BloodPressure_Label_style, &lv_font_Chinese_SiYuan_Light_18);
lv_style_set_text_color(&ui_Menu_BloodPressure_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Menu_BloodPressure_Label, &ui_Menu_BloodPressure_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Menu_BloodPressure_Label, LV_ALIGN_TOP_LEFT, 35, 115);
lv_label_set_text(ui_Menu_BloodPressure_Label, "血压");
/* 显示蓝牙图标按钮 */
ui_Menu_BlueTooth_btn = lv_btn_create(ui_MenuPage);
lv_obj_set_width(ui_Menu_BlueTooth_btn, 32);
lv_obj_set_height(ui_Menu_BlueTooth_btn, 32);
lv_obj_align(ui_Menu_BlueTooth_btn, LV_ALIGN_TOP_LEFT, -8, 160);
lv_obj_add_flag(ui_Menu_BlueTooth_btn, LV_OBJ_FLAG_CLICKABLE); // Flags
lv_obj_set_style_radius(ui_Menu_BlueTooth_btn, 32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui_Menu_BlueTooth_btn, lv_color_hex(0xFF8080), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui_Menu_BlueTooth_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
LV_IMG_DECLARE(img_bluetooth_32);
ui_Menu_BlueTooth_img = lv_img_create(ui_Menu_BlueTooth_btn);
lv_img_set_src(ui_Menu_BlueTooth_img, &img_bluetooth_32);
lv_obj_set_width(ui_Menu_BlueTooth_img, LV_SIZE_CONTENT);
lv_obj_set_height(ui_Menu_BlueTooth_img, LV_SIZE_CONTENT);
lv_obj_set_align(ui_Menu_BlueTooth_img, LV_ALIGN_CENTER);
static lv_style_t ui_Menu_BlueTooth_Label_style;
ui_Menu_BlueTooth_Label = lv_label_create(ui_MenuPage);
lv_style_init(&ui_Menu_BlueTooth_Label_style);
lv_style_set_text_font(&ui_Menu_BlueTooth_Label_style, &lv_font_Chinese_SiYuan_Light_18);
lv_style_set_text_color(&ui_Menu_BlueTooth_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Menu_BlueTooth_Label, &ui_Menu_BlueTooth_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Menu_BlueTooth_Label, LV_ALIGN_TOP_LEFT, 35, 165);
lv_label_set_text(ui_Menu_BlueTooth_Label, "蓝牙");
ui_Menu_BlueTooth_blue_sw = lv_switch_create(ui_MenuPage);
lv_obj_set_size(ui_Menu_BlueTooth_blue_sw, 25, 20);
lv_obj_align_to(ui_Menu_BlueTooth_blue_sw, ui_Menu_BlueTooth_Label, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
lv_obj_add_event_cb(ui_Menu_BlueTooth_btn, ui_event_BlueTooth_Handler, LV_EVENT_CLICKED, ui_Menu_BlueTooth_blue_sw);
/* 显示关于图标按钮 */
ui_Menu_About_btn = lv_btn_create(ui_MenuPage);
lv_obj_set_width(ui_Menu_About_btn, 32);
lv_obj_set_height(ui_Menu_About_btn, 32);
lv_obj_align(ui_Menu_About_btn, LV_ALIGN_TOP_LEFT, -8, 210);
lv_obj_add_flag(ui_Menu_About_btn, LV_OBJ_FLAG_CLICKABLE); // Flags
lv_obj_set_style_radius(ui_Menu_About_btn, 32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui_Menu_About_btn, lv_color_hex(0xFF8080), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui_Menu_About_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_event_cb(ui_Menu_About_btn, ui_event_About_Handler, LV_EVENT_CLICKED, NULL);
LV_IMG_DECLARE(img_about_32);
ui_Menu_About_img = lv_img_create(ui_Menu_About_btn);
lv_img_set_src(ui_Menu_About_img, &img_about_32);
lv_obj_set_width(ui_Menu_About_img, LV_SIZE_CONTENT);
lv_obj_set_height(ui_Menu_About_img, LV_SIZE_CONTENT);
lv_obj_set_align(ui_Menu_About_img, LV_ALIGN_CENTER);
static lv_style_t ui_Menu_About_Label_style;
ui_Menu_About_Label = lv_label_create(ui_MenuPage);
lv_style_init(&ui_Menu_About_Label_style);
lv_style_set_text_font(&ui_Menu_About_Label_style, &lv_font_Chinese_SiYuan_Light_18);
lv_style_set_text_color(&ui_Menu_About_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Menu_About_Label, &ui_Menu_About_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Menu_About_Label, LV_ALIGN_TOP_LEFT, 35, 215);
lv_label_set_text(ui_Menu_About_Label, "关于");
// 创建一个 group_menu 并添加按钮
group_menu = lv_group_create();
lv_group_add_obj(group_menu, ui_Menu_Heart_btn);
lv_group_add_obj(group_menu, ui_Menu_Blood_Oxy_btn);
lv_group_add_obj(group_menu, ui_Menu_BloodPressure_btn);
lv_group_add_obj(group_menu, ui_Menu_BlueTooth_btn);
lv_group_add_obj(group_menu, ui_Menu_About_btn);
}
/**
* @brief 心率界面
* @param 无
* @return 无
*/
lv_obj_t * ui_HeartPage;
lv_timer_t * ui_HeartPageTimer;
lv_obj_t * ui_Heart_img;
lv_obj_t * ui_Heart_Label;
lv_style_t ui_Heart_Label_style;
lv_obj_t * ui_Heart_Label2;
lv_style_t ui_Heart_Label2_style;
lv_obj_t * ui_Heart_State_Label;
lv_style_t ui_Heart_State_Label_style;
static void HeartPage_timer_cb(lv_timer_t * timer)
{
char buf[64];
}
void Ui_HeartPage_Init(void)
{
char buf[64];
ui_HeartPage = lv_obj_create(lv_scr_act());
lv_obj_set_size(ui_HeartPage, 128, 160); // 设置页面占满整个屏幕
lv_obj_clear_flag(ui_HeartPage, LV_OBJ_FLAG_SCROLLABLE); // 禁止页面滚动
LV_IMG_DECLARE(img_love_32);
ui_Heart_img = lv_img_create(ui_HeartPage);
lv_img_set_src(ui_Heart_img, &img_love_32);
lv_obj_align(ui_Heart_img, LV_ALIGN_CENTER, 0, -40);
lv_obj_set_size(ui_Heart_img, 32, 32);
ui_Heart_Label = lv_label_create(ui_HeartPage);
lv_style_init(&ui_Heart_Label_style);
lv_style_set_text_font(&ui_Heart_Label_style, &lv_font_montserrat_32);
lv_style_set_text_color(&ui_Heart_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Heart_Label, &ui_Heart_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Heart_Label, LV_ALIGN_CENTER, -10, 5);
sprintf(buf, "%d ", 100);
lv_label_set_text(ui_Heart_Label, buf);
ui_Heart_Label2 = lv_label_create(ui_HeartPage);
lv_style_init(&ui_Heart_Label2_style);
lv_style_set_text_font(&ui_Heart_Label2_style, &lv_font_montserrat_14);
lv_style_set_text_color(&ui_Heart_Label2_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Heart_Label2, &ui_Heart_Label2_style, LV_PART_MAIN);
lv_obj_align_to(ui_Heart_Label2, ui_Heart_Label, LV_ALIGN_OUT_RIGHT_MID, 5, 5);
sprintf(buf, "t/m");
lv_label_set_text(ui_Heart_Label2, buf);
ui_Heart_State_Label = lv_label_create(ui_HeartPage);
lv_style_init(&ui_Heart_State_Label_style);
lv_style_set_text_font(&ui_Heart_State_Label_style, &lv_font_montserrat_14);
lv_style_set_text_color(&ui_Heart_State_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Heart_State_Label, &ui_Heart_State_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Heart_State_Label, LV_ALIGN_CENTER, 0, 35);
lv_label_set_text(ui_Heart_State_Label, "Wait");
ui_HeartPageTimer = lv_timer_create(HeartPage_timer_cb, 100, NULL);
}
/**
* @brief 血氧界面
* @param 无
* @return 无
*/
lv_obj_t * ui_Blood_Oxy_Page;
lv_timer_t * ui_Blood_Oxy_PageTimer;
lv_obj_t * ui_Blood_Oxy_img;
lv_obj_t * ui_Blood_Oxy_Label;
lv_style_t ui_Blood_Oxy_Label_style;
lv_obj_t * ui_Blood_Oxy_Label2;
lv_style_t ui_Blood_Oxy_Label2_style;
lv_obj_t * ui_Blood_Oxy_State_Label;
lv_style_t ui_Blood_Oxy_State_Label_style;
static void Blood_Oxy_Page_timer_cb(lv_timer_t * timer)
{
char buf[64];
}
void Ui_Blood_Oxy_Page_Init(void)
{
char buf[64];
ui_Blood_Oxy_Page = lv_obj_create(lv_scr_act());
lv_obj_set_size(ui_Blood_Oxy_Page, 128, 160); // 设置页面占满整个屏幕
lv_obj_clear_flag(ui_Blood_Oxy_Page, LV_OBJ_FLAG_SCROLLABLE); // 禁止页面滚动
LV_IMG_DECLARE(img_SaO2_32);
ui_Blood_Oxy_img = lv_img_create(ui_Blood_Oxy_Page);
lv_img_set_src(ui_Blood_Oxy_img, &img_SaO2_32);
lv_obj_align(ui_Blood_Oxy_img, LV_ALIGN_CENTER, 0, -40);
lv_obj_set_size(ui_Blood_Oxy_img, 32, 32);
ui_Blood_Oxy_Label = lv_label_create(ui_Blood_Oxy_Page);
lv_style_init(&ui_Blood_Oxy_Label_style);
lv_style_set_text_font(&ui_Blood_Oxy_Label_style, &lv_font_montserrat_32);
lv_style_set_text_color(&ui_Blood_Oxy_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Blood_Oxy_Label, &ui_Blood_Oxy_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Blood_Oxy_Label, LV_ALIGN_CENTER, -10, 5);
sprintf(buf, "%d ", 100);
lv_label_set_text(ui_Blood_Oxy_Label, buf);
ui_Blood_Oxy_Label2 = lv_label_create(ui_Blood_Oxy_Page);
lv_style_init(&ui_Blood_Oxy_Label2_style);
lv_style_set_text_font(&ui_Blood_Oxy_Label2_style, &lv_font_montserrat_14);
lv_style_set_text_color(&ui_Blood_Oxy_Label2_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Blood_Oxy_Label2, &ui_Blood_Oxy_Label2_style, LV_PART_MAIN);
lv_obj_align_to(ui_Blood_Oxy_Label2, ui_Blood_Oxy_Label, LV_ALIGN_OUT_RIGHT_MID, 5, 5);
sprintf(buf, "%%");
lv_label_set_text(ui_Blood_Oxy_Label2, buf);
ui_Blood_Oxy_State_Label = lv_label_create(ui_Blood_Oxy_Page);
lv_style_init(&ui_Blood_Oxy_State_Label_style);
lv_style_set_text_font(&ui_Blood_Oxy_State_Label_style, &lv_font_montserrat_14);
lv_style_set_text_color(&ui_Blood_Oxy_State_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Blood_Oxy_State_Label, &ui_Blood_Oxy_State_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Blood_Oxy_State_Label, LV_ALIGN_CENTER, 0, 35);
lv_label_set_text(ui_Blood_Oxy_State_Label, "Wait");
ui_Blood_Oxy_PageTimer = lv_timer_create(Blood_Oxy_Page_timer_cb, 100, NULL);
}
/**
* @brief 血压界面
* @param 无
* @return 无
*/
lv_obj_t * ui_Blood_Pressure_Page;
lv_timer_t * ui_Blood_Pressure_PageTimer;
lv_obj_t * ui_Blood_Pressure_img;
lv_obj_t * ui_Blood_Pressure_Label;
lv_style_t ui_Blood_Pressure_Label_style;
lv_obj_t * ui_Blood_Pressure_Label2;
lv_style_t ui_Blood_Pressure_Label2_style;
static void Blood_Pressure_Page_timer_cb(lv_timer_t * timer)
{
char buf[64];
}
void Ui_Blood_Pressure_Page_Init(void)
{
char buf[64];
ui_Blood_Pressure_Page = lv_obj_create(lv_scr_act());
lv_obj_set_size(ui_Blood_Pressure_Page, 128, 160); // 设置页面占满整个屏幕
lv_obj_clear_flag(ui_Blood_Pressure_Page, LV_OBJ_FLAG_SCROLLABLE); // 禁止页面滚动
LV_IMG_DECLARE(img_blood_pressure2_32);
ui_Blood_Pressure_img = lv_img_create(ui_Blood_Pressure_Page);
lv_img_set_src(ui_Blood_Pressure_img, &img_blood_pressure2_32);
lv_obj_align(ui_Blood_Pressure_img, LV_ALIGN_CENTER, 0, -40);
lv_obj_set_size(ui_Blood_Pressure_img, 32, 32);
ui_Blood_Pressure_Label = lv_label_create(ui_Blood_Pressure_Page);
lv_style_init(&ui_Blood_Pressure_Label_style);
lv_style_set_text_font(&ui_Blood_Pressure_Label_style, &lv_font_montserrat_32);
lv_style_set_text_color(&ui_Blood_Pressure_Label_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Blood_Pressure_Label, &ui_Blood_Pressure_Label_style, LV_PART_MAIN);
lv_obj_align(ui_Blood_Pressure_Label, LV_ALIGN_CENTER, 5, 5);
sprintf(buf, "%s ", "966593");
lv_label_set_text(ui_Blood_Pressure_Label, buf);
ui_Blood_Pressure_Label2 = lv_label_create(ui_Blood_Pressure_Page);
lv_style_init(&ui_Blood_Pressure_Label2_style);
lv_style_set_text_font(&ui_Blood_Pressure_Label2_style, &lv_font_montserrat_14);
lv_style_set_text_color(&ui_Blood_Pressure_Label2_style, lv_color_hex(0x0000ff));
lv_obj_add_style(ui_Blood_Pressure_Label2, &ui_Blood_Pressure_Label2_style, LV_PART_MAIN);
lv_obj_align_to(ui_Blood_Pressure_Label2, ui_Blood_Pressure_Label, LV_ALIGN_OUT_BOTTOM_MID, -5, 5);
sprintf(buf, "BMP");
lv_label_set_text(ui_Blood_Pressure_Label2, buf);
ui_Blood_Pressure_PageTimer = lv_timer_create(Blood_Pressure_Page_timer_cb, 100, NULL);
}
/**
* @brief LVGL演示
* @param 注释掉对应GUI,即可看到对应的GUI界面
* @return 无
*/
void my_gui(void)
{
//Ui_MainPage_Init();
//Ui_MenuPage_Init();
//Ui_HeartPage_Init();
//Ui_Blood_Oxy_Page_Init();
Ui_Blood_Pressure_Page_Init();
}
这里我们用到了非常多的部件,包括按钮部件、标签部件、图片部件、进度条部件。并且使用了中文字库,正好这几个部件我都有专门的博客讲解过,并且针对LVGL基础知识也有讲解过,如下所示:
注意的是,由于我们模拟器无法模拟传感器获取,所以我们直接把数值写死进行模拟。
界面切换
我们这么多个界面是如何进行切换的呢?这个就是这个项目的灵魂之处了。我们采用的是压栈以及入栈的思想,我们先看一下源码:
#include "PageManager.h"
extern Page_t Page_Main;
extern Page_t Page_Menu;
PageStack_t PageStack;
static void page_stack_init(PageStack_t* stack) {
stack->top = 0;
}
static uint8_t page_stack_push(PageStack_t* stack, Page_t* page) {
if (stack->top >= MAX_DEPTH)
return -1;
stack->pages[stack->top++] = page;
return 0;
}
static uint8_t page_stack_pop(PageStack_t* stack) {
if (stack->top <= 0)
return -1;
stack->pages[--stack->top]->deinit();
return 0;
}
static uint8_t page_stack_is_empty(const PageStack_t* stack) {
return stack->top == 0;
}
static Page_t* get_top_page(PageStack_t* stack) {
// 检查栈是否为空
if (stack->top == 0) {
return NULL; // 如果栈为空,返回NULL
}
// 返回栈顶页面的指针
return stack->pages[stack->top - 1];
}
/**
* 获取当前页面(栈顶页面)的指针。
*
* @param NULL
* @return 返回当前页面的指针,如果栈为空则返回NULL。
*/
Page_t* Page_Get_NowPage(void) {
return get_top_page(&PageStack);
}
/**
* back to previous page
*
* @param NULL
* @return NULL
*/
void Page_Back(void) {
if (page_stack_is_empty(&PageStack)) {
// 栈为空时,不应发生
return;
}
// 弹出当前页面
page_stack_pop(&PageStack);
if (page_stack_is_empty(&PageStack)) {
// 如果栈为空,入栈并切换到MenuPage
page_stack_push(&PageStack, &Page_Main);
page_stack_push(&PageStack, &Page_Menu);
Page_Menu.init();
lv_scr_load_anim(*Page_Menu.page_obj, LV_SCR_LOAD_ANIM_NONE, 100, 0, true);
} else {
// 切换到上一个页面
Page_t *previous_page = PageStack.pages[PageStack.top - 1];
previous_page->init();
lv_scr_load(*previous_page->page_obj);
//lv_scr_load_anim(*previous_page->page_obj, LV_SCR_LOAD_ANIM_NONE, 100, 0, true);
}
}
/**
* back to bottom page home page
*
* @param NULL
* @return NULL
*/
void Page_Back_Bottom(void) {
if (page_stack_is_empty(&PageStack)) {
// 栈为空时,不应发生
return;
}
// 弹出除栈底的所有页面
while(PageStack.top > 1)
page_stack_pop(&PageStack);
PageStack.pages[PageStack.top - 1]->init(); // 初始化新页面
lv_scr_load_anim(*PageStack.pages[PageStack.top - 1]->page_obj, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 100, 0, true); // 加载并应用动画
}
/**
* Load a new page to stack top
*
* @param newPage Page_t a new page
* @return NULL
*/
void Page_Load(Page_t *newPage) {
// 检查堆栈是否已满
if (PageStack.top >= MAX_DEPTH - 1) {
// 错误处理:堆栈满
return;
}
// 如果堆栈非空,反初始化当前页面
if (PageStack.top > 0) {
PageStack.pages[PageStack.top - 1]->deinit();
}
// 将新页面推入堆栈
page_stack_push(&PageStack, newPage);
newPage->init(); // 初始化新页面
lv_scr_load(*newPage->page_obj);
//lv_scr_load_anim(*newPage->page_obj, LV_SCR_LOAD_ANIM_NONE, 100, 0, true); // 加载并应用动画
}
/**
* initialize the page manager & start home page
*
* @param NULL
* @return NULL
*/
void Pages_init(void) {
page_stack_init(&PageStack);
page_stack_push(&PageStack, &Page_Main);
Page_Main.init();
lv_scr_load(*Page_Main.page_obj);
//lv_disp_load_scr(*Page_Main.page_obj);
// page_stack_init(&PageStack);
// page_stack_push(&PageStack, &Page_Menu);
// Page_Menu.init();
// lv_disp_load_scr(*Page_Menu.page_obj);
}
#ifndef _PAGE_STACK_H
#define _PAGE_STACK_H
//#include "main.h"
#include "stm32f4xx.h"
#include <stdio.h>
#include "lvgl.h"
// 页面栈深度
#define MAX_DEPTH 6
// 页面结构体
typedef struct {
void (*init)(void);
void (*deinit)(void);
lv_obj_t **page_obj;
} Page_t;
// 页面堆栈结构体
typedef struct {
Page_t* pages[MAX_DEPTH];
uint8_t top;
} PageStack_t;
extern PageStack_t PageStack;
Page_t* Page_Get_NowPage(void);
void Page_Back(void);
void Page_Back_Bottom(void);
void Page_Load(Page_t *newPage);
void Pages_init(void);
#endif //PAGE_STACK_H
这个页面切换的代码实现了一个简单的页面管理器,允许在不同的页面之间进行切换和导航。该代码使用了页面栈的方式来管理页面的切换。页面栈是一种先进后出(LIFO)的数据结构,允许实现“返回”功能,让用户能够从一个页面返回到之前的页面。
主要结构与功能:
Page_t 类型: 每个页面由一个 Page_t 结构表示,其中包含:
init():初始化页面的函数。
deinit():反初始化页面的函数。
page_obj:页面对象指针,通常是 LVGL 页面对象,用于显示页面。
PageStack_t 类型: 这是一个栈结构,专门用于存储页面指针。栈的操作包括 push(入栈)、pop(出栈)等基本操作。
页面栈管理:
初始化栈:在 Pages_init() 函数中,初始化页面栈 PageStack,并将主页(Page_Main)推入栈中,加载并显示该页面。
切换页面:通过栈来切换页面,每次加载新页面时,都将该页面推入栈中,栈顶保持当前显示的页面。
返回上一个页面:通过 Page_Back() 函数,弹出栈顶页面,切换到上一个页面。如果栈为空,则加载菜单页面(Page_Menu)。
返回底部页面(主页):Page_Back_Bottom() 函数弹出栈中除了主页的所有页面,返回主页并加载该页面。
代码细节:
page_stack_init(PageStack_t* stack):
初始化页面栈,设置栈顶为0,表示栈是空的。
page_stack_push(PageStack_t* stack, Page_t* page):
将新页面推入栈中。每次栈顶加1,表示栈的深度增加。
如果栈已经满了(即超过了最大深度 MAX_DEPTH),则无法再推入新页面。
page_stack_pop(PageStack_t* stack):
弹出栈顶页面,栈顶减1。如果栈不为空,它将执行页面的反初始化 (deinit) 操作。
在页面切换时,通常需要先弹出当前页面,然后再加载新的页面。
page_stack_is_empty(PageStack_t* stack):
判断页面栈是否为空,如果为空则返回 true,否则返回 false。
get_top_page(PageStack_t* stack):
获取栈顶的页面对象。通过检查栈的深度来确定栈是否为空。如果栈为空,返回 NULL。
Page_Get_NowPage():
返回当前页面,即栈顶页面。
Page_Back():
返回上一个页面:弹出栈顶页面并加载上一个页面。若栈为空,加载主页面和菜单页面。
在加载新的页面时,调用 init() 函数初始化该页面,并显示该页面。
Page_Back_Bottom():
返回到底部页面(主页):弹出栈中除了栈底的所有页面,并加载主页(Page_Main)。
Page_Load(Page_t *newPage):
加载新页面:反初始化当前页面,然后将新页面推入栈中并显示该页面。
Pages_init():
初始化页面管理器,加载并显示主页(Page_Main)。
页面切换流程:
初始化:当系统启动时,通过 Pages_init() 加载并显示主页页面。
页面切换:通过 Page_Load() 函数加载新页面,将页面推入栈中并显示该页面。此时当前页面是栈顶页面。
返回上一个页面:通过 Page_Back() 函数弹出栈顶页面,返回栈中之前的页面。
返回主页:通过 Page_Back_Bottom() 函数弹出栈中所有页面,返回到主页。
总结:
该代码提供了一个简单而有效的页面管理方案,利用栈结构实现了页面切换和历史记录功能,可以方便地进行页面的后退操作、返回首页操作等。这种方法非常适合嵌入式图形用户界面(GUI)开发,尤其是在需要多个界面切换的智能设备应用中,读者需要仔细揣摩一下这份源码,之后就会感叹到他的精妙。
获取传感器数值
我们LVGL如何获取我们的传感器值如何刷新到屏幕上面呢?非常的简单,我们首先要知道LVGL有一个定时器功能,和我们FreeRTOS的软件定时器很像,会隔断时间进行调用一次,我们这里就是利用这个功能,每隔一段时间去获取一次传感器数值。我们一个有四个界面需要去实时获取传感器数值,分别是主界面、心率界面、血氧界面以及血压界面,这里对应四个LVGL定时:
ui_MainPageTimer、ui_HeartPageTimer
ui_Blood_Oxy_PageTimer、ui_Blood_Pressure_PageTimer
每次进行切换的时候,都会根据当前的界面,创建或者删除对应的LVGL定时器。
我们列举一个ui_MainPageTimer,其他都是一样的道理:
// need to be destroyed when the page is destroyed
static void MainPage_timer_cb(lv_timer_t * timer)
{
char buf[128];
uint32_t tmp;
if(Page_Get_NowPage()->page_obj == &ui_MainPage)
{
if(xQueueReceive(Senser_Queue, &r_SensorData_queue, 0) == pdPASS)
{
sprintf(buf, "%02d:%02d:%02d", r_SensorData_queue.rtc_time.RTC_Hours, r_SensorData_queue.rtc_time.RTC_Minutes, r_SensorData_queue.rtc_time.RTC_Seconds);
lv_label_set_text(Time_label, buf);
sprintf(buf, "%02d-%02d %s", r_SensorData_queue.rtc_date.RTC_Month, r_SensorData_queue.rtc_date.RTC_Date, ui_Days[r_SensorData_queue.rtc_date.RTC_WeekDay - 1]);
lv_label_set_text(Date_label, buf);
sprintf(buf, "%s", blue_state);
lv_label_set_text(Blue_label, buf);
sprintf(buf, "%d", r_SensorData_queue.dht11_data[2]);
lv_label_set_text(Temp_label, buf);
sprintf(buf, "%d", r_SensorData_queue.dht11_data[0]);
lv_label_set_text(Humi_label, buf);
// tmp = 3564;
// sprintf(buf, "Step: %d", tmp);
// lv_bar_set_value(Step_bar, tmp, LV_ANIM_ON);
// lv_label_set_text(Step_bar_label, buf);
sprintf(buf, "Step: %d", r_SensorData_queue.Step_Data);
lv_bar_set_value(Step_bar, r_SensorData_queue.Step_Data, LV_ANIM_ON);
lv_label_set_text(Step_bar_label, buf);
sprintf(buf, "%s", blue_state);
lv_label_set_text(Blue_label, buf);
memset(buf, 0, sizeof(buf));
}
}
}
前面的 Senser_Queue 这里就有用到了,通过获取这个队列,把所需传感器数值获取出来,如何修改到LVGL标签部件,从而显示到我们的GUI上,实现了我们传感器值实时显示到我们屏幕上面。
实体按键控制
其实这个属于LVGL基础知识,我们这里也讲解给大家听,因为这都是一套模板,都可以举一反三的,我们去到 lv_port_indev_template.c 这个文件中,只需要修改这里,并且前面把除了Keypad的输入设备全部注释掉,如图所示:
/*Will be called by the library to read the mouse*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static uint32_t last_key = 0;
static uint8_t key_pressed = 0; // 防止重复处理按键
char buf[30];
/*Get whether the a key is pressed and save the pressed key*/
//uint32_t act_key = keypad_get_key();
uint32_t act_key = keypad_get_key();
if(act_key != 0 && !key_pressed) {
data->state = LV_INDEV_STATE_PR;
BEEP_TOGGLE(1, 100);
/*Translate the keys to LVGL control characters according to your key definitions*/
switch(act_key) {
case 1:
act_key = LV_KEY_PREV;
break;
case 2:
act_key = LV_KEY_ENTER;
break;
case 3:
act_key = LV_KEY_NEXT;
break;
case 4:
act_key = LV_KEY_HOME;
//Exit_key_flag = 233;
//lv_event_send(lv_scr_act(), LV_EVENT_KEY, (void *)LV_KEY_DOWN);
break;
}
last_key = act_key;
key_pressed = 1; // 防止重复处理
}
else if(act_key == 0 && key_pressed)
{
data->state = LV_INDEV_STATE_REL;
last_key = 0;
key_pressed = 0; // 按键松开后,允许再次按下
}
data->key = last_key;
if (data->key == LV_KEY_HOME)
{
key_home_flag = 1;
//xSemaphoreGive(Page_Switch_BinarySem);
// if(Page_Get_NowPage()->page_obj == &ui_MainPage)
// {
// Page_Load(&Page_Menu);
// }
// else if(Page_Get_NowPage()->page_obj == &ui_MenuPage ||
// Page_Get_NowPage()->page_obj == &ui_HeartPage ||
// Page_Get_NowPage()->page_obj == &ui_Blood_Oxy_Page ||
// Page_Get_NowPage()->page_obj == &ui_Blood_Pressure_Page)
// {
// Page_Back();
// }
}
}
/*Get the currently being pressed key. 0 if no key is pressed*/
static uint32_t keypad_get_key(void)
{
/*Your code comes here*/
if(GPIO_ReadInputDataBit(KEY1_INT_GPIO_PORT, KEY1_INT_GPIO_PIN) == 1)
{
//delay_ms(20);
vTaskDelay(20);
if(GPIO_ReadInputDataBit(KEY1_INT_GPIO_PORT, KEY1_INT_GPIO_PIN) == 1)
{
//while(GPIO_ReadInputDataBit(KEY1_INT_GPIO_PORT, KEY1_INT_GPIO_PIN) == 1);
return 1;
}
}
else if(GPIO_ReadInputDataBit(KEY2_INT_GPIO_PORT, KEY2_INT_GPIO_PIN) == 1)
{
//delay_ms(20);
vTaskDelay(20);
if(GPIO_ReadInputDataBit(KEY2_INT_GPIO_PORT, KEY2_INT_GPIO_PIN) == 1)
{
//while(GPIO_ReadInputDataBit(KEY2_INT_GPIO_PORT, KEY2_INT_GPIO_PIN) == 1);
return 2;
}
}
else if(GPIO_ReadInputDataBit(KEY3_INT_GPIO_PORT, KEY3_INT_GPIO_PIN) ==1)
{
//delay_ms(20);
vTaskDelay(20);
if(GPIO_ReadInputDataBit(KEY3_INT_GPIO_PORT, KEY3_INT_GPIO_PIN) == 1)
{
//while(GPIO_ReadInputDataBit(KEY3_INT_GPIO_PORT, KEY3_INT_GPIO_PIN) == 1);
return 3;
}
}
else if(GPIO_ReadInputDataBit(KEY0_INT_GPIO_PORT, KEY0_INT_GPIO_PIN) == 0)
{
//delay_ms(20);
vTaskDelay(20);
if(GPIO_ReadInputDataBit(KEY0_INT_GPIO_PORT, KEY0_INT_GPIO_PIN) == 0)
{
//while(GPIO_ReadInputDataBit(KEY0_INT_GPIO_PORT, KEY0_INT_GPIO_PIN) == 0);
return 4;
}
}
return 0;
}
做完这一步,我们实际上就把我们的四个按键分别映射为了LV_KEY_PREV、LV_KEY_ENTER、LV_KEY_NEXT、LV_KEY_HOME,之后LVGL会根据这个,来进行对应的处理,至于如何处理,那就不归我们管了,这就是LVGL的好处了。
总结
至此,关于这个项目的LVGL知识点大概已经全部讲完了,这个已经把大概思路告诉大家了,至于细节部分,得大家多多揣摩一下源码了,我相信,只要肯多看,不会就去搜,那么所有问题就不是问题了。