lvgl的区别 qt_调试 lvgl 的一个例子

本文介绍了在Linux环境下配置和调试LVGL图形库的过程。首先,作者介绍了LVGL的特点和适用场景,然后详细阐述了配置项目所需的文件,包括lvgl主项目、驱动和示例代码。在配置部分,详细讲解了如何修改lv_conf.h、lv_drv_conf.h和lv_ex_conf.h等配置文件,并提供了main.c的代码示例。在调试过程中,作者针对fbdev驱动和event设备驱动进行了修改,解决了显示错位和鼠标坐标范围问题。最后,提供了运行该项目所需的步骤,包括关闭图形系统和启动程序的方法。附录中包含用于测试framebuffer和event设备的代码示例。
摘要由CSDN通过智能技术生成

发现一个新的 vector graphic 的库,用 C 写的,效果丰富,接口简单,而且是 MIT License,所以想试一试。因为它支持 framebuffer,所以,在 linux 上先走一个。

项目主页:https://littlevgl.com/

1. 文件准备

项目组织还不是很好,所以需要手动配置项目,需要的文件包括:

- lvgl 主项目

- lv_driver 目前支持的驱动。基本上如果使用渲染缓存的话,只要考虑怎么把渲染缓存里的东西搬移到显示缓存中即可。即最简实现 disp_init 和 disp_flush。

- lv_example 示例代码。本实验尝试了 demo 和 benchmark,记录的是 benchmark 的调试。

另外,作者还提供了一个基于 SDL 的模拟器,如果不是特别熟悉 LInux 的话,从 SDL 开始会是个比较好的选择。作者 github 上可以找到。

2. 配置

我使用的环境是 vmware+mint19。

项目需要建一个新的目录,将上面准备的三个文件夹拷贝到项目目录下,也可以用软连接链过来,随意。

在项目目录下,需要添加下面几个文件:

1)lv_conf.h 这个文件从 lvgl 目录下的 lv_config_temple.h 拷贝而来。我这里修改了分辨率为 800x400,color_depth = 24

2)lv_drv_conf.h 这个文件从 lv_drv_conf_temple.h 拷贝而来。将 USE_FBDEV(frame_buffer) 和 USE_EVDEV(/dev/input/event) 修改为 1.

3)  lv_ex_conf.h 这个文件从 lv_ex_conf_temple.h 拷贝而来。将 BENCHMARK 改为1 就好了。

4)mian.c 最终版本如下。从官网的例子修改而来,benchmark 的 demo,然后使用 /dev/input/event2 作为鼠标输入,还给鼠标加了个图标。

#include "lvgl/lvgl.h"#include"lv_drivers/display/fbdev.h"#include"lv_drivers/indev/evdev.h"#include"lv_examples/lv_apps/benchmark/benchmark.h"#include

int main(void)

{

lv_init();

fbdev_init();

lv_disp_drv_t disp_drv;

lv_disp_drv_init(&disp_drv);

disp_drv.disp_flush=fbdev_flush;lv_disp_drv_register(&disp_drv);

evdev_init();

lv_indev_drv_t indev_drv;

lv_indev_drv_init(&indev_drv);

indev_drv.type=LV_INDEV_TYPE_POINTER;

indev_drv.read=evdev_read;

lv_indev_drv_register(&indev_drv);

lv_indev_t*mouse =lv_indev_next(NULL);

lv_obj_t*cursor =lv_label_create(lv_scr_act(), NULL);

lv_label_set_recolor(cursor,true);

lv_label_set_text(cursor,"#ff0000 .cursor");

lv_indev_set_cursor(mouse, cursor);

benchmark_create();while(1) {

lv_tick_inc(5);

lv_task_handler();

usleep(5000);

}return 0;

}

5)Makefile 用的下面这个,从哪里找来的,找不到出处了,自己稍微做了修改

#

# Makefile

#

CC= gccCFLAGS= -Wall -Wshadow -Wundef -Wmaybe-uninitialized

CFLAGS+= -O3 -g3 -I./#LDFLAGS+= -lSDL2 -lm

BIN=demo

VPATH=MAINSRC=main.c

#LIBRARIES

include ./lvgl/lv_core/lv_core.mk

include ./lvgl/lv_hal/lv_hal.mk

include ./lvgl/lv_objx/lv_objx.mk

include ./lvgl/lv_misc/lv_fonts/lv_fonts.mk

include ./lvgl/lv_misc/lv_misc.mk

include ./lvgl/lv_themes/lv_themes.mk

include ./lvgl/lv_draw/lv_draw.mk

#DRIVERS

include ./lv_drivers/display/display.mk

include ./lv_drivers/indev/indev.mk

#EXAMPLE

include ./lv_examples/lv_apps/benchmark/benchmark.mk

OBJEXT?=.o

AOBJS= $(ASRCS:.S=$(OBJEXT))

COBJS= $(CSRCS:.c=$(OBJEXT))

MAINOBJ= $(MAINSRC:.c=$(OBJEXT))

SRCS=$(ASRCS) $(CSRCS) $(MAINSRC)

OBJS=$(AOBJS) $(COBJS)

## MAINOBJ->OBJFILES

all: clean default%.o: %.c

@$(CC) $(CFLAGS)-c $< -o $@

@echo"CC $

$(CC)-o $(BIN) $(MAINOBJ) $(AOBJS) $(COBJS) $(LDFLAGS)

clean:rm -f $(BIN) $(AOBJS) $(COBJS) $(MAINOBJ)

3. 做的修改

原作者的代码可能是测试环境不一样,我第一次没跑出来,经过调试,最终做了下面修改后得到想要的结果。

1)第一处是 fbdev 的驱动,修改了 /lv_driver/display/fbdev.c。第一次编译后,显示一团浆糊,仔细看可以辨认是填图的时候错位了,借鉴了后面附1 的代码,修改了 flush 函数如下。

if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {

uint32_t*fbp32 = (uint32_t*)fbp;

uint32_t x;

uint32_t y;int stride = finfo.line_length / 4;for(y = act_y1; y <= act_y2; y++) {for(x = act_x1; x <= act_x2; x++) {

location= (x+vinfo.xoffset) + (y+vinfo.yoffset) *stride;

fbp32[location]= color_p->full;

color_p++;

}

color_p+= x2 -act_x2;

}

}

重新计算了 buffer 中一行的长度,作者原来直接是把 vinfo.xref 拿来用了,我这里是 800。上面代码算出来的 stride 是 1176,但是能正常显示。

2)针对 event 设备的修改。修改了文件 lv_drivers/indev/evdev.c。这里的问题是,驱动里面的 x 范围只有 0 - LV_HOR_RES。大概是作者的理解中,鼠标的坐标范围是和分辨率一致的。但是,我用 附录2 的代码以及 hexdump 看到的,这个范围是 0-65535。所以,这个坐标需要归一化。我添加了两个变量。

#if USE_FBDEV

extern intfb_x_max;extern intfb_y_max;#endif

这两个全局变量,需要在 fbdev.c 也要在声明一下,他们取下面的值:

//Get variable screen information

if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {

perror("Error reading variable information");return;

}

printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

printf("%d \n", finfo.line_length);

fb_x_max=vinfo.xres;

fb_y_max= vinfo.yres;

因此,main 函数中,初始化 event 设备,要在初始化 fbdev 之后,要不然,这两个值取不到。然后,在 evdev_init 中 将这两个值转化为鼠标的分辨率。

void evdev_init(void)

{

evdev_fd= open(EVDEV_NAME, O_RDWR|O_NOCTTY|O_NDELAY);if (evdev_fd == -1) {

perror("unable open evdev interface:");return;

}

fcntl(evdev_fd, F_SETFL, O_ASYNC|O_NONBLOCK);

evdev_root_x= 0;

evdev_root_y= 0;

evdev_button=LV_INDEV_STATE_REL;#if USE_FBDEV

//global var: double evdev_x_resolution, evdev_y_resolution

evdev_x_resolution = (float)fb_x_max / 65535.0;

evdev_y_resolution= (float)fb_y_max / 65535.0;#elseevdev_x_resolution= 1;

evdev_y_resolution= 1;#endif}

然后,读取鼠标坐标的时候,进行归一化:

while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {if (in.type ==EV_REL) {if (in.code ==REL_X)

evdev_root_x+= in.value;else if (in.code ==REL_Y)

evdev_root_y+= in.value;

}else if (in.type ==EV_ABS) {if (in.code ==ABS_X)

evdev_root_x= in.value *evdev_x_resolution;else if (in.code ==ABS_Y)

evdev_root_y= in.value *evdev_y_resolution;

}else if (in.type ==EV_KEY) {if (in.code == BTN_MOUSE || in.code ==BTN_TOUCH) {if (in.value == 0)

evdev_button=LV_INDEV_STATE_REL;else if (in.value == 1)

evdev_button=LV_INDEV_STATE_PR;

}//printf("BTN ClICKED(%d, %d) \n", evdev_root_x, evdev_root_y);

}

}

这样,/dev/intpu/event 中读到的坐标就可以被 lvgl 识别了。

4. 运行

需要关闭图形系统,来运行这个程序。首先按 ctr+alt+f1 登录到 tty,然后使用 sudo service ligthdm stop 来关闭系统的图形系统。

然后,就可以 sudo .demo 来查看效果了。

想回到图形系统,直接 sudo service lightdm start 即可。

20180822153852528336.png

附1. framebuffer 测试程序

#include #include#include#include#include#include#include#include#include#include#include

structfb_var_screeninfo vinfo;structfb_fix_screeninfo finfo;char *frameBuffer = 0;//打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。

voidprintFixedInfo ()

{

printf ("Fixed screen info:\n"

"\tid: %s\n"

"\tsmem_start: 0x%lx\n"

"\tsmem_len: %d\n"

"\ttype: %d\n"

"\ttype_aux: %d\n"

"\tvisual: %d\n"

"\txpanstep: %d\n"

"\typanstep: %d\n"

"\tywrapstep: %d\n"

"\tline_length: %d\n"

"\tmmio_start: 0x%lx\n"

"\tmmio_len: %d\n"

"\taccel: %d\n"

"\n",

finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,

finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,

finfo.ywrapstep, finfo.line_length, finfo.mmio_start,

finfo.mmio_len, finfo.accel);

}//打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置

voidprintVariableInfo ()

{

printf ("Variable screen info:\n"

"\txres: %d\n"

"\tyres: %d\n"

"\txres_virtual: %d\n"

"\tyres_virtual: %d\n"

"\tyoffset: %d\n"

"\txoffset: %d\n"

"\tbits_per_pixel: %d\n"

"\tgrayscale: %d\n"

"\tred: offset: %2d, length: %2d, msb_right: %2d\n"

"\tgreen: offset: %2d, length: %2d, msb_right: %2d\n"

"\tblue: offset: %2d, length: %2d, msb_right: %2d\n"

"\ttransp: offset: %2d, length: %2d, msb_right: %2d\n"

"\tnonstd: %d\n"

"\tactivate: %d\n"

"\theight: %d\n"

"\twidth: %d\n"

"\taccel_flags: 0x%x\n"

"\tpixclock: %d\n"

"\tleft_margin: %d\n"

"\tright_margin: %d\n"

"\tupper_margin: %d\n"

"\tlower_margin: %d\n"

"\thsync_len: %d\n"

"\tvsync_len: %d\n"

"\tsync: %d\n"

"\tvmode: %d\n"

"\n",

vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,

vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel,

vinfo.grayscale, vinfo.red.offset, vinfo.red.length,

vinfo.red.msb_right, vinfo.green.offset, vinfo.green.length,

vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length,

vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length,

vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate,

vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock,

vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin,

vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len,

vinfo.sync, vinfo.vmode);

}//画大小为width*height的同色矩阵,8alpha+8reds+8greens+8blues

voiddrawRect_rgb32 (int x0, int y0, int width, int height, intcolor)

{const int bytesPerPixel = 4;const int stride = finfo.line_length /bytesPerPixel;int *dest = (int *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);intx, y;for (y = 0; y < height; ++y)

{for (x = 0; x < width; ++x)

{

dest[x]=color;

}

dest+=stride;

}

}//画大小为width*height的同色矩阵,5reds+6greens+5blues

voiddrawRect_rgb16 (int x0, int y0, int width, int height, intcolor)

{const int bytesPerPixel = 2;const int stride = finfo.line_length /bytesPerPixel;const int red = (color & 0xff0000) >> (16 + 3);const int green = (color & 0xff00) >> (8 + 2);const int blue = (color & 0xff) >> 3;const short color16 = blue | (green << 5) | (red << (5 + 6));short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);intx, y;for (y = 0; y < height; ++y)

{for (x = 0; x < width; ++x)

{

dest[x]=color16;

}

dest+=stride;

}

}//画大小为width*height的同色矩阵,5reds+5greens+5blues

voiddrawRect_rgb15 (int x0, int y0, int width, int height, intcolor)

{const int bytesPerPixel = 2;const int stride = finfo.line_length /bytesPerPixel;const int red = (color & 0xff0000) >> (16 + 3);const int green = (color & 0xff00) >> (8 + 3);const int blue = (color & 0xff) >> 3;const short color15 = blue | (green << 5) | (red << (5 + 5)) | 0x8000;short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);intx, y;for (y = 0; y < height; ++y)

{for (x = 0; x < width; ++x)

{

dest[x]=color15;

}

dest+=stride;

}

}voiddrawRect (int x0, int y0, int width, int height, intcolor)

{switch(vinfo.bits_per_pixel)

{case 32:

drawRect_rgb32 (x0, y0, width, height, color);break;case 16:

drawRect_rgb16 (x0, y0, width, height, color);break;case 15:

drawRect_rgb15 (x0, y0, width, height, color);break;default:

printf ("Warning: drawRect() not implemented for color depth %i\n",

vinfo.bits_per_pixel);break;

}

}#define PERFORMANCE_RUN_COUNT 5

voidperformSpeedTest (void *fb, intfbSize)

{inti, j, run;structtimeval startTime, endTime;

unsignedlong longresults[PERFORMANCE_RUN_COUNT];

unsignedlong longaverage;

unsignedint *testImage;

unsignedint randData[17] ={0x3A428472, 0x724B84D3, 0x26B898AB, 0x7D980E3C, 0x5345A084,0x6779B66B, 0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33,0x0E26EB73, 0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B,0x5F2C22FB, 0x6A742130};

printf ("Frame Buffer Performance test...\n");for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run)

{/*Generate test image with random(ish) data:*/testImage= (unsigned int *) malloc(fbSize);

j=run;for (i = 0; i < (int) (fbSize / sizeof (int)); ++i)

{

testImage[i]=randData[j];

j++;if (j >= 17)

j= 0;

}

gettimeofday (&startTime, NULL);

memcpy (fb, testImage, fbSize);

gettimeofday (&endTime, NULL);long secsDiff = endTime.tv_sec -startTime.tv_sec;

results[run]=secsDiff* 1000000 + (endTime.tv_usec -startTime.tv_usec);free(testImage);

}

average= 0;for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)

average+=results[i];

average= average /PERFORMANCE_RUN_COUNT;

printf ("Average: %llu usecs\n", average);

printf ("Bandwidth: %.03f MByte/Sec\n",

(fbSize/ 1048576.0) / ((double) average / 1000000.0));

printf ("Max. FPS: %.03f fps\n\n",1000000.0 / (double) average);/*Clear the framebuffer back to black again:*/memset (fb,0, fbSize);

}intmain (int argc, char **argv)

{const char *devfile = "/dev/fb0";long int screensize = 0;int fbFd = 0;/*Open the file for reading and writing*/fbFd=open (devfile, O_RDWR);if (fbFd == -1)

{

perror ("Error: cannot open framebuffer device");

exit (1);

}//获取finfo信息并显示

if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)

{

perror ("Error reading fixed information");

exit (2);

}

printFixedInfo ();//获取vinfo信息并显示

if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)

{

perror ("Error reading variable information");

exit (3);

}

printVariableInfo ();/*Figure out the size of the screen in bytes*/screensize=finfo.smem_len;/*Map the device to memory*/frameBuffer=(char *) mmap (0, screensize, PROT_READ |PROT_WRITE, MAP_SHARED,

fbFd,0);if (frameBuffer ==MAP_FAILED)

{

perror ("Error: Failed to map framebuffer device to memory");

exit (4);

}//测试virt fb的性能

performSpeedTest (frameBuffer, screensize);

printf ("Will draw 3 rectangles on the screen,\n"

"they should be colored red, green and blue (in that order).\n");

drawRect (vinfo.xres/ 8, vinfo.yres / 8,

vinfo.xres/ 4, vinfo.yres / 4, 0xffff0000);

drawRect (vinfo.xres* 3 / 8, vinfo.yres * 3 / 8,

vinfo.xres/ 4, vinfo.yres / 4, 0xff00ff00);

drawRect (vinfo.xres* 5 / 8, vinfo.yres * 5 / 8,

vinfo.xres/ 4, vinfo.yres / 4, 0xff0000ff);

sleep (5);

printf ("Done.\n");

munmap (frameBuffer, screensize);//解除内存映射,与mmap对应

close (fbFd);return 0;

}

附2 event 的测试程序

#include #include#include#include#include#include#include

#define DEV_NAME "/dev/input/event2"

#define DBG_PRINTF printf

//#define DBG_PRINTF(...)

structinput_event input_mouse;int main(int argc, char **argv)

{intfd,retval;

fd_set readfds;

fd=open(DEV_NAME, O_RDONLY);if (fd < 0)

{

printf("can‘t open %s\n",DEV_NAME);return -1;

}while(1)

{

FD_ZERO(&readfds );

FD_SET( fd,&readfds );

retval= select( fd+1, &readfds, NULL, NULL, NULL);if(retval==0)

{

printf("Time out!\n");

}if(FD_ISSET(fd,&readfds))

{

read(fd,&input_mouse,sizeof(structinput_event));//printf("mouse.type = %d, mouse.code = %d\n", input_mouse.type, input_mouse.code);

switch(input_mouse.type)

{caseEV_KEY:

{/*have key is press*/

switch(input_mouse.code)

{caseBTN_LEFT:

{if(input_mouse.value==1)

DBG_PRINTF("the left is press!\n");

}break;caseBTN_RIGHT:

{if(input_mouse.value==1)

DBG_PRINTF("the right is press!\n");

}break;caseBTN_MIDDLE:

{if(input_mouse.value==1)

DBG_PRINTF("the middle is press!\n");

}break;

}

}break;caseEV_REL:caseEV_ABS:

{switch(input_mouse.code)

{caseREL_X:

{/*if(input_mouse.value>0)

DBG_PRINTF("X slip is right!\n");

else if(input_mouse.value<0)

DBG_PRINTF("X slip is left!\n");*/printf("POS( %d,", input_mouse.value);

}break;caseREL_Y:

{/*if(input_mouse.value<0)

DBG_PRINTF("Y slip is up!\n");

else if(input_mouse.value>0)

DBG_PRINTF("Y slip is down!\n");*/printf("%d ) \n", input_mouse.value);

}break;

}

}break;

}

}

}

close(fd);return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值