前言

  在日常的开发中,涉及到用户显示界面控制的时候,如何快速、优美的设计一款用户UI,是攻城狮应该具备的能力(择偶优先权),如何把嵌入式UI设计像高级语言图形化设计一样简便、快捷,今天重磅介绍一款GUI设计开源库,LittleVgl,俗称LVGL,来吧,直接上干货,淦!

硬件环境

  • STM32F407ZGT6(或者其他板子)

  • 2.4寸TFT电阻式触摸屏

软件环境

  • keil5

  • lvgl软件源码

  • 正点原子触摸屏例程

  • 注:以上只是小飞哥使用的环境,其他也可以的,重要的是这种方法~

LVGL开源库是什么?

  欢迎大家查看这篇文章,对LVGL有详细的介绍

  • lvgl最新版本在STM32上的移植使用

  移植过程是相对不复杂的,主要是添加文件到STM32工程,将LVGL源码添加进来,源码部分就没有什么多说的啦,所有的基本绘图函数都在其中,用户UI代码主要是用户自己设计的显示代码,可以导入一些官方例程之类的,也不多做介绍

LVGL与嵌入式平台显示接口

  我们本次主要关注lv_port_disp.c和lv_port_indev.c,学习如何在LVGL开源库和嵌入式平台之间搭建一条桥梁,让两者联系起来,在lv_port_disp.c中调用打点函数或者画图形函数即可,小飞哥调用的是打点函数,显示部分只需要调用这一点即可。

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)

//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(u16 x, u16 y, u32 color)
{if (lcddev.id == 0X9341 || lcddev.id == 0X5310){LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x >> 8);LCD_WR_DATA(x & 0XFF);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y >> 8);LCD_WR_DATA(y & 0XFF);}else if (lcddev.id == 0X5510){LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x >> 8);LCD_WR_REG(lcddev.setxcmd + 1);LCD_WR_DATA(x & 0XFF);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y >> 8);LCD_WR_REG(lcddev.setycmd + 1);LCD_WR_DATA(y & 0XFF);}else if (lcddev.id == 0X1963){if (lcddev.dir == 0)x = lcddev.width - 1 - x;LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x >> 8);LCD_WR_DATA(x & 0XFF);LCD_WR_DATA(x >> 8);LCD_WR_DATA(x & 0XFF);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y >> 8);LCD_WR_DATA(y & 0XFF);LCD_WR_DATA(y >> 8);LCD_WR_DATA(y & 0XFF);}LCD->LCD_REG = lcddev.wramcmd;LCD->LCD_RAM = color;
}
void LCD_DrawFRONT_COLOR(u16 x, u16 y, u16 color)
{LCD_Fast_DrawPoint(x,y,color);
}
/* 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)
{/*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: */LCD_DrawFRONT_COLOR(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);
}

LVGL与嵌入式平台控制接口

  然后是触摸屏控制部分,本文只介绍如何实现触摸屏结合LVGL控制,完成代替物理按键控制,关于触摸屏的驱动,可以查看原子哥的详细介绍,就不做赘述了。

  lv_port_indev.c源文件中,我们可以看到定义了很多的接口,鼠标的,按键的,触摸的,等等,此次我们只用到触摸部分,我只保留了触摸的代码,其他的都删除了(主要是懒,删除最快捷),一下是修改后的代码,触摸部分的代码,只需要把原子哥的电阻屏驱动代码copy进来即可。

  其实,lvgl的框架是不错的,这里为了省事,是直接改掉了tuoch_read函数,其他的获取坐标、按下确认等都没有使用,建议小伙伴们可以使用下完整的框架试试。

/* Will be called by the library to read the touchpad */
static bool 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;tp_dev.scan(0);if (tp_dev.sta & TP_PRES_DOWN) //{printf("x坐标:%d,Y坐标:%d\r\n", tp_dev.x[0], tp_dev.y[0]);last_x = tp_dev.x[0];last_y = tp_dev.y[0];data->point.x = last_x;data->point.y = last_y;data->state = LV_INDEV_STATE_PR;}else{data->point.x = last_x;data->point.y = last_y;data->state = LV_INDEV_STATE_REL;}//    /*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 `false` because we are not buffering and no more data to read*/return false;
}
/*** @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.h"
#include "lv_hal_indev.h"
#include "touch.h"/**********************      DEFINES*********************/
extern _m_tp_dev tp_dev; //锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷touch.c锟斤拷锟芥定锟斤拷
/***********************      TYPEDEFS**********************//***********************  STATIC PROTOTYPES**********************/static void touchpad_init(void);
static bool 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 VARIABLES**********************/
lv_indev_t *indev_touchpad;/***********************      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*/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);
}/***********************   STATIC FUNCTIONS**********************//*------------------* Touchpad* -----------------*//*Initialize your touchpad*/
static void touchpad_init(void)
{/*Your code comes here*/
}/* Will be called by the library to read the touchpad */
static bool 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;tp_dev.scan(0);if (tp_dev.sta & TP_PRES_DOWN) //{printf("x坐标:%d,Y坐标:%d\r\n", tp_dev.x[0], tp_dev.y[0]);last_x = tp_dev.x[0];last_y = tp_dev.y[0];data->point.x = last_x;data->point.y = last_y;data->state = LV_INDEV_STATE_PR;}else{data->point.x = last_x;data->point.y = last_y;data->state = LV_INDEV_STATE_REL;}//    /*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 `false` because we are not buffering and no more data to read*/return false;
}/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{/*Your code comes here*/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) = 0;(*y) = 0;
}#else /* Enable this file at the top *//* This dummy typedef exists purely to silence -Wpedantic. */
typedef int keep_pedantic_happy;
#endif

LVGL配置文件

   开发过程中,屏幕尺寸一般是根据外壳结构,产品形态等决定的,但是一般不会更换驱动芯片,所以对开发者来讲,底层驱动是不变的,但是随着屏幕尺寸的改变,苦逼的是还要一一修改尺寸,我们可以通过配置文件,对不同的屏幕做适配,可以参考LVGL官方配置文件,这里可以更改屏幕尺寸,配置文件里面还有很多配置项,很像我们做上位机界面时候的属性,通过修改不同的值,得到我们想要的效果,小伙伴们可以探索探索哈,实践出真知~

实例演示

   群里有小伙伴最近有些疑惑,想使用slider做控制,不知道如何是用触摸屏,对如何如何获取触摸值,通过slider传输值目标器件,小飞哥一听,必须安排,粉丝的事无大小,干!!!

  我们直接使用官方库,slider例程,例程是有两种slider,我使用的是第二种,添加到我们的工程中即可,需要再配置文件中开启方框中的选项。

void lv_ex_slider_2(void)
{/* Create a slider in the center of the display */lv_obj_t * slider = lv_slider_create(lv_scr_act(), NULL);lv_obj_set_width(slider, LV_DPI * 2);lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 0);lv_obj_set_event_cb(slider, slider_event_cb);lv_slider_set_range(slider, 0, 100);     //修改此处,可以修改slider数值范围,目前是0-100/* Create a label below the slider */slider_label = lv_label_create(lv_scr_act(), NULL);lv_label_set_text(slider_label, "0");lv_obj_set_auto_realign(slider_label, true);lv_obj_align(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);/* Create an informative label */lv_obj_t * info = lv_label_create(lv_scr_act(), NULL);lv_label_set_text(info, "Welcome to join in Embeded-Party\n");lv_obj_align(info, NULL, LV_ALIGN_IN_TOP_LEFT, 10, 10);
}

  上面顺利的话,此时我们的触摸屏驱动是OK的,无论按在哪一处,都是有坐标值的,来测试下,触摸任意位置时候,获取到的坐标值,可以发现,我们无论按在哪一位置,总是有坐标的,但是,显然是有很多我们不需要的值,那么如何处理呢?

  对于slider来说,我们只需要进度条区域内的值作为我们输出的对象,这里就可以体会到LVGL的乐趣了,如何把坐标值转换为slider对应的数值,我们不需要关心如何实现的,直接按就完事了,黑盒子会帮我们实现,我们只需要在slider回调函数里面处理即可:

static void slider_event_cb(lv_obj_t * slider, lv_event_t event)
{ int16_t barvalue = 0;if(event == LV_EVENT_VALUE_CHANGED) {static char buf[4]; /* max 3 bytes for number plus 1 null terminating byte */barvalue =  lv_slider_get_value(slider);printf("barvlue is %d\r\n",barvalue);snprintf(buf, 4, "%u", lv_slider_get_value(slider));lv_label_set_text(slider_label, buf);}
}

  main函数部分

int main(void)
{HAL_Init();      //初始化HAL库Stm32_Clock_Init(336, 8, 2, 7); //设置时钟,168Mhzdelay_init(168);    //初始化延时函数uart_init(115200);    //初始化USARTLED_Init();      //初始化LEDKEY_Init();      //初始化KEYLCD_Init();      //初始化LCDtp_dev.init();     //触摸屏初始化lv_init();    // 初始化lvgllv_port_disp_init(); // 显示初始化lv_port_indev_init();//lv_demo_widgets();  // 例子演示lv_ex_slider_2();//lv_ex_calendar_1();//lv_demo_keypad_encoder();
// lv_demo_printer();KEY_Init();        //初始化按键TIM3_Init(1000 - 1, 84 - 1); //定时器3初始化,定时器时钟为84M,分频系数为8400-1,//所以定时器3的频率为84M/8400=10K,自动重装载为100-1,那么定时器周期就是10mswhile (1){lv_task_handler(); // 循环调用处理lvgl tasks}
}

  对比上面,小伙伴们是不是发现什么不同了呢,当我们触摸位置在slider有效区域内的时候,坐标值,坐标值是 已经转换为0-100内的数值了的,是不是很方便呢。

demo演示视频

见公众号~

本次的介绍就到这里啦,后面有更精彩的内容,拥有自己的GUI,欢迎大家持续关注嵌入式实验基地,来这里还可以学习HAL库+cubemx的更多精彩内容哦!

  如果你觉得对自己有帮助的话,给个赞,点个关注,点个在看,感谢前进的道路上有你的陪伴!

资料源码已上传,关注公众号回复资料即可获取哦,欢迎加群一起炸起来!

LVGL在STM32上的移植及触摸驱动移植(触摸屏控制版)相关推荐

  1. 基于rk3288平台的gt9xx 触摸驱动移植

                                              基于rk3288平台的gt9xx 触摸驱动移植 一.硬件介绍:     1 core-rk3288j 核心板     ...

  2. LVGL - 在STM32上的移植

    一.硬件平台 本次移植选用的是正点原子的APOLLO开发板,MCU为STM32F429IG,1M的内部FLASH,256K的SRAM,并且板载了一颗32M的SDRAM.7寸RGB电容屏,分辨率1024 ...

  3. 嵌入式驱动移植之触摸驱动初识

    开发环境 BootLoader:u-boot-1.1.6 kernel:linux-2.6.30.4 CPU:s3c2440 开发板:TQ2440 参考资料:<天嵌科技Linux移植手册> ...

  4. Y410P用虚拟机装Linux系统,OK6410、Linux2.6.36内核移植,DM9000 驱动移植

    对照这个结构体  将那些进行修改,注意  by  acanoe   的语句为修改重点. // add by acanoe 2 &s3c_device_nand,//这一语句为添加nand  设 ...

  5. Wireless工具移植之RTL8188eus驱动移植

    RTL8188eus驱动版本: RTL8188EUS_linux_v4.3.0.3_10997.20140327.zip,该驱动源码包支持rtl8188eus和rtl8188etv的芯片. 一.交叉编 ...

  6. vb.net程序可以在触摸屏上运行么_【干货】触摸屏控制变频器的方法与步骤

    一.触摸屏通过PLC控制变频器 1.目前一般情况的控制变频器,都需要采用PLC与变频器通讯,读取变频器的信息,然后触摸屏再与PLC通讯,才能完成控制变频器启动.停止,以及监视变频器的运行频率.电流.电 ...

  7. linux在开发板LCD上显,W35型LCD驱动移植 - linux-2.6.32在mini2440开发板上移植_Linux编程_Linux公社-Linux系统门户网站...

    编者注:本移植主要步骤还是按照手册来,里面讲解了一些有用的基础知识.但书册上提供了集中屏幕的方案,我们这里主要就用一种,也就是开发板自带的W35型号.液晶驱动的源程序在src/drivers/vide ...

  8. 基于Linux系统mjpg_streamer流媒体移植(摄像头驱动移植)

    一.mjpg-streamer移植 主机环境 :ubuntu 14.04 编译器:arm-none-linux-gnueabi-gcc 开发板:A9 移植系统:Linux3.14 摄像头:USB摄像头 ...

  9. HLK-W801-LVGL8之触摸驱动

    HLK-W801-LVGL8之触摸驱动 前言 触摸驱动实现 驱动芯片SPI接口 XPT2046驱动接口 显示截图 前言 本篇完成最后一部的触摸驱动移植 前面两部分: 第一部分:HLK-W801-LVG ...

最新文章

  1. 数据库将某个字段由可为空改为非空
  2. oracle11g安装补丁升级
  3. linux服务器文件后缀名,linux服务器备份网站程序并下载到本地(自动)
  4. Python基础知识(第四天)
  5. Web安全通讯之JWT的Java实现
  6. 桥接模式(Bridge) 1
  7. 疑似小米11 Pro保护壳曝光:横向矩阵相机设计
  8. android简单课表,模仿大神的一个android课程表
  9. Using Delegates with Data Readers to Control DAL Responsibility[转]
  10. 微观经济学 读书笔记
  11. Tableau 南丁格尔玫瑰图
  12. 云计算学习笔记——VLAN与三层交换机
  13. 使用N2N软件远程管理DLAP221设备
  14. python print什么意思_python中print有什么用
  15. 虚拟机重启服务器命令,虚拟机中重启命令
  16. java计算机毕业设计黑格伯爵国际英语贵族学校官网源码+mysql数据库+系统+lw文档+部署
  17. Jetson Orin平台4-16路 GMSL2/GSML1相机采集套件推荐
  18. 常用音频软件大比拼,再也不为选择哪一款犯愁了!
  19. 如何使用Selenium自动化测试工具获取动态图片验证码?
  20. 个性化推荐的工业级实现

热门文章

  1. XML语言数据读写理解10
  2. 【TIPS】MAC OS 自定义打开应用的快捷键
  3. 【BUG:unable to connect redis 6379】
  4. 拆装计算机主机,怎样快速拆卸电脑主机
  5. MybatisPlus 之 插件
  6. 【无人机】关于无人机从事物流配送业务审定的思考
  7. 用python快速发微博
  8. matlab常用随机函数randperm
  9. linux 端口访问限制,linux 端口限制ip访问
  10. 李宏毅机器学习笔记(十六)——无监督学习(四):自编码器