esp32 arduino 移植lvgl,oled显示,lvgl屏幕建立,屏幕切换,图片显示,手动发送事件,触发部件响应其对应的回调函数,label,bar,line,style简单使用,显示字体修改
作者:互联网
屏幕采用的是128*64的分辨率的OLED,驱动ic应该是SSD1306,这个刚好支持129*64的,但是就是单色屏,用的是IIC接口
1,OLED设置:
管脚配置如下:
SSD1306Wire display(0x3c, 4, 15);//实例化OLED显示,设置管脚,该方法输入参数:uint8_t _address, uint8_t _sda, uint8_t _scl
由于我的OLED的库没有清除像素点的函数,而在lvgl的显示驱动函数中,需要设置一下,基于OLED显示的lvgl移植的关键点之一就是将LVGL的显示接口与
OLED的显示接口对应,在显示驱动函数中实现。所以我在源库文件(OLEDDisplay.cpp)里添加了像素点清除函数如下所示:当然在OLEDDisplay.h声明也少不了,就不贴代码啦。
void OLEDDisplay::clearPixel(int16_t x, int16_t y) { if (x >= 0 && x < 128 && y >= 0 && y < 64) { switch (color) { case WHITE: buffer[x + (y / 8) * DISPLAY_WIDTH] &= ~(1 << (y & 7)); break; case BLACK: buffer[x + (y / 8) * DISPLAY_WIDTH] |= (1 << (y & 7)); break; case INVERSE: buffer[x + (y / 8) * DISPLAY_WIDTH] ^= (1 << (y & 7)); break; } } }
2,lvgl移植
首先贴上官方基于arduino的LVGL库中的说明文档。
<h1 align="center"> LVGL - Light and Versatile Graphics Library</h1> <p align="center"> <a href="https://github.com/lvgl/lvgl/blob/master/LICENCE.txt"><img src="https://img.shields.io/badge/licence-MIT-blue.svg"></a> <a href="https://github.com/lvgl/lvgl/releases/tag/v7.0.0"><img src="https://img.shields.io/badge/version-7.0.0-blue.svg"></a> </p> <p align="center"> <img src="https://lvgl.io/assets/images/img_1.png"> </p> <p align="center"> LVGL provides everything you need to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. </p> <h4 align="center"> <a href="https://lvgl.io">Website </a> · <a href="https://lvgl.io/demos">Live demo</a> · <a href="https://docs.lvgl.io/">Docs</a> · <a href="https://forum.lvgl.io">Forum</a> · <a href="https://blog.lvgl.io/">Blog</a> </h4> --- - [Features](#features) - [Supported devices](#supported-devices) - [Quick start in a simulator](#quick-start-in-a-simulator) - [Add LVGL to your project](#add-lvgl-to-your-project) - [Learn the basics](#learn-the-basics) - [Examples](#examples) - [Release policy](#release-policy) - [Contributing](#contributing) ## Features * **Powerful building blocks** buttons, charts, lists, sliders, images, etc. * **Advanced graphics** with animations, anti-aliasing, opacity, smooth scrolling * **Simultaneously use various input devices** touchscreen, mouse, keyboard, encoder, buttons, etc. * **Simultaneously use multiple displays** i.e. monochrome and color display * **Multi-language support** with UTF-8 encoding, Bidirectional support, and Arabic text handling * **Fully customizable** graphical elements * **Hardware independent** to use with any microcontroller or display * **Scalable** to operate with little memory (64 kB Flash, 10 kB RAM) * **OS, External memory and GPU** supported but not required * **Single frame buffer** operation even with advances graphical effects * **Written in C** for maximal compatibility (C++ compatible) * **Micropython Binding** exposes [LVGL API in Micropython](https://blog.lvgl.io/2019-02-20/micropython-bindings) * **Simulator** to develop on PC without embedded hardware * **Tutorials, examples, themes** for rapid development * **Documentation** and API references ## Supported devices Basically, every modern controller (which is able to drive a display) is suitable to run LVGL. The minimal requirements are: - 16, 32 or 64 bit microcontroller or processor - > 16 MHz clock speed is recommended - Flash/ROM: > 64 kB for the very essential components (> 180 kB is recommended) - RAM: - Static RAM usage: ~2 kB depending on the used features and objects types - Stack: > 2kB (> 8 kB is recommended) - Dynamic data (heap): > 2 KB (> 16 kB is recommended if using several objects). Set by `LV_MEM_SIZE` in *lv_conf.h*. - Display buffer: > *"Horizontal resolution"* pixels (> 10 × *"Horizontal resolution"* is recommended) - C99 or newer compiler *Note that the memory usage might vary depending on the architecture, compiler and build options.* Just to mention some **platforms**: - STM32F1, STM32F3, [STM32F4](https://blog.lvgl.io/2017-07-15/stm32f429_disco_port), [STM32F7](https://github.com/lvgl/lv_port_stm32f746_disco_sw4stm32) - Microchip dsPIC33, PIC24, PIC32MX, PIC32MZ - NXP Kinetis, LPC, iMX - [Linux frame buffer](https://blog.lvgl.io/2018-01-03/linux_fb) (/dev/fb) - [Raspberry PI](http://www.vk3erw.com/index.php/16-software/63-raspberry-pi-official-7-touchscreen-and-littlevgl) - [Espressif ESP32](https://github.com/lvgl/lv_port_esp32) - Nordic nrf52 - Quectell M66 ## Quick start in a simulator The easiest way to get started with LVGL is to run it in a simulator on your PC without any embedded hardware. Choose a project with your favourite IDE: | Eclipse | CodeBlocks | Visual Studio | PlatformIO | Qt Creator | |-------------|-------------|---------------|-----------|------------| | [![Eclipse](https://raw.githubusercontent.com/lvgl/docs/master/v7/misc//eclipse.jpg)](https://github.com/lvgl/lv_sim_eclipse_sdl) | [![CodeBlocks](https://raw.githubusercontent.com/lvgl/docs/master/v7/misc//codeblocks.jpg)](https://github.com/lvgl/lv_sim_codeblocks_win) | [![VisualStudio](https://raw.githubusercontent.com/lvgl/docs/master/v7/misc//visualstudio.jpg)](https://github.com/lvgl/lv_sim_visual_studio_sdl) | [![PlatformIO](https://raw.githubusercontent.com/lvgl/docs/master/v7/misc//platformio.jpg)](https://github.com/lvgl/lv_platformio) | [![QtCreator](https://raw.githubusercontent.com/lvgl/docs/master/v7/misc//qtcreator.jpg)](https://blog.lvgl.io/2019-01-03/qt-creator) | | Cross-platform<br>with SDL<br>(Recommended on<br>Linux and Mac) | Native Windows | Windows<br>with SDL | Cross-platform<br>with SDL | Cross-platform<br>with SDL | ## Add LVGL to your project The steps below show how to setup LVGL on an embedded system with a display and a touchpad. You can use the [Simulators](https://docs.lvgl.io/v7/en/html/get-started/pc-simulator) to get ready to use projects which can be run on your PC. 1. [Download](https://github.com/lvgl/lvgl/archive/master.zip) or [Clone](https://github.com/lvgl/lvgl) the library 2. Copy the `lvgl` folder into your project 3. Copy `lvgl/lv_conf_template.h` as `lv_conf.h` next to the `lvgl` folder, change the `#if 0` statement near the top of the file to `#if 1` and set at least `LV_HOR_RES_MAX`, `LV_VER_RES_MAX` and `LV_COLOR_DEPTH`. 4. Include `lvgl/lvgl.h` where you need to use LVGL related functions. 5. Call `lv_tick_inc(x)` every `x` milliseconds (should be 1..10) in a Timer or Task. It is required for the internal timing of LVGL. 6. Call `lv_init()` 7. Create a display buffer for LVGL ```c static lv_disp_buf_t disp_buf; static lv_color_t buf[LV_HOR_RES_MAX * 10]; /*Declare a buffer for 10 lines*/ lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10); /*Initialize the display buffer*/ ``` 8. Implement and register a function which can copy a pixel array to an area of your display: ```c lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/ disp_drv.buffer = &disp_buf; /*Assign the buffer to the display*/ lv_disp_drv_register(&disp_drv); /*Finally register the driver*/ void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p) { int32_t x, y; for(y = area->y1; y <= area->y2; y++) { for(x = area->x1; x <= area->x2; x++) { my_set_pixel(x, y, *color_p); /* Put a pixel to the display.*/ color_p++; } } lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/ } ``` 9. Implement and register a function which can read an input device. E.g. for a touch pad: ```c lv_indev_drv_init(&indev_drv); /*Descriptor of a input device driver*/ indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/ indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/ lv_indev_drv_register(&indev_drv); /*Finally register the driver*/ bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) { data->state = my_touchpad_is_pressed() ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; if(data->state == LV_INDEV_STATE_PR) touchpad_get_xy(&data->point.x, &data->point.y); return false; /*Return `false` because we are not buffering and no more data to read*/ } ``` 10. Call `lv_task_handler()` periodically every few milliseconds in the main `while(1)` loop, in Timer interrupt or in an Operation system task. It will redraw the screen if required, handle input devices etc. For more detailed desription visit the [Porting](https://docs.lvgl.io/v7/en/html/porting/index.html) section of the documentation. ## Learn the basics In this section you can read the very basics of LVGL. For a more detailed guide check the [Quick overview](https://docs.lvgl.io/v7/en/html/get-started/quick-overview.html#learn-the-basics) in the documentation. ### Widgets (Objects) The graphical elements like Buttons, Labels, Sliders, Charts etc are called objects or widgets in LVGL. Go to [Widgets](https://docs.lvgl.io/v7/en/html/widgets/index) to see the full list of available types. Every object has a parent object. The child object moves with the parent and if you delete the parent the children will be deleted too. Children can be visible only on their parent. The *screen* are the "root" parents. To get the current screen call `lv_scr_act()`. You can create a new object with `lv_<type>_create(parent, obj_to_copy)`. It will return an `lv_obj_t *` variable which should be used as a reference to the object to set its parameters later. The first parameter is the desired *parent*, the second parameters can be an object to copy (`NULL` if unused). For example: ```c lv_obj_t * slider1 = lv_slider_create(lv_scr_act(), NULL); ``` To set some basic attribute `lv_obj_set_<paramters_name>(obj, <value>)` function can be used. For example: ```c lv_obj_set_x(btn1, 30); lv_obj_set_y(btn1, 10); lv_obj_set_size(btn1, 200, 50); ``` The objects have type specific parameters too which can be set by `lv_<type>_set_<paramters_name>(obj, <value>)` functions. For example: ```c lv_slider_set_value(slider1, 70, LV_ANIM_ON); ``` To see the full API visit the documentation of the object types or the related header file (e.g. `lvgl/src/lv_objx/lv_slider.h`). To create a new screen pass `NULL` as the fisrt paramater of a *create* function: ```c lv_obj_t * scr2 = lv_obj_create(NULL, NULL); /*Create a screen*/ lv_scr_load(scr2); /*Load the new screen*/ ``` ### Styles Widgets are created with a default appearance but it can be changed by adding new styles to them. A new style can be created like this: ```c static lv_style_t style1; /*Should be static, global or dynamically allocated*/ lv_style_init(&style1); lv_style_set_bg_color(&style1, LV_STATE_DEFAULT, LV_COLOR_RED); /*Default background color*/ lv_style_set_bg_color(&style1, LV_STATE_PRESSED, LV_COLOR_BLUE); /*Pressed background color*/ ``` The wigedt have *parts* which can be referenced via `LV_<TYPE>_PART_<PART_NAME>`. E.g. `LV_BTN_PART_MAIN` or `LV_SLIDER_PART_KNOB`. See the documentation of the widgets to see the exisitng parts. To add the style to a button: ```c lv_obj_add_style(btn1, LV_BTN_PART_MAIN, &style1); ``` To remove all styles from a part of an object: ```cc lv_obj_reset_style_list(obj, LV_OBJ_PART_MAIN); ``` Learn more in [Style overview](https://docs.lvgl.io/v7/en/html/overview/style) section. ### Events Events are used to inform the user if something has happened with an object. You can assign a callback to an object which will be called if the object is clicked, released, dragged, being deleted etc. It should look like this: ```c lv_obj_set_event_cb(btn, btn_event_cb); /*Assign a callback to the button*/ ... void btn_event_cb(lv_obj_t * btn, lv_event_t event) { if(event == LV_EVENT_CLICKED) { printf("Clicked\n"); } } ``` Learn more about the events in the [Event overview](https://docs.lvgl.io/v7/en/html/overview/event) section. ## Examples ### Button with label ```c lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); /*Add a button the current screen*/ lv_obj_set_pos(btn, 10, 10); /*Set its position*/ lv_obj_set_size(btn, 100, 50); /*Set its size*/ lv_obj_set_event_cb(btn, btn_event_cb); /*Assign a callback to the button*/ lv_obj_t * label = lv_label_create(btn, NULL); /*Add a label to the button*/ lv_label_set_text(label, "Button"); /*Set the labels text*/ ... void btn_event_cb(lv_obj_t * btn, lv_event_t event) { if(event == LV_EVENT_CLICKED) { printf("Clicked\n"); } } ``` ![LVGL button with label example](https://docs.lvgl.io/v7/en/misc/simple_button_example.gif) ### Use LVGL from Micropython Learn more about [Micropython](https://docs.lvgl.io/en/html/get-started/micropython). ```python # Create a Button and a Label scr = lv.obj() btn = lv.btn(scr) btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0) label = lv.label(btn) label.set_text("Button") # Load the screen lv.scr_load(scr) ``` ## Release policy LVGL follows the rules of [Semantic versioning](https://semver.org/): - Major versions for incompatible API changes. E.g. v5.0.0, v6.0.0 - Minor version for new but backward-compatible functionalities. E.g. v6.1.0, v6.2.0 - Patch version for backward-compatible bug fixes. E.g. v6.1.1, v6.1.2 Branches: - `master` most recent version, patches are merged directly here. - `dev` merge new features here until they are merged into `master`. - `release/vX` there is a branch for every major version to allow adding specific, not forward compatible fixes. LVGL has a monthly periodic release cycle. - **1st Tuesday of the month** - Make a major, minor, or patch release from `master` depending on the new features. - After that merge only patches into `master` and add new features into the `dev`. - **3rd Tuesday of the month** - Make a patch release from `master`. - After that merge the new features from the `dev` to `master` branch. - In the rest of the month merge only patches into `master` and new features into `dev` branch. ## Contributing To ask questions please use the [Forum](https://forum.lvgl.io). For development-related things (bug reports, feature suggestions) use [GitHub's Issue tracker](https://github.com/lvgl/lvgl/issues). If you are interested in contributing to LVGL you can - **Help others** in the [Forum](https://forum.lvgl.io). - **Inspire people** by speaking about your project in [My project](https://forum.lvgl.io/c/my-projects) category in the Forum. - **Improve and/or translate the documentation.** Go to the [Documentation](https://github.com/lvgl/docs) repository to learn more - **Write a blog post** about your experiences. See how to do it in the [Blog](https://github.com/lvgl/blog) repository - **Report and/or fix bugs** in [GitHub's issue tracker](https://github.com/lvgl/lvgl/issues) - **Help in the developement**. Check the [Open issues](https://github.com/lvgl/lvgl/issues) especially the ones with [Help wanted](https://github.com/lvgl/lvgl/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) label and tell your ideas about a topic or implement a feature. Before sending Pull requests, please read the following guides: - [Contributing guide](https://github.com/lvgl/lvgl/blob/master/docs/CONTRIBUTING.md) - [Coding style guide](https://github.com/lvgl/lvgl/blob/master/docs/CODING_STYLE.md)
在## Add LVGL to your project栏详细介绍了移植过程,部分过程解读:
步骤3:配置lv_conf.h文件说明
LV_HOR_RES_MAX 和 LV_HOR_RES_MAX 宏的值,这个是告诉 littleVGL 你所用的液晶屏分辨率是多少,请根据自己手头液晶屏的实际分辨率大小相应设置
LV_COLOR_DEPTH 颜色深度,最常见的设置就是 1 或者 16 了,1 是用于单色屏,而 16 是用于彩色屏,这里我设置成1,因为我用的OLED是单色屏
LV_DPI 的值,默认值为 130(我的库默认是这个),把他设置到100,这个宏是用来调节界面缩放比例的,此值越大,控件分布的就越散,控件自身的间隔也会变大
LV_MEM_SIZE 的大小,这个就是控制 littleVGL 中所谓的动态数据堆的大小,是用来给控件的创建动态分配空间的,我这里设置为 32KB 的大小
当要使能某种字体时,找到对应的字体定义,设置为1,例如:#define LV_FONT_MONTSERRAT_12 1
LV_USE_FILESYSTEM 的值,其默认值为 1,使能文件系统的功能
,(might be required for images )
接着可以设置 LV_THEME_LIVE_UPDATE, LV_USE_THEME_TEMPL,LV_USE_THEME_DEFAULT,LV_USE_THEME_ALIEN, LV_USE_THEME_NIGHT, LV_USE_THEME_MONO,
LV_USE_THEME_MATERIAL, LV_USE_THEME_ZEN, LV_USE_THEME_NEMO 等宏的值为 1,即使能,这些宏都是跟 littleVGL自带的主题相关的,1表示使能对应主题,
注意,在实际项目中,我们一般最多使能一个,如果我们项目根本就用不到其自带的主题,那么我们应该把这些宏全部禁止,因为这样可以节省 flash 和 ram
步骤5:littleVGL 提供心跳节拍 的函数:lv_tick_inc参考lv_conf.h的这段代码
/* 1: use a custom tick source. * It removes the need to manually update the tick with `lv_tick_inc`) */ #define LV_TICK_CUSTOM 1 #if LV_TICK_CUSTOM == 1 #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ #endif /*LV_TICK_CUSTOM*/
所以,其实在esp32 arduino中,不需要调用这个函数,但是在比如stm32等看别人是用定时器定时调用的。
步骤8:配置显示,这里是移植的关键点,就是对应lvgl与OLED的接口,代码参考如下,显示驱动函数,在这里可知道上面定义的OLED像素点清除函数的作用了:
/* Display flushing 1.把指定区域的显示缓冲区内容写入到屏幕上,你可以使用DMA或者其他的硬件加速器在后台去完成这个操作 2.但是在完成之后,你必须得调用lv_disp_flush_ready() 3.移植lvgl到对应屏幕上,需要对应lvgl的接口与显示的接口,在这里设置 4.littleVGL 支持 4 种颜色深度,格式分为为 1 byte per pixel, RGB233, RGB565, ARGB8888,其对应的配置项值分别为 1, 8, 16, 32,在一般的实际项目中,最常用的为 1 和 16,当然如果你 的处理器性能和资源都很高的话,那么你可以选择 32,占用 4 个字节,他会给你的项目带来更逼真的颜色效果,保证不失真,如果你选择的是 1,那么它只支持 2 种颜色,占用 1 个字节,在液晶 屏上的表现就是显示与不显示的关系,常用于单色屏,比如 lcd12864,oled 等,当你选择的是 16时,那么他支持 65536 种颜色,占用 2 个字节,显示效果还是很不错的,同时对处理器的要求也不 是很高,因此 16 成为了我们实际项目中最常用的设置值.Display flushing函数中lv_color_t* color_p变量传递回来的就是显示区第要显示的点的颜色值地址 */ void my_disp_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { /*获取显示区的宽度与高度*/ uint32_t w = (area->x2 - area->x1 + 1); uint32_t h = (area->y2 - area->y1 + 1); /*刷新显示区每个点的像素值*/ for (uint16_t y = area->y1; y <= area->y2; y++){ for (uint16_t x = area->x1; x <= area->x2; x++){ if(color_p->full != 0)display.setPixel(x, y);//由于我是用的OLED只有黑白,所以配置的2种颜色,当颜色值为1时设置该像素点 else display.clearPixel(x, y);//由于我是用的OLED只有黑白,所以配置的2种颜色,当颜色值为0时设置清除像素点 color_p++; } } display.display();//刷新OLED显示 lv_disp_flush_ready(disp);/* Indicate you are ready with the flushing 最后必须得调用,通知 lvgl 库你已经 flushing 拷贝完成了*/ }
步骤9:由于我还没有外部输入,所以这里就没有配置
3,我的程序说明
cpu:dsp32,IDE:arduino
程序功能
1,esp32串口调用
2,OLED显示
3,esp32管脚输入输出使用
4,lvgl窗口建立,在OLED显示
lvgl使用功能:
建立了三个屏幕,按键控制屏幕切换
在屏幕上添加控件:label,bar,line,img等
label,bar,line,style简单使用,显示字体修改
手动发送事件,触发部件响应其对应的回调函数
.c文件存储图片数据,窗口显示,lvgl官方的在线图片转.c文件工具链接:https://lvgl.io/tools/imageconverter
ps:我的程序源码如下,注释都挺清楚的,LVGL的学习可以参考正点原子手把手教你学littleVGL【轻量级开源GUI】,正点原子资料下载网站:http://www.openedv.com/docs/index.html
主程序:
#include <lvgl.h> #include "SSD1306Wire.h" // alias for `#include "SSD1306Wire.h"` #include "caiya_gui.h" SSD1306Wire display(0x3c, 4, 15);//实例化OLED显示,设置管脚,该方法输入参数:uint8_t _address, uint8_t _sda, uint8_t _scl /*Create a display buffer for LVGL*/ static lv_disp_buf_t disp_buf; static lv_color_t buf[LV_HOR_RES_MAX * 10];/*Declare a buffer for 10 lines*/ USER_DATA user_data = {{"xixi"},0};//初始化一下用于回调函数传输数据的结构体 /* Display flushing 1.把指定区域的显示缓冲区内容写入到屏幕上,你可以使用DMA或者其他的硬件加速器在后台去完成这个操作 2.但是在完成之后,你必须得调用lv_disp_flush_ready() 3.移植lvgl到对应屏幕上,需要对应lvgl的接口与显示的接口,在这里设置 4.littleVGL 支持 4 种颜色深度,格式分为为 1 byte per pixel, RGB233, RGB565, ARGB8888,其对应的配置项值分别为 1, 8, 16, 32,在一般的实际项目中,最常用的为 1 和 16,当然如果你 的处理器性能和资源都很高的话,那么你可以选择 32,占用 4 个字节,他会给你的项目带来更逼真的颜色效果,保证不失真,如果你选择的是 1,那么它只支持 2 种颜色,占用 1 个字节,在液晶 屏上的表现就是显示与不显示的关系,常用于单色屏,比如 lcd12864,oled 等,当你选择的是 16时,那么他支持 65536 种颜色,占用 2 个字节,显示效果还是很不错的,同时对处理器的要求也不 是很高,因此 16 成为了我们实际项目中最常用的设置值.Display flushing函数中lv_color_t* color_p变量传递回来的就是显示区第要显示的点的颜色值地址 */ void my_disp_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) { /*获取显示区的宽度与高度*/ uint32_t w = (area->x2 - area->x1 + 1); uint32_t h = (area->y2 - area->y1 + 1); /*刷新显示区每个点的像素值*/ for (uint16_t y = area->y1; y <= area->y2; y++){ for (uint16_t x = area->x1; x <= area->x2; x++){ if(color_p->full != 0)display.setPixel(x, y);//由于我是用的OLED只有黑白,所以配置的2种颜色,当颜色值为1时设置该像素点 else display.clearPixel(x, y);//由于我是用的OLED只有黑白,所以配置的2种颜色,当颜色值为0时设置清除像素点 color_p++; } } display.display();//刷新OLED显示 lv_disp_flush_ready(disp);/* Indicate you are ready with the flushing 最后必须得调用,通知 lvgl 库你已经 flushing 拷贝完成了*/ } //显示器接口初始化 void lv_port_disp_init(void) { lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);/*Initialize the display buffer*/ /*Implement and register a function which can copy a pixel array to an area of your display:*/ lv_disp_drv_t disp_drv;/*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv);/*Basic initialization*/ /*设置屏幕的显示大小,我这里是为了支持多个屏幕,采用动态获取的方式如果你是用于实际项目的话,可以不用设置, 那么其默认值就是 lv_conf.h 中LV_HOR_RES_MAX 和 LV_VER_RES_MAX 宏定义的值*/ disp_drv.hor_res = 128; disp_drv.ver_res = 64; disp_drv.flush_cb = my_disp_flush;/*Set your driver function*/ disp_drv.buffer = &disp_buf;/*Assign the buffer to the display*/ lv_disp_drv_register(&disp_drv);/*Finally register the driver*/ } void setup() { Serial.begin(115200); /* prepare for possible serial debug */ pinMode(2,OUTPUT);//设置管脚2位输出,连接的LED digitalWrite(2,1);//管脚2输出1 pinMode(0,INPUT_PULLUP);//管脚0位输入,连接的按键 /*想要使用 littleVGL 的任务管理系统,就必须得调用 lv_task_core_init 进行初始化一下,但是好处在于不需要我们自己去手动调用了,littleVGL 内部已经帮我们完成了初始化调用 * 在 lv_init 函数中可以看到 lv_task_core_init 函数的调用,而我们又在 main 函数中调用了lv_init 函数,所以我们完全可以不用去理会 lv_task_core_init 这个 API 接口*/ lv_init();//lvgl系统初始化 display.init();//oled驱动初始化 lv_port_disp_init();//显示器接口初始化 set_caiya_gui();//GUI初始化 lv_scr_load_anim(scr1, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 500, 5000, false); // 加载屏幕scr1,动画效果为LV_SCR_LOAD_ANIM_FADE_ON,切换时间为500ms,延迟5000ms后从第一屏开始切换,切换完成后不删除原来的屏幕 } int flag = 0; void loop() { /*periodically every few milliseconds in the main `while(1)` loop, in Timer interrupt or in an Operation system task. It will redraw the screen if required, handle input devices etc.*/ lv_task_handler(); /* let the GUI do its work */ delay(5); if(digitalRead(0)==0) { while(digitalRead(0)==0); digitalWrite(2,!digitalRead(2)); flag++; if(flag==1){ lv_scr_load_anim(scr2, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 500, 0, false); } else if(flag==2){ lv_scr_load_anim(scr1, LV_SCR_LOAD_ANIM_MOVE_RIGHT, 500, 0, false); flag=0; } //手动发送事件 //方式 1:发送用户自定义事件,同时携带用户自定义数据 user_data.age=(unsigned char)flag; Serial.println(user_data.age); /*手动发送事件进行触发,同时可以携带用户自定义的数据 函数参数:lv_obj_t * obj, lv_event_t event, const void * data*/ lv_event_send(label2,USER_EVENT_1,&user_data); } }
lvgl GUI窗口搭建的.c,.h源码:
#ifndef CAIYA_GUI_H #define CAIYA_GUI_H #ifdef __cplusplus extern "C" { //extern "C"表示编译生成的内部符号名使用C约定。这样在c++文件中也可以调用对应c函数 #endif #include "lvgl.h" /* 1.在 littleVGL 中任何对象都可以注册事件,这是在新版本中才加入的特性,分为通用事件和专用事件,总共支持 20 种事件类型,这是一个总和哈,并不是指每一个对象都具有 20 种事件 类型,事件可以是由 littleVGL 库自身触发的,也可以是由外部物理操作触发的,比如触摸,点击等等,当然了,我们也可以通过调用 lv_event_send 接口来手动发送事件进行触发,同时可以携 带用户自定义的数据. 2.这里需要注意 event 参数,系统是自带了 20 种事件类型,其对应的值是从 0 到 19,除了给event 参数传系统自带的事件外,其实我们还可以传用户自定义的事件的,范围为:[20,255]*/ #define USER_EVENT_START 20 #define USER_EVENT_1 (USER_EVENT_START+1) //用户自定义事件 1 //构建一个用户自定义数据结构体,当然了,如果你的用户数据简单,可以不用结构体 typedef struct{ char name[20]; unsigned char age; }USER_DATA; //extern lv_img_dsc_t screen_buffer; extern lv_obj_t* scr1; extern lv_obj_t* scr2; extern lv_obj_t* label2; void set_caiya_gui(void); static void btn_event_cb(lv_obj_t * obj,lv_event_t event); #ifdef __cplusplus } /* extern "C" */ #endif #endif
/********************* * INCLUDES *********************/ #include "caiya_gui.h" /*Use this macro to declare an image in a c file #define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name; 建议:声明的图片名字为图片数据文件的文件名,然后littleVGL 用lv_img_dsc_t 结构体对图片数据进行一次封装的变量名也要使用文件名*/ LV_IMG_DECLARE(myimage1); lv_obj_t* scr1; lv_obj_t* scr2; lv_obj_t* label2; static lv_point_t line_points[] = { {5, 25}, {30, 50}, {50, 30}, {80, 80}, {100, 30} }; lv_obj_t * line; void set_caiya_gui(void) { /*设置默认屏幕*/ //创建bar /*Create style*/ static lv_style_t style; lv_style_init(&style);//初始化样式 lv_style_set_border_width(&style, LV_STATE_DEFAULT, 4);//设置样式的边框宽度 lv_style_set_bg_color(&style, LV_STATE_DEFAULT, LV_COLOR_BLACK);//设置样式的背景颜色 lv_obj_t* bar = lv_bar_create(lv_scr_act(), NULL);//在默认屏上创建bar对象 lv_scr_act()表示当前屏幕 /*apply the new style*/ lv_obj_add_style(bar, LV_LABEL_PART_MAIN, &style); lv_obj_set_size(bar, 140, 20);//设置bar尺寸 lv_obj_align(bar, NULL, LV_ALIGN_CENTER, 0, 0);//校准bar在屏幕中的位置 居中 lv_bar_set_anim_time(bar, 2000);//设置bar的动画时间 lv_bar_set_value(bar, 100, LV_ANIM_ON);//设置值 //创建label static lv_style_t style1; lv_style_init(&style1); lv_style_set_border_width(&style1, LV_STATE_DEFAULT, 2); lv_style_set_text_font(&style1,LV_STATE_DEFAULT,&lv_font_montserrat_12);//设置字体大小 需要去lv_conf.H文件中设置对应字体定义为1 例如#define LV_FONT_MONTSERRAT_12 1 lv_obj_t * label = lv_label_create(lv_scr_act(), NULL); lv_obj_add_style(label, LV_LABEL_PART_MAIN, &style); /*设置label文本为长文本模式 void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode); 参数: label: 标签对象 long_mode: 长文本模式 LV_LABEL_LONG_EXPAND, 自动扩展对象的大小来包裹文本内容 保持对象的宽度不变,当文本内容的宽度超过对象的宽度时会 自动换行,然后同时自动扩展对象的高度来包裹文本内容的高度 LV_LABEL_LONG_BREAK, 保持对象的大小不变,当文本内容太长显示不下时, 会在文本末尾显示...三个点的省略号 LV_LABEL_LONG_DOT, 保持对象的大小不变,当文本内容太长显示不下时,会自动循环向前向后滚动文本 LV_LABEL_LONG_SROLL, 保持对象的大小不变,当文本内容太长显示不下时,会自动循环环形滚动文本 LV_LABEL_LONG_SROLL_CIRC, LV_LABEL_LONG_CROP, 保持对象大小不变,超过的文本内容将会被剪切掉*/ lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL); /*设置文本对齐方式 void lv_label_set_align(lv_obj_t * label, lv_label_align_t align); 参数: label: 标签对象 align: 水平方向上的文本对齐方式 LV_LABEL_ALIGN_LEFT, //文本左对齐 LV_LABEL_ALIGN_CENTER, //文本居中对齐 LV_LABEL_ALIGN_RIGHT,//文本右对齐*/ lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); lv_obj_set_pos(label, 10, 0);//设置对象位置 lv_obj_set_size(label, 108, 20); /*设置动态文本(字符串形式) void lv_label_set_text(lv_obj_t * label, const char * text); 参数: label: 标签对象 text: 新的文本内容,文本内容要是’\0’空字符结尾,如果传 NULL 的话,那么代表刷新当前文本内容*/ lv_label_set_text(label, "let us begining......"); /*设置默认屏幕 我们再来了解另外一个核心概念 Screen 屏幕对象,屏幕对象是一个特殊的对象,因为他自己没有父对象,所以它以这样的方式来创建: lv_obj_t * screen = lv_obj_create(NULL, NULL); 默认情况下,littleVGL 会为显示器创建一个 lv_obj 类型的基础对象来作为它的屏幕,即最 顶层的父类,可以通过 lv_scr_act()接口来获取当前活跃的屏幕对象*/ /*创建屏幕1*/ scr1 = lv_obj_create(NULL, NULL); // 创建新屏幕但未加载到显示 /*lv_img 就是一个图片控件,它就是根据你传入的图片源来显示你想要的图片,littleVGL 为了提供最大的灵活性,它支持如下三种图片源方式: 1) 内部 C 数组,用 lv_img_dsc_t 结构体来进行描述 2) 外部存储文件,比如 SD 卡或者 U 盘上的图片文件 3) LV_SYMBOL_XXX 形式的图标字体或者文本,此时 lv_img 图片就相当于一个 lv_label 标签控件 如果你确定好图片源之后,就可以通过 lv_img_set_src(img, src)接口来显示此图片,此接口内部会自动判断出 src 是属于哪一种图片源方式,然后选择相应的解析程序把图片给显示出来.*/ lv_obj_t* img1 = lv_img_create(scr1, NULL); lv_img_set_src(img1, &myimage1); lv_obj_set_pos(scr1, 0, 0); lv_obj_set_size(scr1, 128, 64); /*创建屏幕2*/ scr2 = lv_obj_create(NULL, NULL); // 创建新屏幕但未加载到显示 label2 = lv_label_create(scr2, NULL); // 创建label lv_label_set_long_mode(label2, LV_LABEL_LONG_SROLL); lv_label_set_align(label2, LV_LABEL_ALIGN_CENTER); lv_obj_set_pos(label2, 44, 0); lv_obj_set_size(label2, 40, 20); lv_label_set_text(label2, "TWO"); static lv_style_t style_line; lv_style_init(&style_line); lv_style_set_line_width(&style_line, LV_STATE_DEFAULT, 8); lv_style_set_line_rounded(&style_line, LV_STATE_DEFAULT, true); line = lv_line_create(scr2, NULL); lv_line_set_points(line, line_points, 5); /*Set the points*/ lv_obj_add_style(line, LV_LINE_PART_MAIN, &style_line); /*Set the points*/ lv_obj_align(line, NULL, LV_ALIGN_CENTER, 0, 0); /*事件回调函数 void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb); 参数: obj: 对象句柄 event_cb: 事件回调函数*/ lv_obj_set_event_cb(label2,btn_event_cb); } //事件回调函数 这个函数的自己写的 static void btn_event_cb(lv_obj_t * obj,lv_event_t event) { static unsigned char i=0; if(event==USER_EVENT_1) { //用户自定义事件 1 //获取用户自定义数据 USER_DATA* data = (USER_DATA*)lv_event_get_data(); if(data->age==1){ i++; if(i>10)i=0; if(i%2)lv_line_set_points(line, line_points, 3); /*Set the points*/ else lv_line_set_points(line, line_points, 5); /*Set the points*/ } if(data->age==1) lv_label_set_text_fmt(label2, "back successful!-%d", i); // lv_label_set_text_fmt()它就是pintf("%d user", user_num)实现 } }
图片数据.c源码:
//#include "E:\DC BREAKER\ESP32\Project\libraries\lvgl\src\lv_examples\lv_examples.h" #include "lvgl.h" /* #define LV_ATTRIBUTE_MEM_ALIGN说明 With size optimization (-Os) the compiler might not align data to * 4 or 8 byte boundary. This alignment will be explicitly applied where needed. * E.g. __attribute__((aligned(4))) */ #ifndef LV_ATTRIBUTE_MEM_ALIGN #define LV_ATTRIBUTE_MEM_ALIGN #endif #ifndef LV_ATTRIBUTE_IMG_2 #define LV_ATTRIBUTE_IMG_2 #endif const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_2 uint8_t my_map[] = { 0xff, 0xff, 0xff, 0xff, /*Color of index 0*/ 0x00, 0x00, 0x00, 0xff, /*Color of index 1*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x58, 0x0c, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x1a, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x81, 0x10, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x81, 0x34, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0xa5, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x48, 0xa4, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x4a, 0xfe, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x40, 0x47, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x3f, 0xff, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x7f, 0xff, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x60, 0x00, 0xff, 0xfa, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xff, 0xe0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x01, 0xfc, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x18, 0x03, 0xff, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfc, 0x07, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x07, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xff, 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdf, 0xff, 0xf4, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x7f, 0xff, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x1f, 0xff, 0xfc, 0x1f, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x3f, 0xff, 0xfe, 0x18, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xbf, 0xff, 0xfe, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0xff, 0xff, 0xfe, 0x0f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0xff, 0xff, 0xfe, 0x07, 0xf0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0xfc, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfd, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x80, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe1, 0xff, 0xf8, 0xff, 0xff, 0xbf, 0x20, 0x7f, 0xff, 0x0c, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x07, 0xcf, 0xff, 0xc0, 0x7f, 0xff, 0x0f, 0xff, 0xc7, 0xff, 0xef, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /*littleVGL 会用lv_img_dsc_t 结构体对图片数据进行一次封装*/ const lv_img_dsc_t myimage1 = { .header.cf = LV_IMG_CF_INDEXED_1BIT,//图片的转换格式 .header.always_zero = 0, .header.reserved = 0, .header.w = 128,//图片的宽度 .header.h = 64,//图片的高度 .data_size = 1033,//C 数组的大小,单位为字节 .data = my_map,//C 数组,也就是图片的核心像素数据 };
OLED显示图片:
标签:LV,显示,obj,0x00,lv,0xff,屏幕,lvgl 来源: https://www.cnblogs.com/caiya/p/15978839.html