【兆易GD32H759I-EVAL】 LVGL 实验 跑Guider实例
[复制链接]
本帖最后由 尹小舟 于 2024-6-26 08:45 编辑
LVGL(Light and Versatile Graphics Library)是一个开源的嵌入式图形库,专为资源有限的微控制器和显示器设计。要在MCU中使用LVGL中要实现定时器心跳函数、LCD填充函数和触摸屏驱动。需要遵循几个步骤。下面是一个简化的方法:
LVGL(Light and Versatile Graphics Library)是一个开源的嵌入式图形库,专为资源有限的微控制器和显示器设计。要在LVGL中实现定时器心跳函数、LCD填充函数和触摸屏驱动,你需要遵循几个步骤。下面是一个简化的指南:
1. 定时器心跳函数
LVGL 需要一个心跳函数(通常是一个定时器中断服务程序)来定期调用 lv_task_handler()。这个函数处理所有与LVGL相关的任务,如动画、事件处理等。
步骤:
- 设置定时器:使用你的微控制器的定时器功能来设置一个周期性的中断。
- 中断服务程序:在中断服务程序中,调用 lv_task_handler()。这个函数会处理LVGL的所有任务。
- 调整周期:根据你的应用需求调整定时器的周期。较短的周期可以提供更平滑的动画效果,但也会增加CPU负载。
2. LCD填充函数
LVGL 需要一个用于在LCD上显示像素的函数。这通常是一个硬件相关的函数,它知道如何将像素数据发送到LCD控制器。
步骤:
- 定义填充函数:创建一个函数,它接受一个矩形区域(由x、y坐标、宽度和高度定义)和一个颜色值作为参数。
- 实现填充逻辑:在这个函数中,编写代码来将颜色值写入到LCD控制器的帧缓冲区中,对应于指定的矩形区域。这通常涉及设置LCD控制器的地址指针、写入颜色数据等。
- 注册填充函数:使用LVGL的API( lv_disp_drv_register())来注册你的填充函数。当LVGL需要更新屏幕时,它就会调用你的函数。
3. 触摸屏驱动
为了使用触摸屏输入,你需要编写一个驱动程序来读取触摸屏控制器的数据,并将其转换为LVGL可以理解的坐标和触摸事件。
步骤:
- 初始化触摸屏:配置触摸屏控制器的寄存器,使其处于正常工作状态。
- 读取触摸数据:编写一个函数来从触摸屏控制器的寄存器中读取触摸数据(如X和Y坐标、触摸状态等)。
- 转换数据:将读取到的原始数据转换为LVGL可以理解的坐标和事件。例如,你可能需要将触摸坐标从触摸屏控制器的分辨率缩放到LVGL的坐标系统。
- 注册驱动程序:使用LVGL的API(如lv_indev_drv_register())来注册你的触摸屏驱动程序。这样,当LVGL需要处理触摸事件时,它就会调用你的驱动程序来读取触摸数据。
- 处理触摸事件:在驱动程序中,除了读取触摸数据外,你还需要编写代码来处理触摸事件(如按下、移动、释放等)。这些事件可以通过LVGL的API(如 lv_event_send())发送到LVGL的事件队列中,以便LVGL的控件可以响应它们。
定时器心跳函数移植
#include "./BSP/TIMER/timer.h"
#include "lvgl.h"
/**
* @brief 定时器TIMERX定时中断初始化函数
* @note
* 定时器的时钟来自APB1或APB2,如果CK_APBx = CK_AHB或CK_APBx = CK_AHB/2,
* 则定时器的时钟等于CK_AHB(CK_TIMERx = CK_AHB),而CK_AHB为300M, 所以定时器时钟 = 300Mhz
* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
* Ft=定时器工作频率,单位:Mhz
*
* @param arr: 自动重装值
* @param psc: 时钟预分频数
* @retval 无
*/
void timerx_int_init(uint64_t arr, uint16_t psc)
{
timer_parameter_struct timer_initpara; /* timer_initpara用于存放定时器的参数 */
/* 使能外设定时器时钟 */
rcu_periph_clock_enable(TIMERX_INT_CLK); /* 使能TIMERX的时钟 */
/* 复位定时器 */
timer_deinit(TIMERX_INT); /* 复位TIMERX */
timer_struct_para_init(&timer_initpara); /* 初始化timer_initpara为默认值 */
/* 配置定时器参数 */
timer_initpara.prescaler = psc; /* 设置预分频值 */
timer_initpara.alignedmode = TIMER_COUNTER_EDGE; /* 设置对齐模式为边沿对齐模式 */
timer_initpara.counterdirection = TIMER_COUNTER_UP; /* 设置向上计数模式 */
timer_initpara.period = arr; /* 设置自动重装载值 */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; /* 设置时钟分频因子 */
timer_initpara.repetitioncounter = 0; /* 设置重复计数器值 */
timer_init(TIMERX_INT, &timer_initpara); /* 根据参数初始化定时器 */
/* 使能定时器及其中断 */
timer_interrupt_flag_clear(TIMERX_INT, TIMER_INT_FLAG_UP); /* 清除定时器更新中断标志 */
timer_interrupt_enable(TIMERX_INT, TIMER_INT_UP); /* 使能定时器的更新中断 */
nvic_irq_enable(TIMERX_INT_IRQn, 1, 3); /* 配置NVIC设置优先级,抢占优先级1,响应优先级3 */
timer_enable(TIMERX_INT); /* 使能定时器TIMERX */
}
/**
* @brief 定时器TIMERX中断服务函数
* @param 无
* @retval 无
*/
void TIMERX_INT_IRQHandler(void)
{
if (timer_interrupt_flag_get(TIMERX_INT, TIMER_INT_FLAG_UP) == SET) /* 判断定时器更新中断是否发生 */
{
lv_tick_inc(1); /* lvgl的1ms心跳 */
timer_interrupt_flag_clear(TIMERX_INT, TIMER_INT_FLAG_UP); /* 清除定时器更新中断标志 */
}
}
LCD填充函数
/**
* @File lv_port_disp_templ.c
*
*/
/*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
#if 1
/*********************
* INCLUDES
*********************/
#include "gd32h759i_lcd_eval.h"
#include "lv_port_disp_template.h"
#include <stdbool.h>
#include "./BSP/LCD/lcd.h"
/*********************
* DEFINES
*********************/
#ifndef MY_DISP_HOR_RES
#warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now.
#define MY_DISP_HOR_RES 480
#endif
#ifndef MY_DISP_VER_RES
#warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen height, default value 240 is used for now.
#define MY_DISP_VER_RES 272
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void disp_init(void);
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*-----------------------------
* Create a buffer for drawing
*----------------------------*/
/**
* LVGL requires a buffer where it internally draws the widgets.
* Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
* The buffer has to be greater than 1 display row
*
* There are 3 buffering configurations:
* 1. Create ONE buffer:
* LVGL will draw the display's content here and writes it to your display
*
* 2. Create TWO buffer:
* LVGL will draw the display's content to a buffer and writes it your display.
* You should use DMA to write the buffer's content to the display.
* It will enable LVGL to draw the next part of the screen to the other buffer while
* the data is being sent form the first buffer. It makes rendering and flushing parallel.
*
* 3. Double buffering
* Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
* This way LVGL will always provide the whole rendered screen in `flush_cb`
* and you only need to change the frame buffer's address.
*/
/* Example for 1) */
// static lv_disp_draw_buf_t draw_buf_dsc_1;
// static lv_color_t buf_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
// lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
/* Example for 2) */
static lv_disp_draw_buf_t draw_buf_dsc_2;
static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/
static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/
lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/
// /* Example for 3) also set disp_drv.full_refresh = 1 below*/
// static lv_disp_draw_buf_t draw_buf_dsc_3;
// static lv_color_t buf_3_1[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*A screen sized buffer*/
// static lv_color_t buf_3_2[MY_DISP_HOR_RES * MY_DISP_VER_RES]; /*Another screen sized buffer*/
// lv_disp_draw_buf_init(&draw_buf_dsc_3, buf_3_1, buf_3_2,
// MY_DISP_VER_RES * LV_VER_RES_MAX); /*Initialize the display buffer*/
/*-----------------------------------
* Register the display in LVGL
*----------------------------------*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &draw_buf_dsc_2;
/*Required for Example 3)*/
//disp_drv.full_refresh = 1;
/* Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.*/
//disp_drv.gpu_fill_cb = gpu_fill;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
/*You code here*/
}
volatile bool disp_flush_enabled = true;
/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL
*/
void disp_enable_update(void)
{
disp_flush_enabled = true;
}
/* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL
*/
void disp_disable_update(void)
{
disp_flush_enabled = false;
}
/*Flush the content of the internal buffer the specific area on the display
*You can use DMA or any hardware acceleration to do this operation in the background but
*'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if(disp_flush_enabled) {
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
int32_t x;
int32_t y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/*Put a pixel to the display. For example:*/
/*put_px(x, y, *color_p)*/
lcd_draw_point(x, y, color_p ->full);
color_p++;
}
}
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
/*OPTIONAL: GPU INTERFACE*/
/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
// const lv_area_t * fill_area, lv_color_t color)
//{
// /*It's an example code which should be done by your GPU*/
// int32_t x, y;
// dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
//
// for(y = fill_area->y1; y <= fill_area->y2; y++) {
// for(x = fill_area->x1; x <= fill_area->x2; x++) {
// dest_buf[x] = color;
// }
// dest_buf+=dest_width; /*Go to the next line*/
// }
//}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
画点函数
/**
* @brief 画点
* @param x,y: 坐标
* @param color: 点的颜色(32位颜色,方便兼容TLI)
* @retval 无
*/
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
*(__IO uint16_t*)(current_framebuffer + 2*((LCD_PIXEL_WIDTH*y) + x)) = color;
}
触摸屏驱动
/**
* @file lv_port_indev_templ.c
*
*/
/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1
/*********************
* INCLUDES
*********************/
#include "lv_port_indev_template.h"
#include "../../lvgl.h"
#include "./BSP/TOUCH/touch.h"
#include <stdio.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);
//static void mouse_init(void);
//static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static bool mouse_is_pressed(void);
//static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y);
//static void keypad_init(void);
//static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static uint32_t keypad_get_key(void);
//static void encoder_init(void);
//static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static void encoder_handler(void);
//static void button_init(void);
//static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
//static int8_t button_get_pressed_id(void);
//static bool button_is_pressed(uint8_t id);
/**********************
* STATIC VARIABLES
**********************/
lv_indev_t * indev_touchpad;
//lv_indev_t * indev_mouse;
//lv_indev_t * indev_keypad;
//lv_indev_t * indev_encoder;
//lv_indev_t * indev_button;
//static int32_t encoder_diff;
//static lv_indev_state_t encoder_state;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_port_indev_init(void)
{
/**
* Here you will find example implementation of input devices supported by LittelvGL:
* - Touchpad
* - Mouse (with cursor support)
* - Keypad (supports GUI usage only with key)
* - Encoder (supports GUI usage only with: left, right, push)
* - Button (external buttons to press points on the screen)
*
* The `..._read()` function are only examples.
* You should shape them according to your hardware
*/
static lv_indev_drv_t indev_drv;
/*------------------
* Touchpad
* -----------------*/
/*Initialize your touchpad if you have*/
touchpad_init();
/*Register a touchpad input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = touchpad_read;
indev_touchpad = lv_indev_drv_register(&indev_drv);
/*------------------
* Mouse
* -----------------*/
/*Initialize your mouse if you have*/
// mouse_init();
// /*Register a mouse input device*/
// lv_indev_drv_init(&indev_drv);
// indev_drv.type = LV_INDEV_TYPE_POINTER;
// indev_drv.read_cb = mouse_read;
// indev_mouse = lv_indev_drv_register(&indev_drv);
// /*Set cursor. For simplicity set a HOME symbol now.*/
// lv_obj_t * mouse_cursor = lv_img_create(lv_scr_act());
// lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);
// lv_indev_set_cursor(indev_mouse, mouse_cursor);
// /*------------------
// * Keypad
// * -----------------*/
// /*Initialize your keypad or keyboard if you have*/
// keypad_init();
// /*Register a keypad input device*/
// lv_indev_drv_init(&indev_drv);
// indev_drv.type = LV_INDEV_TYPE_KEYPAD;
// indev_drv.read_cb = keypad_read;
// indev_keypad = lv_indev_drv_register(&indev_drv);
// /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
// *add objects to the group with `lv_group_add_obj(group, obj)`
// *and assign this input device to group to navigate in it:
// *`lv_indev_set_group(indev_keypad, group);`*/
// /*------------------
// * Encoder
// * -----------------*/
// /*Initialize your encoder if you have*/
// encoder_init();
// /*Register a encoder input device*/
// lv_indev_drv_init(&indev_drv);
// indev_drv.type = LV_INDEV_TYPE_ENCODER;
// indev_drv.read_cb = encoder_read;
// indev_encoder = lv_indev_drv_register(&indev_drv);
// /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
// *add objects to the group with `lv_group_add_obj(group, obj)`
// *and assign this input device to group to navigate in it:
// *`lv_indev_set_group(indev_encoder, group);`*/
// /*------------------
// * Button
// * -----------------*/
// /*Initialize your button if you have*/
// button_init();
// /*Register a button input device*/
// lv_indev_drv_init(&indev_drv);
// indev_drv.type = LV_INDEV_TYPE_BUTTON;
// indev_drv.read_cb = button_read;
// indev_button = lv_indev_drv_register(&indev_drv);
// /*Assign buttons to points on the screen*/
// static const lv_point_t btn_points[2] = {
// {10, 10}, /*Button 0 -> x:10; y:10*/
// {40, 100}, /*Button 1 -> x:40; y:100*/
// };
// lv_indev_set_button_points(indev_button, btn_points);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*------------------
* Touchpad
* -----------------*/
/*Initialize your touchpad*/
static void touchpad_init(void)
{
/*Your code comes here*/
/*Your code comes here*/
// /* 电阻屏如果发现显示屏XY镜像现象,需要坐标矫正 */
// if (0 == (tp_dev.touchtype & 0x80)) {
// tp_adjust();
// tp_save_adjust_data();
// }
}
/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
/*Save the pressed coordinates and the state*/
if(touchpad_is_pressed()) {
touchpad_get_xy(&last_x, &last_y);
data->state = LV_INDEV_STATE_PR;
}
else {
data->state = LV_INDEV_STATE_REL;
}
/*Set the last pressed coordinates*/
data->point.x = last_x;
data->point.y = last_y;
}
/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
/*Your code comes here*/
tp_dev.scan(0);
if (tp_dev.sta & TP_PRES_DOWN)
{
printf("\r\n x = %d y = %d",tp_dev.x[0],tp_dev.y[0]);
return true;
}
return false;
}
/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
/*Your code comes here*/
(*x) = tp_dev.x[0];
(*y) = tp_dev.y[0];
}
/*------------------
* Mouse
* -----------------*/
/*Initialize your mouse*/
static void mouse_init(void)
{
/*Your code comes here*/
}
///*Will be called by the library to read the mouse*/
//static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{
// /*Get the current x and y coordinates*/
// mouse_get_xy(&data->point.x, &data->point.y);
// /*Get whether the mouse button is pressed or released*/
// if(mouse_is_pressed()) {
// data->state = LV_INDEV_STATE_PR;
// }
// else {
// data->state = LV_INDEV_STATE_REL;
// }
//}
///*Return true is the mouse button is pressed*/
//static bool mouse_is_pressed(void)
//{
// /*Your code comes here*/
// return false;
//}
///*Get the x and y coordinates if the mouse is pressed*/
//static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y)
//{
// /*Your code comes here*/
// (*x) = 0;
// (*y) = 0;
//}
///*------------------
// * Keypad
// * -----------------*/
///*Initialize your keypad*/
//static void keypad_init(void)
//{
// /*Your code comes here*/
//}
///*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;
// /*Get the current x and y coordinates*/
// mouse_get_xy(&data->point.x, &data->point.y);
// /*Get whether the a key is pressed and save the pressed key*/
// uint32_t act_key = keypad_get_key();
// if(act_key != 0) {
// data->state = LV_INDEV_STATE_PR;
// /*Translate the keys to LVGL control characters according to your key definitions*/
// switch(act_key) {
// case 1:
// act_key = LV_KEY_NEXT;
// break;
// case 2:
// act_key = LV_KEY_PREV;
// break;
// case 3:
// act_key = LV_KEY_LEFT;
// break;
// case 4:
// act_key = LV_KEY_RIGHT;
// break;
// case 5:
// act_key = LV_KEY_ENTER;
// break;
// }
// last_key = act_key;
// }
// else {
// data->state = LV_INDEV_STATE_REL;
// }
// data->key = last_key;
//}
///*Get the currently being pressed key. 0 if no key is pressed*/
//static uint32_t keypad_get_key(void)
//{
// /*Your code comes here*/
// return 0;
//}
///*------------------
// * Encoder
// * -----------------*/
///*Initialize your keypad*/
//static void encoder_init(void)
//{
// /*Your code comes here*/
//}
///*Will be called by the library to read the encoder*/
//static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{
// data->enc_diff = encoder_diff;
// data->state = encoder_state;
//}
///*Call this function in an interrupt to process encoder events (turn, press)*/
//static void encoder_handler(void)
//{
// /*Your code comes here*/
// encoder_diff += 0;
// encoder_state = LV_INDEV_STATE_REL;
//}
///*------------------
// * Button
// * -----------------*/
///*Initialize your buttons*/
//static void button_init(void)
//{
// /*Your code comes here*/
//}
///*Will be called by the library to read the button*/
//static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
//{
// static uint8_t last_btn = 0;
// /*Get the pressed button's ID*/
// int8_t btn_act = button_get_pressed_id();
// if(btn_act >= 0) {
// data->state = LV_INDEV_STATE_PR;
// last_btn = btn_act;
// }
// else {
// data->state = LV_INDEV_STATE_REL;
// }
// /*Save the last pressed button's ID*/
// data->btn_id = last_btn;
//}
///*Get ID (0, 1, 2 ..) of the pressed button*/
//static int8_t button_get_pressed_id(void)
//{
// uint8_t i;
// /*Check to buttons see which is being pressed (assume there are 2 buttons)*/
// for(i = 0; i < 2; i++) {
// /*Return the pressed button's ID*/
// if(button_is_pressed(i)) {
// return i;
// }
// }
// /*No button pressed*/
// return -1;
//}
///*Test if `id` button is pressed or not*/
//static bool button_is_pressed(uint8_t id)
//{
// /*Your code comes here*/
// return false;
//}
#else /*Enable this file at the top*/
/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
跑一个Guider的实例
GUI-Guider 是恩智浦(NXP)为 LVGL 开发的一个上位机 GUI 设计工具。
- 功能特点:
- 拖放控件设计:GUI-Guider 提供了一个直观的拖放编辑器,允许用户通过拖放控件的方式快速设计 LVGL GUI 页面,从而加速 GUI 的设计过程。
- PC 端仿真运行:设计完成的 GUI 页面可以在 PC 上进行仿真运行,用户可以在没有实际硬件的情况下预览自己设计的 UI 界面。
- C 代码生成:确认设计完毕后,GUI-Guider 可以生成 C 代码,这些代码可以直接整合到 MCU 项目中,实现嵌入式设备的 GUI 功能。
- 兼容性:
- GUI-Guider 支持 Windows 10 和 Ubuntu 20.04 等操作系统。
- 它与恩智浦的通用和跨界 MCU 兼容,并包括用于多个受支持平台的内置项目模板。
- 优势:
- 相比 LVGL 官方推出的 SquareLine Studio(付费工具),GUI-Guider 完全免费,同时提供了类似的功能和界面布局。
- GUI-Guider 生成的示例工程底层代码全部开源
选择V8.3.5
选择Simulator
选择ButtonCounter模版
输入名称创建
选择模拟器生成编译
添加文件
添加头文件目录
main.c 添加头文件
#include "gui_guider.h"
#include "events_init.h"
定义 guider_ui 全局变量
lv_ui guider_ui;
#include "gd32h7xx.h"
#include "systick.h"
#include <stdio.h>
#include "gd32h759i_eval.h"
#include "gd32h759i_lcd_eval.h"
#include "./BSP/LCD/lcd.h"
#include "lv_port_disp_template.h"
#include "lv_port_indev_template.h"
#include "../../lvgl.h"
#include "lv_demo_stress.h"
#include "lv_demo_music.h"
#include "./BSP/TOUCH/touch.h"
#include "./BSP/TIMER/timer.h"
#include "gui_guider.h"
#include "events_init.h"
lv_ui guider_ui;
/*!
\brief enable the CPU cache
\param[in] none
\param[out] none
\retval none
*/
void cache_enable(void)
{
/* enable i-cache */
SCB_EnableICache();
/* enable d-cache */
SCB_EnableDCache();
}
/**
* @brief 清空屏幕并在右上角显示"RST"
* @param 无
* @retval 无
*/
void load_draw_dialog(void)
{
lcd_clear(WHITE); /* 清屏 */
lcd_show_string(lcddev.width - 24, 0, 200, 16, 16, "RST", BLUE); /* 显示清屏区域 */
}
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
/* enable the CPU cache */
cache_enable();
/* configure systick */
//systick_config();
delay_init(600);
/* initilize the LEDs, USART and key */
gd_eval_led_init(LED1);
gd_eval_led_init(LED2);
gd_eval_com_init(EVAL_COM);
gd_eval_key_init(KEY_WAKEUP, KEY_MODE_GPIO);
timerx_int_init(10 - 1, 30000 - 1);
printf("\r\nCK_SYS is %d", rcu_clock_freq_get(CK_SYS));
lcd_init();
tp_dev.init();
if(RESET == gd_eval_key_scan(KEY_WAKEUP))
{
lcd_clear(WHITE); /* 清屏 */
tp_adjust(); /* 屏幕校准 */
tp_save_adjust_data();
}
lv_init();
lv_port_disp_init();
lv_port_indev_init();
setup_ui(&guider_ui);
events_init(&guider_ui);
while(1) {
lv_timer_handler();
}
}
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
usart_data_transmit(EVAL_COM, (uint8_t)ch);
while(RESET == usart_flag_get(EVAL_COM, USART_FLAG_TBE));
return ch;
}
实验现象
WeChat_20240625173102
|