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> &middot; 
<a href="https://lvgl.io/demos">Live demo</a> &middot; 
<a href="https://docs.lvgl.io/">Docs</a> &middot; 
<a href="https://forum.lvgl.io">Forum</a> &middot;
<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
- &gt; 16 MHz clock speed is recommended
- Flash/ROM: &gt; 64 kB for the very essential components (&gt; 180 kB is recommended)
- RAM: 
  - Static RAM usage: ~2 kB depending on the used features and objects types
  - Stack: &gt; 2kB (&gt; 8 kB is recommended)
  - Dynamic data (heap): &gt; 2 KB (&gt; 16 kB is recommended if using several objects).
    Set by `LV_MEM_SIZE` in *lv_conf.h*. 
  - Display buffer:  &gt; *"Horizontal resolution"* pixels (&gt; 10 &times; *"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:由於我還沒有外部輸入,所以這里就沒有配置

lvgl簡介:

littleVGL 可以說是這 2 年才剛開始流行的一個小型開源嵌入式 GUI ,具有界面精美,消耗資源小,可移植度高,響應式布局等特點,全庫采用純 c 語言開發,

littleVGL 的主要特性如下:
具有非常豐富的內置控件,buttons, charts, lists, sliders, images
高級圖形效果:動畫,反鋸齒,透明度,平滑滾動
支持多種輸入設備,touchpad, mouse, keyboard, encoder
支持多語言的 UTF-8 編碼
支持多個和多種顯示設備,例如同步顯示在多個彩色屏或單色屏上
完全自定制的圖形元素
硬件獨立於任何微控制器或顯示器
可以縮小到最小內存 (64 kB Flash, 16 kB RAM)
支持操作系統、外部儲存和 GPU(非必須)
僅僅單個幀緩沖設備就可以呈現高級視覺特效
使用 C 編寫以獲得最大兼容性(兼容 C++)
支持 PC 模擬器
為加速 GUI 設計,提供教程,案例和主題,支持響應式布局
提供了在線和離線文檔
基於自由和開源的 MIT 協議

littleVGL 的要求如下:
1632 64 位的單片機(微控制器)或處理器
微處理器的主頻最好高於 16MHZ
Flash/ROM:如果只用 littleVGL 核心組件的話,則至少需要 64kB 的容量,如果想完整使用的
,最好保證 180kB 以上的容量
RAM:
    o 靜態 RAM: 大約 8 16 kB,這取決於你所用的組件功能和 objects 控件對象類型
    o : 至少為 2Kb,一般推薦值為 4kB

    o 動態數據(): 至少 4kB,如果你用到了多個或多種控件的話,那么最好設置為 16kB 以上,這個是可以通過 lv_conf.h 配置文件中的 LV_MEM_SIZE 宏來定義的
    o 顯示緩沖區: 至少要比水平分辨率像素要大,一般推介值為 10 倍的水平分辨率素”,取個例子,假如我們屏幕的水平分辨率為480個像素,采用16位的顏色深度進行顯
,即一個像素占 2 個字節,那么推介的顯示緩沖區大小為 10*480*2=9600 個字節
C99 或更新的編譯器,如果是用 keil 開發的話,一定得勾選”c99”模式,否則編譯會報錯的
基本的 c(或者 c++)語言知識,:指針,結構體,回調函數

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顯示圖片:

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM