LVGL+FreeRTOS实战项目:智能健康助手(LVGL篇)

目录

简介

生成GUI界面

界面切换

获取传感器数值

实体按键控制

总结


简介

本篇主要会教大家如何利用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基础知识也有讲解过,如下所示:

LVGL基础知识(入门必看)

LVGL部件篇:标签部件(lv_label)

LVGL部件篇: 开关部件(lv_switch)

LVGL控件篇:图片部件(lv_img)

注意的是,由于我们模拟器无法模拟传感器获取,所以我们直接把数值写死进行模拟。

界面切换

我们这么多个界面是如何进行切换的呢?这个就是这个项目的灵魂之处了。我们采用的是压栈以及入栈的思想,我们先看一下源码:

#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知识点大概已经全部讲完了,这个已经把大概思路告诉大家了,至于细节部分,得大家多多揣摩一下源码了,我相信,只要肯多看,不会就去搜,那么所有问题就不是问题了。

lvgl是一个开源的图形库,用于嵌入式系统的图形界面开发。而FreeRTOS是一个流行的实时操作系统,用于嵌入式系统的任务调度和管理。将lvglFreeRTOS进行移植,可以在嵌入式系统上实现图形界面和多任务的功能。 移植lvgl+FreeRTOS的步骤如下: 1. 配置硬件平台:根据目标硬件平台的特性,配置相应的驱动和外设支持。例如,配置显示屏驱动、触摸屏驱动等。 2. 配置FreeRTOS:根据目标硬件平台的资源和需求,配置FreeRTOS的内核参数,如任务堆栈大小、任务优先级等。 3. 移植lvgl:将lvgl的源代码添加到项目中,并根据目标硬件平台的特性进行适配。主要包括以下几个方面: - 配置显示驱动:根据硬件平台的显示屏特性,实现lvgl的显示驱动接口。 - 配置输入设备驱动:根据硬件平台的输入设备特性,实现lvgl的输入设备驱动接口,如触摸屏驱动。 - 配置定时器:lvgl需要定时器来进行刷新和动画效果的处理,需要配置定时器中断。 - 配置内存管理:lvgl需要内存管理来进行图形对象的创建和销毁,需要配置内存管理接口。 4. 编写应用程序:在FreeRTOS的任务中,使用lvgl的API来创建图形界面和处理用户交互。可以使用lvgl提供的控件、样式和动画效果来设计界面。 5. 编译和调试:将移植好的代码编译生成可执行文件,并下载到目标硬件平台上进行调试和测试。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值