IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> lvgl移植到 stm32 (stm32H743IIT6) -> 正文阅读

[嵌入式]lvgl移植到 stm32 (stm32H743IIT6)

1.简介

LVGL(轻巧而多功能的图形库)是一个免费的开放源代码图形库,它提供创建具有易于使用的图形元素,精美的视觉效果和低内存占用的嵌入式GUI所需的一切。

2.移植准备

硬件准备

我使用的是正点原子的stm32H743IIt6核心板+7寸 ALENTEK 7’’ RGB TFTLCDC触摸屏。(其他屏幕也可以,但是必须包含lcd与touch驱动函数)

lvgl源码

我使用的是lvgl 7.10.1

源码
demos

3.移植过程

1.准备一个lcd触摸屏的例程
工程文件
2.在工程目录下新建一个GUI文件夹,GUI文件夹下包含两个子文件夹

GUI
lvgl_app
lvgl

3.移植lvgl
打开下载的lvgl-8.0.1
下载的
把刚才下载的lvgl-8.0.1里所有内容复制在lvgl文件夹下,lvgl_app文件夹暂时留空。
4.porting文件更名操作
我们把刚才复制后的GUI\lvgl\examples\porting下的文件进行一个改名
(1)原始
在这里插入图片描述
(2)更改名字之后
在这里插入图片描述
5.把GUI\lvgl\下的lv_conf_template.h文件复制到GUI文件夹下并更名为lv_conf.h:在这里插入图片描述
5.keil
(1)新建Group
在这里插入图片描述
(1)lvgl_app暂时空着
(2)将显示函数与触摸函数导入lvgl_porting中

在这里插入图片描述

(3)将lvgl源码中所有的.c文件全部导入lvgl_src
在这里插入图片描述
并且导入这些.c的路径
在这里插入图片描述
6.修改堆栈大小
在这里插入图片描述

7.设计c99模式
在这里插入图片描述
8.使能l条件编译
要使能lv_conf.h,lv_port_indev.c。lv_port_indev.h,lv_port_disp.c,lv_port_disp.h的条件编译,如下
在这里插入图片描述
下面部分注释掉,只留一个即可,否则会报错
在这里插入图片描述

即可编译通过
在这里插入图片描述

4.连接底层

显示移植
与touch.h相关

这个连接的画点函数,比较慢
// An highlighted block
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: */
            /* put_px(x, y, *color_p)*/
					  GUI_DrawPoint(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);
}

下面展示一些 内联代码片

直接调用颜色块会很快
// An highlighted block
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:*/
//            /*put_px(x, y, *color_p)*/
//				    LCD_Fast_DrawPoint(x,y,color_p->full);
//            color_p++;
//        }
//    }

//    /*IMPORTANT!!!
//     *Inform the graphics library that you are ready with the flushing*/
//    
				
					LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);
	//最后必须得调用,通知lvgl库你已经flushing拷贝完成了
	        lv_disp_flush_ready(disp_drv);
}

两者选一个就可以
触摸移植
下面展示一些 内联代码片

// An highlighted block
/*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;

       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;
    }
}

有外部sdram时
可以这样定义
下面展示一些 内联代码片

// An highlighted block
*********************/ 
#define LTDC_LCD_FRAMEBUF_SIZE		(1280*800*2)		//ltdc.c中ltdc_lcd_framebuf缓冲区的大小
#define COLOR_BUF_SIZE		(1024*10)	//全屏的大小

static lv_color_t color_buf[COLOR_BUF_SIZE]	__attribute__((at(LCD_FRAME_BUF_ADDR+LTDC_LCD_FRAMEBUF_SIZE+COLOR_BUF_SIZE*2))); //分配到外部SDRAM,需要跳过ltdc.c中分配的帧缓冲区
static lv_color_t color_buf2[COLOR_BUF_SIZE]	__attribute__((at(LCD_FRAME_BUF_ADDR+LTDC_LCD_FRAMEBUF_SIZE+COLOR_BUF_SIZE*4)));//lvgl的第二个缓冲区,紧跟在第一个缓冲区的后面

5.屏幕配置

挺重要的,有时候搞完一直出不来,可能就是屏幕横屏竖屏没弄好
下面展示一些 内联代码片

这里面屏幕的配置和你的lcd里横竖屏应该一致
// An highlighted block

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) */
                     /*A buffer for 10 rows*/
    lv_disp_draw_buf_init(&draw_buf_dsc_1, color_buf, color_buf2, 1024 * 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_1[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_1, 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_1[MY_DISP_HOR_RES * MY_DISP_VER_RES];            /*An other 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 = 1024;
    disp_drv.ver_res = 600;

    /*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_1;

    /*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);
}
LCD_Display_Dir(1);	lcd里这个函数配置横竖屏

在 lv_conf.h里进行一些配置
色彩深度: #define LV_COLOR_DEPTH 16
DPI: #define LV_DPI 100
提供给lvgl的空间: #define LV_MEM_SIZE (32U * 1024U)

6.给lvgl一个心跳

下面展示一些 内联代码片

	TIM7_Init(10-1,20000-1);  1ms的心跳
// An highlighted block

void TIM7_Init(u16 arr,u16 psc)
{  
    TIM7_Handler.Instance=TIM7;                          //通用定时器3
    TIM7_Handler.Init.Prescaler=psc;                     //分频
    TIM7_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;    //向上计数器
    TIM7_Handler.Init.Period=arr;                        //自动装载值
    TIM7_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
    HAL_TIM_Base_Init(&TIM7_Handler);
    
    HAL_TIM_Base_Start_IT(&TIM7_Handler); //使能定时器3和定时器3更新中断:TIM_IT_UPDATE    
}

//定时器底册驱动,开启时钟,设置中断优先级
//此函数会被HAL_TIM_Base_Init()函数调用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
  
	 if(htim->Instance==TIM7)
	{
		__HAL_RCC_TIM7_CLK_ENABLE();            //使能TIM3时钟
		HAL_NVIC_SetPriority(TIM7_IRQn,1,3);    //设置中断优先级,抢占优先级1,子优先级3
		HAL_NVIC_EnableIRQ(TIM7_IRQn);          //开启ITM3中断   
	}  
}

//定时器3中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
   
		if(htim==(&TIM7_Handler))
    {
			   lv_tick_inc(1);
    }
}


在主函数while循环里写入 lv_task_handler();

7. 移植demos

1.复制lv_examples-7.10.1整个文件夹至GUI\lvgl_app文件夹下并更名为lv_examples:
2.把GUI\lvgl_app\lv_examples下的lv_demo_conf_template.h复制到GUI文件夹下并更名为lv_demo_conf.h
在这里插入图片描述
使用哪个就在哪个地方打开预编译
在lv_demo_conf.h中
下面展示一些 内联代码片

// An highlighted block
/*Show some widget*/
#define LV_USE_DEMO_WIDGETS        0
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW  0
#endif

/*Printer demo, optimized for 800x480*/
#define LV_USE_DEMO_PRINTER     0

/*Demonstrate the usage of encoder and keyboard*/
#define LV_USE_DEMO_KEYPAD_AND_ENCODER     1

/*Benchmark your system*/
#define LV_USE_DEMO_BENCHMARK   0

/*Stress test for LVGL*/
#define LV_USE_DEMO_STRESS      0

我用的是//lv_demo_keypad_encoder();的demo
将lv_demo_keypad_encoder文件夹的c文件添加进lvgl_app

在这里插入图片描述
我的主函数
下面展示一些 内联代码片

// An highlighted block
int main(void)
{
	HAL_Init();				        		//初始化HAL库
	Stm32_Clock_Init(160,5,2,4);  		    //设置时钟,400Mhz 
	delay_init(400);						//延时初始化
	uart_init(115200);						//串口初始化
	usmart_dev.init(200); 		    		//初始化USMART	
	TIM3_Init(10-1,20000-1);
	LED_Init();								//初始化LED
	KEY_Init();								//初始化按键
	SDRAM_Init();                   		//初始化SDRAM
	LCD_Init();								//初始化LCD
	//	TP_Init();
	  lv_init();
		lv_port_disp_init();
		lv_port_indev_init();
	  tp_dev.init();				    		//触摸屏初始化 
//  	POINT_COLOR=RED;
//	LCD_ShowString(30,50,200,16,16,"Apollo STM32H7"); 
//	LCD_ShowString(30,70,200,16,16,"TOUCH TEST");	
//	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
//	LCD_ShowString(30,110,200,16,16,"2017/8/14");	 		
//   	if(tp_dev.touchtype!=0XFF)LCD_ShowString(30,130,200,16,16,"Press KEY0 to Adjust");//电阻屏才显示
//	delay_ms(1500);
//	Load_Drow_Dialog();	 	
//	if(tp_dev.touchtype&0X80)ctp_test();//电容屏测试
//	else rtp_test(); 					//电阻屏测试  		 
//	
//  lv_demo_widgets();
// lv_demo_stress();
//  lv_demo_benchmark();
lv_demo_keypad_encoder();
//   lv_demo_test();
    while(1){
		   lv_task_handler();
	}
	
}

移植成功
在这里插入图片描述

第一次写博客好开心哦__,嘻嘻

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-30 12:12:35  更:2021-08-30 12:13:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:58:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码