RP2350-LCD-0.85 使用教程

产品特性

  • 采用 Raspberry Pi 研发的 RP2350 微控制器芯片
  • 独特的双核、双架构,搭载了双核 ARM Cortex-M33 处理器和双核 Hazard3 RISC-V 处理器,时钟运行频率高达 150MHz,支持用户在两种架构间灵活切换
  • 内置 520KB 的 SRAM 和 16MB 的片上 Flash
  • 采用 Type-C 接口,紧跟时代潮流,无需纠结正反插
  • 板载 0.85 英寸 LCD 屏,128 × 128 分辨率,65K 彩色
  • 支持 USB1.1 主机和设备
  • 支持低功耗睡眠和休眠模式
  • 可通过 USB 识别为大容量存储器进行拖放式下载程序
  • 引出 4 个多功能 GPIO 引脚
  • 1 个 I2C,1 个 UART,2 个 12 位 ADC,以及 2 个可控 PWM 通道
  • 精确的片上时钟和定时器
  • 内置温度传感器,可实时监测芯片温度
  • 12 个可编程 I/O (PIO) 状态机,用于自定义外设支持

板载资源


  1. RP2350 双核、双架构处理器,运行频率高达 150MHz
  2. NS4150B 音频功率放大器芯片
  3. QMI8658 六轴惯性测量单元(IMU),包含 3 轴陀螺仪和 3 轴加速度计
  4. ES8311 低功耗音频编解码芯片
  5. 音量控制按键 短按音量增大,长按音量减小,支持自定义按键功能
  6. PWR 电源按键 用于电源控制
  7. BOOT 按键 复位时按下可进入下载模式
  8. 电池充放电管理芯片 用于锂电池充放电管理
  9. 麦克风 用于音频采集
  10. Micro SD 卡座 支持 Micro SD 卡扩展存储
  11. 16MB NOR-Flash 用于程序与数据存储
  12. MX1.25 锂电池接口 可用于接入 3.7V 锂电池,支持充放电,峰值充电电流 500mA
  13. USB Type-C 接口 用于程序下载,支持 USB 1.1 主机和从设备模式
  14. MX1.25 喇叭接口 用于外接扬声器

接口介绍


产品尺寸



MicroPython 开发

本章节包含以下部分,请按需阅读:

MicroPython 入门教程

初次接触 Pico MicroPython 开发,想要快速上手?我们为您准备了一套通用的入门教程。此教程旨在帮助开发者快速熟悉 Thonny IDE 并上手开发。教程内容涵盖环境搭建、项目创建、组件使用及外设编程等,帮助您迈出 MicroPython 编程的第一步。

配置开发环境

请参考 安装和配置 Thonny IDE 教程 下载安装 Thonny IDE。

示例程序

MicroPython 示例程序位于 示例程序包 的 examples\MicroPython 目录中。

示例程序基础例程说明依赖库
01_SD挂载 SD 卡-
02_IMU获取六轴传感器数据-
03_GUI液晶 GUI 显示程序-

01_SD

【程序说明】

  • 使用 SPI 与 SD 卡通讯,并将 SD 卡挂载到开发板,挂载成功后,可通过 Thonny 查看和修改 SD 卡中的内容。

【硬件连接】

  • 插入 SD 卡
  • 使用 USB 线把板子接入电脑

【代码分析】

  • sdcard.SDCard(spi, cs, baudrate):创建 SD 卡对象,并将初始化的 SPI 接口与 CS 引脚绑定到 SD 卡驱动中。
  • uos.mount(sd, '/sd'):将 SD 卡文件系统挂载到 /sd 目录下。挂载成功后,用户即可通过 /sd 路径对 SD 卡进行文件读写操作,例如创建、读取或删除文件。

【运行效果】

  • 通过 thonny 将 01_SD 文件下的所有 py 文件上传到开发板中,并复位。开发板复位后会根据 boot.py 的程序,自动将 SD 挂载到 sd 目录下。


02_IMU

【程序说明】

  • 使用 I2C 与 板载六轴传感器通讯,读取六轴传感器数据。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

  • IMU = QMI8658():创建 IMU 对象。
  • IMU.Read_XYZ():读取六轴传感器数据。

【运行效果】

  • 使用 thonny 运行 02_IMU 文件下的 py 文件。


03_GUI

【程序说明】

  • 通过 SPI 通信驱动 0.85 寸 LCD 显示屏,利用 GUI 绘图函数绘制文字、边框与彩色色块,刷新屏幕完成显示。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

  • lcd = lcd_0inch85() :创建 LCD 对象。
  • lcd.fill(BLACK):填充全屏颜色。
  • lcd.write_text("Hello",25,25,2,GREEN):在屏幕上写文字。
  • lcd.hline(7,20,110,BLUE):画水平线。
  • lcd.vline(7,20,90,BLUE):画垂直线。
  • lcd.fill_rect():画实心矩形。
  • lcd.display():刷新屏幕(真正显示出来)。

【运行效果】

  • 使用 thonny 运行 03_GUI 文件下的 py 文件。



C/C++ 开发

本章节包含以下部分,请按需阅读:

配置开发环境

请参考 安装和配置 Pico C/C++ 开发环境教程 下载安装 Pico VS Code。

示例程序

C/C++ 示例程序位于 示例程序包 的 examples\C 目录中。

示例程序基础例程说明依赖库
01_FatFsFAT 文件系统,SD 卡 支持 SPI/SDIO 通讯-
02_ES8311开发板音频测试程序-
03_GUI液晶 GUI 显示程序-
04_LVGL液晶 LVGL 显示程序LVGL V8.4
05_WS2812WS2812灯珠循环显示-

01_FatFs

【程序说明】

  • 使用 SPI 或 PIO 模拟的 SDIO 与 SD 卡通讯,实现类似于 busybox 或 DOS 的命令行界面。

【硬件连接】

  • 插入 SD 卡
  • 使用 USB 线把板子接入电脑

【代码分析】

  • sd_init_driver():初始化 SD 卡驱动。
  • getchar_timeout_us():获取串口输入。
  • process_stdio():处理串口输入。

【运行效果】

  1. 使用 putty 或者 mobaxterm 等终端工具,打开开发板对应的 USB 串行端口

  2. 按 Enter 键启动命令行界面 (CLI)。您应该会看到类似这样的提示:

    >
  3. 输入 help 指令可以得到可用指令,如下

    > help
    setrtc <DD> <MM> <YY> <hh> <mm> <ss>:
    Set Real Time Clock
    Parameters: new date (DD MM YY) new time in 24-hour format (hh mm ss)
    e.g.:setrtc 16 3 21 0 4 0

    date:
    Print current date and time

    lliot <drive#>:
    !DESTRUCTIVE! Low Level I/O Driver Test
    e.g.: lliot 1

    format [<drive#:>]:
    Creates an FAT/exFAT volume on the logical drive.
    e.g.: format 0:

    mount [<drive#:>]:
    Register the work area of the volume
    e.g.: mount 0:

    unmount <drive#:>:
    Unregister the work area of the volume

    chdrive <drive#:>:
    Changes the current directory of the logical drive.
    <path> Specifies the directory to be set as current directory.
    e.g.: chdrive 1:

    getfree [<drive#:>]:
    Print the free space on drive

    cd <path>:
    Changes the current directory of the logical drive.
    <path> Specifies the directory to be set as current directory.
    e.g.: cd 1:/dir1

    mkdir <path>:
    Make a new directory.
    <path> Specifies the name of the directory to be created.
    e.g.: mkdir /dir1

    ls:
    List directory

    cat <filename>:
    Type file contents

    simple:
    Run simple FS tests

    big_file_test <pathname> <size in bytes> <seed>:
    Writes random data to file <pathname>.
    <size in bytes> must be multiple of 512.
    e.g.: big_file_test bf 1048576 1
    or: big_file_test big3G-3 0xC0000000 3

    cdef:
    Create Disk and Example Files
    Expects card to be already formatted and mounted

    start_logger:
    Start Data Log Demo

    stop_logger:
    Stop Data Log Demo

02_ES8311

【程序说明】

  • 使用 PIO 模拟的 I2S 与 ES8311 通讯,实现音频的输入与输出。

【硬件连接】

  • 连接喇叭
  • 使用 USB 线把板子接入电脑

【代码分析】

  • Es8311_Init():初始化 ES8311。
  • Es8311_Sample_Frequency_Config():配置采样率。
  • Es8311_Microphone_Config():配置麦克风。
  • Es8311_Microphone_Gain_Set():设置麦克风增益。
  • Es8311_Voice_Volume_Set():设置音量。
  • Sine_440hz_Out():输出 440 Hz 正弦波。
  • Happy_Birthday_Out():生日快乐电子乐。
  • Loopback_Test():录音播放测试。
  • Music_Out():播放音乐。

【运行效果】

  • 使用 VS Code 导入并编译 02_ES8311 工程,编译完成后,烧录 build 目录下 uf2 尾缀文件,或直接烧录 02_ES8311\uf2 目录下 uf2 尾缀文件进行快速验证。

03_GUI

【程序说明】

  • 使用 SPI 与 液晶通讯,并通过 GUI 实现显示文本和图片等功能。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

底层硬件接口

我们对硬件操作进行了底层的封装,由于硬件平台不一样,内部的实现是不一样的,如果需要了解内部实现可以去对应的目录中查看,在 DEV_Config.c(.h) 可以看到很多定义,在目录:lib\Config

  • 模块初始化与退出的处理

    void DEV_Module_Init(void);
    void DEV_Module_Exit(void);
    提示

    这里是处理使用液晶屏前与使用完之后一些 GPIO 的处理。

  • GPIO 读写

    void DEV_Digital_Write(uint_16 Pin, uint_8 Value);
    uint_8 DEV_Digital_Read(uint_16 Pin);
  • SPI 写数据

    void DEV_SPI_WriteByte(uint_8 Value);

上层应用

对于屏幕而言,如果需要进行画图、显示中英文字符、显示图片等怎么办,这些都是上层应用做的。这有很多小伙伴有问到一些图形的处理,我们这里提供了一些基本的功能 在如下的目录中可以找到 GUI,在目录:lib\GUI\GUI_Paint.c(.h)


在如下目录下是 GUI 依赖的字符字体,在目录:lib\Fonts


  • 新建图像属性:新建一个图像属性,这个属性包括图像缓存的名称、宽度、高度、翻转角度、颜色

    void Paint_NewImage(uint16_t *image, uint16_t Width, uint16_t Height, uint16_t Rotate, uint16_t Color)
    参数:
    image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
    Width: 图像缓存的宽度;
    Height: 图像缓存的高度;
    Rotate: 图像的翻转的角度
    Color: 图像的初始颜色;
  • 选择图像缓存:选择图像缓存,选择的目的是你可以创建多个图像属性,图像缓存可以存在多个,你可以选择你所创建的每一张图像

    void Paint_SelectImage(uint8_t *image)
    参数:
    image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
  • 图像旋转:设置选择好的图像的旋转角度,最好使用在 Paint_SelectImage() 后,可以选择旋转 0、90、180、270 度

    void Paint_SetRotate(uint16_t Rotate)
    参数:
    Rotate: 图像选择角度,可以选择 ROTATE_0、ROTATE_90、ROTATE_180、ROTATE_270 分别对应 090180270
    提示

    不同选择角度下,坐标对应起始像素点不同,这里以 1.14 为例,四张图,按顺序为 0°, 90°, 180°, 270°。仅做为参考。


  • 图像镜像翻转:设置选择好的图像的镜像翻转,可以选择不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像。

    void Paint_SetMirroring(uint8_t mirror)
    参数:
    mirror: 图像的镜像方式,可以选择 MIRROR_NONE、MIRROR_HORIZONTAL、MIRROR_VERTICAL、MIRROR_ORIGIN 分别对应不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像
  • 设置点在缓存中显示位置和颜色:这里是 GUI 最核心的一个函数、处理点在缓存中显示位置和颜色。

    void Paint_SetPixel(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color)
    参数:
    Xpoint: 点在图像缓存中 X 位置
    Ypoint: 点在图像缓存中 Y 位置
    Color: 点显示的颜色
  • 图像缓存填充颜色:把图像缓存填充为某颜色,一般作为屏幕刷白的作用。

    void Paint_Clear(uint16_t Color)
    参数:
    Color: 填充的颜色
  • 图像缓存部分窗口填充颜色:把图像缓存的某部分窗口填充为某颜色,一般作为窗口刷白的作用,常用于时间的显示,刷白上一秒。

    void Paint_ClearWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color)
    参数:
    Xstart: 窗口的 X 起点坐标
    Ystart: 窗口的 Y 起点坐标
    Xend: 窗口的 X 终点坐标
    Yend: 窗口的 Y 终点坐标
    Color: 填充的颜色
  • 画点:在图像缓存中,在(Xpoint, Ypoint)上画点,可以选择颜色,点的大小,点的风格

    void Paint_DrawPoint(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color, DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_Style)
    参数:
    Xpoint: 点的 X 坐标
    Ypoint: 点的 Y 坐标
    Color: 填充的颜色
    Dot_Pixel: 点的大小,提供默认的 8 种大小点
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Dot_Style: 点的风格,大小扩充方式是以点为中心扩大还是以点为左下角往右上扩大
    typedef enum {
    DOT_FILL_AROUND = 1,
    DOT_FILL_RIGHTUP,
    } DOT_STYLE;
  • 画线:在图像缓存中,从 (Xstart, Ystart) 到 (Xend, Yend) 画线,可以选择颜色,线的宽度,线的风格

    void Paint_DrawLine(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color, LINE_STYLE Line_Style , LINE_STYLE Line_Style)
    参数:
    Xstart: 线的 X 起点坐标
    Ystart: 线的 Y 起点坐标
    Xend: 线的 X 终点坐标
    Yend: 线的 Y 终点坐标
    Color: 填充的颜色
    Line_width: 线的宽度,提供默认的 8 种宽度
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Line_Style: 线的风格,选择线是以直线连接还是以虚线的方式连接
    typedef enum {
    LINE_STYLE_SOLID = 0,
    LINE_STYLE_DOTTED,
    } LINE_STYLE;
  • 画矩形:在图像缓存中,从 (Xstart, Ystart) 到 (Xend, Yend) 画一个矩形,可以选择颜色,线的宽度,是否填充矩形内部

    void Paint_DrawRectangle(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
    参数:
    Xstart: 矩形的 X 起点坐标
    Ystart: 矩形的 Y 起点坐标
    Xend: 矩形的 X 终点坐标
    Yend: 矩形的 Y 终点坐标
    Color: 填充的颜色
    Line_width: 矩形四边的宽度,提供默认的 8 种宽度
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Draw_Fill: 填充,是否填充矩形的内部
    typedef enum {
    DRAW_FILL_EMPTY = 0,
    DRAW_FILL_FULL,
    } DRAW_FILL;
  • 画圆:在图像缓存中,以 (X_Center Y_Center) 为圆心,画一个半径为 Radius 的圆,可以选择颜色,线的宽度,是否填充圆内部

    void Paint_DrawCircle(uint16_t X_Center, uint16_t Y_Center, uint16_t Radius, uint16_t Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
    参数:
    X_Center: 圆心的 X 坐标
    Y_Center: 圆心的 Y 坐标
    Radius: 圆的半径
    Color: 填充的颜色
    Line_width: 圆弧的宽度,提供默认的 8 种宽度
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Draw_Fill: 填充,是否填充圆的内部
    typedef enum {
    DRAW_FILL_EMPTY = 0,
    DRAW_FILL_FULL,
    } DRAW_FILL;
  • 写 Ascii 字符:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一个 Ascii 字符,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色

    void Paint_DrawChar(uint16_t Xstart, uint16_t Ystart, const uint8_t Ascii_Char, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    Ascii_Char:Ascii 字符
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 写英文字符串:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串英文字符,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色

    void Paint_DrawString_EN(uint16_t Xstart, uint16_t Ystart, const uint8_t * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    pString: 字符串,字符串是一个指针
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 写中文字符串:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串中文字符,可以选择 GB2312 编码字符字库、字体前景色、字体背景色

    void Paint_DrawString_CN(uint16_t Xstart, uint16_t Ystart, const uint8_t * pString, cFONT* font, uint16_t Color_Foreground, uint16_t Color_Background)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    pString: 字符串,字符串是一个指针
    Font: GB2312 编码字符字库,在 Fonts 文件夹中提供了以下字体:
    font12CN:ascii 字符字体 11*21,中文字体 16*21
    font24CN:ascii 字符字体 24*41,中文字体 32*41
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 写数字:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串数字,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色

    void Paint_DrawNum(uint16_t Xpoint, uint16_t Ypoint, uint32_t Nummber, sFONT* Font, uint16_t Digit,uint16_t Color_Foreground, uint16_t Color_Background);
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    Nummber: 显示的数字,这里使用的是 32 位长的 int 型保存,可以最大显示到 2147483647
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Digit: 显示小数点位数
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 显示时间:在图像缓存中,在 (Xstart Ystart) 为左顶点,显示一段时间,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色;

    void Paint_DrawTime(uint16_t Xstart, uint16_t Ystart, PAINT_TIME *pTime, sFONT* Font, uint16_t Color_Background, uint16_t Color_Foreground)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    pTime: 显示的时间,这里定义好了一个时间的结构体,只要把时分秒各位数传给参数;
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色

【运行效果】

  • 使用 VS Code 导入并编译 03_GUI 工程,编译完成后,烧录 build 目录下 uf2 尾缀文件,或直接烧录 firmware\C 目录下 03_GUI.uf2 进行快速验证。


04_LVGL

【程序说明】

  • 使用 SPI 与 液晶通讯,并通过 LVGL 实现显示文本和图片等功能。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

源码结构

  • LVGL 库的源码位于工程文件夹的 lib\lvgl ,使用的版本号为 8.4,二次开发请参考对应版本的开发文档。

  • LVGL 库的相关设置在工程文件夹的 examples\inc\lv_conf.h 中,可以设置显示刷新频率、系统占用数据等。

  • LVGL 库的应用代码位于工程文件夹的 main.c lv_port\lv_port_disp.c lv_port\lv_port_indev.c


LVGL 初始化

在使用 LVGL 图像库之前,您需要先初始化 LVGL。

  • LVGL 库的初始化函数

    代码位置:main.c

    实现功能:主要用于初始化 LVGL 所需的硬件和结构体变量。

    LVGL_Init();
  • LVGL 库核心初始化

    代码位置:main.c

    /*2.Init LVGL core*/
    lv_init();

LVGL 运行

LVGL 库定时调用心跳接口函数 lv_tick_inc 来通知 LVGL 过去的时间,以便 LVGL 能够更新其内部的时间状态,处理与时间相关的任务,例如动画、定时器等。在主函数的循环中还需要调用 lv_task_handler 函数,以便 LVGL 及时处理事件和任务,保证用户界面的响应和刷新。

  • LVGL 心跳接口

    代码位置:main.c

    实现方式:需要确保 lv_task_handler 的优先级低于 lv_tick_inc 的优先级,所以在本例中 lv_tick_inc 在定时器回调函数中调用。

    //每 5ms 调用一次定时器回调函数
    add_repeating_timer_ms(5, repeating_lvgl_timer_callback, NULL, &lvgl_timer);

    static bool repeating_lvgl_timer_callback(struct repeating_timer *t)
    {
    lv_tick_inc(5);
    return true;
    }
  • LVGL 任务处理器

    代码位置:examples\src\LCD_XinXX_LVGL_test.c

    实现方式:要处理 LVGL 的任务,需要定期调用 lv_timer_handler(),本例中在主函数的循环中进行调用。

    int main()
    {
    ...
    while(1)
    {
    lv_task_handler();
    DEV_Delay_ms(5);
    ...
    }
    }

LVGL 显示

要实现 LVGL 显示,必须初始化一个显示驱动,并设置显示驱动的各个属性,例如,颜色格式、绘制缓冲区、渲染模式以及显示回调函数。在每个 LV_DISP_DEF_REFR_PERIOD(在 lv_conf.h 中设置),LVGL 会检测 UI 上是否发生了一些需要重绘的事情。例如,按下按钮、更改图表、发生动画等。需要重新绘制时,LVGL 调用显示回调函数完成图像在刷新区的绘制。

  • LVGL 显示刷新率设置

    代码位置:examples\inc\lv_conf.h

    设置方式:在 lv_conf.h 中还能设置显示缓冲区刷新频率的时间,可以修改这个定义来改变屏幕的刷新时间。

    #define LV_DISP_DEF_REFR_PERIOD 10 // 单位:ms,这里为 10ms
  • LVGL 显示颜色设置

    代码位置:examples\inc\lv_conf.h

    设置目的:由于 lv_color_t 结构体在默认状态下所构建的像素颜色储存方式与本例需要传输的数据不一致,直接进行传输会导致显示的图像出现色差。

    #define LV_COLOR_16_SWAP 1
  • LVGL 显示相关变量定义

    代码位置:lv_port\lv_port_disp.c

    实现功能:定义显示驱动 disp_drv,绘制缓冲区 disp_buf。本例绘制缓冲区 buf0 设置为整个屏幕显示面积,能够在降低大面积刷屏锯齿的同时有效提高屏幕刷新率。

    static lv_disp_drv_t disp_drv;
    static lv_disp_draw_buf_t disp_buf;
    static lv_color_t *buf0;
  • LVGL 显示设备注册

    代码位置:lv_port\lv_port_disp.c

    实现功能:根据设计需求完善 LVGL 库核心结构体变量,初始化显示驱动 disp_drv,并设置绘制缓冲区,该缓冲区是 LVGL 用来渲染屏幕内容的简单数组。一旦渲染准备就绪,绘制缓冲区的内容将使用显示驱动程序中设置的 disp_drv_flush_cb 函数发送到显示器。


    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, buf_2, MY_DISP_HOR_RES * MY_DISP_VER_RES * 2); /*Initialize the display buffer*/

    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 = MY_DISP_HOR_RES;
    disp_drv.ver_res = MY_DISP_VER_RES;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;
    disp_drv.user_data = NULL;

    /*Set a display buffer*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /*Required for Example 3)*/
    #if 1
    disp_drv.full_refresh = 1;
    #endif
    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);

  • LVGL 显示回调函数

    代码位置:lv_port\lv_port_disp.c

    实现功能:主要完成图像在刷新区的绘制。

    void disp_flush( lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p )
    参数:
    lv_disp_drv_t *disp_drv: 显示驱动结构体指针,包含了与显示相关的信息和函数指针。该参数常用于通知刷新完成
    const lv_area_t *area : 区域结构体指针,包含待刷新区域的位置信息。在本例中,用于创建 TFT 显示的窗口
    lv_color_t *color_p : 颜色结构体指针,表示要在刷新区域内显示的颜色数据。在本例中,作为 DMA 输入读取地址将数据传输到 SPI 总线,完成图像的绘制
  • LVGL 显示回调函数实现

    代码位置:lv_port\lv_port_disp.c

    static void disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p)
    {
    UWORD *image_data = (UWORD *)color_p;

    #if 1
    LCD_0IN85_Display(image_data);
    #else
    LCD_0IN85_DisplayWindows(
    area->x1,
    area->y1,
    area->x2,
    area->y2,
    image_data
    );
    #endif

    lv_disp_flush_ready(drv);
    }

  • LVGL 刷新完成通知实现

    代码位置:lv_port\lv_port_disp.c

    实现功能:每一次图像刷新完成后都需要通知 LVGL 核心,以便 LVGL 准备下个刷新图像的渲染。

    lv_disp_flush_ready(drv);

LVGL 输入

在 LVGL 中,允许用户注册输入设备,如触摸板、鼠标、键盘或编码器等设备。用户可以通过这些输入设备控制用户界面,实现更好的交互。

  • LVGL 调用输入设备回调函数的频率设置

    代码位置:examples\inc\lv_conf.h

    设置方式: LVGL 默认每 30ms 调用一次输入设备回调函数来更新输入设备所触发的事件,可以在 lv_conf.h 中进行设置。

    #define LV_INDEV_DEF_READ_PERIOD 30 // 单位:ms,这里为 30ms
  • LVGL 输入设备注册

    代码位置:lv_port\lv_port_indev.c

    设置方式:按键设备 indev_drv 并初始化。

    void lv_port_indev_init(void)
    {
    static lv_indev_drv_t indev_drv;

    keypad_init();

    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_KEYPAD;
    indev_drv.read_cb = keypad_read;
    indev_keypad = lv_indev_drv_register(&indev_drv);
    }
  • LVGL 的输入设备回调函数

    代码位置:lv_port\lv_port_indev.c

    实现功能:主要用于更新输入事件。

    static void keypad_read(lv_indev_drv_t * drv, lv_indev_data_t*data);
    参数:
    lv_indev_drv_t *indev_drv: LVGL 中的输入设备驱动结构体指针。在本例中,该结构体为按键输入设备驱动
    lv_indev_data_t *data : LVGL 中的输入设备数据结构体指针。在本例中,该结构体用于存储输入设备的状态和数据,包括当前的按键状态(按下或释放)

LVGL 控件布局

在 LVGL 中,我们能够建立各种不同的用户界面。界面的基本组成部分是对象,也称为控件(Widgets),比如按钮(Button)、标签(Label)、图像(Image)、列表(List)、图表或文本区域。在一个界面中,可以同时创建多个控件,并且我们可以设置它们的位置、尺寸、父对象、样式以及事件处理程序等基本属性。

  • LVGL 控件的对齐定位

    代码位置:main.c

    实现功能:使控件能够基于参考点进行偏移定位。控件对齐偏移的参考点控件的中心。

    对齐标准: LVGL 库具备内部对齐和外部对齐两种方式。默认以左上角作为原点,向左为水平方向的正方向,向下为垂直方向的正方向。

    //将 btn 控件定位在中心点向左偏移 45 个像素
    lv_obj_align(sw, LV_ALIGN_CENTER, -45, 0);


  • LVGL 控件切换字体大小

    代码位置:examples\inc\lv_conf.hmain.c

    实现功能:在实际运用时一个界面可能需要运用多种字体大小,可以在 lv_conf.h 中使能多种字体大小,且可以设置默认字体大小。设置字体大小时需要对控件风格化,使控件能够按照设置的风格进行渲染。利用 lv_obj_add_style 函数可以实现对控件各个部位在不同状态下的渲染。

    #define LV_FONT_MONTSERRAT_16 1 // 使能 16 号字体
    #define LV_FONT_MONTSERRAT_18 1 // 使能 18 号字体
    #define LV_FONT_DEFAULT &lv_font_montserrat_18 // 设置默认字体大小为 18 号

    static lv_style_t style_label;
    lv_style_init(&style_label); // 初始化风格
    lv_style_set_text_font(&style_label, &lv_font_montserrat_16); // 设置字体大小为 16 号
    lv_obj_add_style(label,&style_label,0); // 设置 label 主题的风格
  • LVGL 控件事件处理

    代码位置:main.c

    实现功能:在 LVGL 中,可以给控件添加事件处理回调函数,使控件发生被点击、滚动、重绘等事件时,触发事件从而进入事件处理回调函数。在程序中调用 lv_obj_add_event_cb(obj, event_cb, filter, user_data) 函数,为控件 obj 添加事件 filter 的处理函数 event_cb,当控件 obj 触发 filter 事件时,系统会自动调用 event_cb 函数。最后一个参数是指向事件中可用的任何自定义数据的指针。

    //为控件 sw 添加事件 LV_EVENT_VALUE_CHANGED 的处理函数 sw_event_cb
    lv_obj_add_event_cb(sw, sw_event_cb,LV_EVENT_VALUE_CHANGED,NULL);

【运行效果】

  • 使用 VS Code 导入并编译 04_LVGL 工程,编译完成后,烧录 build 目录下 uf2 尾缀文件,或直接烧录 firmware\C 目录下 04_LVGL.uf2 文件进行快速验证。


05_WS2812

【程序说明】

  • 使用 PIO 模拟的 WS2812 信号 ,实现 RGB 灯珠循环显色。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

  • WS2812_init();:初始化 WS2812。
  • WS2812_show2(r, g, b):发送颜色数据并点亮灯珠。

【运行效果】

  • 使用 VS Code 导入并编译 05_WS2812 工程,编译完成后,烧录 build 目录下 uf2 尾缀文件,或直接烧录 firmware\C 目录下 05_WS2812.uf2 文件进行快速验证。



Arduino 开发

本章节包含以下部分,请按需阅读:

配置开发环境

请参考 安装和配置 Arduino IDE 教程 下载安装 Arduino IDE。

示例程序

Arduino 示例程序位于 示例程序包 的 examples\Arduino 目录中。

示例程序基础例程说明依赖库
01_GUI液晶 GUI 显示程序-
02_LVGL液晶 LVGL 显示程序LVGL V8.4

01_GUI

【程序说明】

  • 使用 SPI 与 液晶通讯,并通过 GUI 实现显示文本和图片等功能。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

底层硬件接口

我们对硬件操作进行了底层的封装,由于硬件平台不一样,内部的实现是不一样的,如果需要了解内部实现可以去对应的目录中查看,在 DEV_Config.c(.h) 可以看到很多定义,在目录:c\lib\Config

  • 模块初始化与退出的处理

    void DEV_Module_Init(void);
    void DEV_Module_Exit(void);
    提示

    这里是处理使用液晶屏前与使用完之后一些 GPIO 的处理。

  • GPIO 读写

    void DEV_Digital_Write(uint_16 Pin, uint_8 Value);
    uint_8 DEV_Digital_Read(uint_16 Pin);
  • SPI 写数据

    void DEV_SPI_WriteByte(uint_8 Value);

上层应用

对于屏幕而言,如果需要进行画图、显示中英文字符、显示图片等怎么办,这些都是上层应用做的。这有很多小伙伴有问到一些图形的处理,我们这里提供了一些基本的功能 在如下的目录中可以找到 GUI,在目录:c\lib\GUI\GUI_Paint.c(.h)


在如下目录下是 GUI 依赖的字符字体,在目录:c\lib\Fonts


  • 新建图像属性:新建一个图像属性,这个属性包括图像缓存的名称、宽度、高度、翻转角度、颜色

    void Paint_NewImage(uint16_t *image, uint16_t Width, uint16_t Height, uint16_t Rotate, uint16_t Color)
    参数:
    image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
    Width: 图像缓存的宽度;
    Height: 图像缓存的高度;
    Rotate: 图像的翻转的角度
    Color: 图像的初始颜色;
  • 选择图像缓存:选择图像缓存,选择的目的是你可以创建多个图像属性,图像缓存可以存在多个,你可以选择你所创建的每一张图像

    void Paint_SelectImage(uint8_t *image)
    参数:
    image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
  • 图像旋转:设置选择好的图像的旋转角度,最好使用在 Paint_SelectImage() 后,可以选择旋转 0、90、180、270 度

    void Paint_SetRotate(uint16_t Rotate)
    参数:
    Rotate: 图像选择角度,可以选择 ROTATE_0、ROTATE_90、ROTATE_180、ROTATE_270 分别对应 090180270
    提示

    不同选择角度下,坐标对应起始像素点不同,这里以 1.14 为例,四张图,按顺序为 0°, 90°, 180°, 270°。仅做为参考。


  • 图像镜像翻转:设置选择好的图像的镜像翻转,可以选择不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像。

    void Paint_SetMirroring(uint8_t mirror)
    参数:
    mirror: 图像的镜像方式,可以选择 MIRROR_NONE、MIRROR_HORIZONTAL、MIRROR_VERTICAL、MIRROR_ORIGIN 分别对应不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像
  • 设置点在缓存中显示位置和颜色:这里是 GUI 最核心的一个函数、处理点在缓存中显示位置和颜色。

    void Paint_SetPixel(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color)
    参数:
    Xpoint: 点在图像缓存中 X 位置
    Ypoint: 点在图像缓存中 Y 位置
    Color: 点显示的颜色
  • 图像缓存填充颜色:把图像缓存填充为某颜色,一般作为屏幕刷白的作用。

    void Paint_Clear(uint16_t Color)
    参数:
    Color: 填充的颜色
  • 图像缓存部分窗口填充颜色:把图像缓存的某部分窗口填充为某颜色,一般作为窗口刷白的作用,常用于时间的显示,刷白上一秒。

    void Paint_ClearWindows(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color)
    参数:
    Xstart: 窗口的 X 起点坐标
    Ystart: 窗口的 Y 起点坐标
    Xend: 窗口的 X 终点坐标
    Yend: 窗口的 Y 终点坐标
    Color: 填充的颜色
  • 画点:在图像缓存中,在(Xpoint, Ypoint)上画点,可以选择颜色,点的大小,点的风格

    void Paint_DrawPoint(uint16_t Xpoint, uint16_t Ypoint, uint16_t Color, DOT_PIXEL Dot_Pixel, DOT_STYLE Dot_Style)
    参数:
    Xpoint: 点的 X 坐标
    Ypoint: 点的 Y 坐标
    Color: 填充的颜色
    Dot_Pixel: 点的大小,提供默认的 8 种大小点
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Dot_Style: 点的风格,大小扩充方式是以点为中心扩大还是以点为左下角往右上扩大
    typedef enum {
    DOT_FILL_AROUND = 1,
    DOT_FILL_RIGHTUP,
    } DOT_STYLE;
  • 画线:在图像缓存中,从 (Xstart, Ystart) 到 (Xend, Yend) 画线,可以选择颜色,线的宽度,线的风格

    void Paint_DrawLine(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color, LINE_STYLE Line_Style , LINE_STYLE Line_Style)
    参数:
    Xstart: 线的 X 起点坐标
    Ystart: 线的 Y 起点坐标
    Xend: 线的 X 终点坐标
    Yend: 线的 Y 终点坐标
    Color: 填充的颜色
    Line_width: 线的宽度,提供默认的 8 种宽度
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Line_Style: 线的风格,选择线是以直线连接还是以虚线的方式连接
    typedef enum {
    LINE_STYLE_SOLID = 0,
    LINE_STYLE_DOTTED,
    } LINE_STYLE;
  • 画矩形:在图像缓存中,从 (Xstart, Ystart) 到 (Xend, Yend) 画一个矩形,可以选择颜色,线的宽度,是否填充矩形内部

    void Paint_DrawRectangle(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint16_t Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
    参数:
    Xstart: 矩形的 X 起点坐标
    Ystart: 矩形的 Y 起点坐标
    Xend: 矩形的 X 终点坐标
    Yend: 矩形的 Y 终点坐标
    Color: 填充的颜色
    Line_width: 矩形四边的宽度,提供默认的 8 种宽度
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Draw_Fill: 填充,是否填充矩形的内部
    typedef enum {
    DRAW_FILL_EMPTY = 0,
    DRAW_FILL_FULL,
    } DRAW_FILL;
  • 画圆:在图像缓存中,以 (X_Center Y_Center) 为圆心,画一个半径为 Radius 的圆,可以选择颜色,线的宽度,是否填充圆内部

    void Paint_DrawCircle(uint16_t X_Center, uint16_t Y_Center, uint16_t Radius, uint16_t Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
    参数:
    X_Center: 圆心的 X 坐标
    Y_Center: 圆心的 Y 坐标
    Radius: 圆的半径
    Color: 填充的颜色
    Line_width: 圆弧的宽度,提供默认的 8 种宽度
    typedef enum {
    DOT_PIXEL_1X1 = 1, // 1 x 1
    DOT_PIXEL_2X2 , // 2 X 2
    DOT_PIXEL_3X3 , // 3 X 3
    DOT_PIXEL_4X4 , // 4 X 4
    DOT_PIXEL_5X5 , // 5 X 5
    DOT_PIXEL_6X6 , // 6 X 6
    DOT_PIXEL_7X7 , // 7 X 7
    DOT_PIXEL_8X8 , // 8 X 8
    } DOT_PIXEL;
    Draw_Fill: 填充,是否填充圆的内部
    typedef enum {
    DRAW_FILL_EMPTY = 0,
    DRAW_FILL_FULL,
    } DRAW_FILL;
  • 写 Ascii 字符:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一个 Ascii 字符,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色

    void Paint_DrawChar(uint16_t Xstart, uint16_t Ystart, const uint8_t Ascii_Char, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    Ascii_Char:Ascii 字符
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 写英文字符串:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串英文字符,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色

    void Paint_DrawString_EN(uint16_t Xstart, uint16_t Ystart, const uint8_t * pString, sFONT* Font, uint16_t Color_Foreground, uint16_t Color_Background)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    pString: 字符串,字符串是一个指针
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 写中文字符串:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串中文字符,可以选择 GB2312 编码字符字库、字体前景色、字体背景色

    void Paint_DrawString_CN(uint16_t Xstart, uint16_t Ystart, const uint8_t * pString, cFONT* font, uint16_t Color_Foreground, uint16_t Color_Background)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    pString: 字符串,字符串是一个指针
    Font: GB2312 编码字符字库,在 Fonts 文件夹中提供了以下字体:
    font12CN:ascii 字符字体 11*21,中文字体 16*21
    font24CN:ascii 字符字体 24*41,中文字体 32*41
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 写数字:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串数字,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色

    void Paint_DrawNum(uint16_t Xpoint, uint16_t Ypoint, uint32_t Nummber, sFONT* Font, uint16_t Digit,uint16_t Color_Foreground, uint16_t Color_Background);
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    Nummber: 显示的数字,这里使用的是 32 位长的 int 型保存,可以最大显示到 2147483647
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Digit: 显示小数点位数
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色
  • 显示时间:在图像缓存中,在 (Xstart Ystart) 为左顶点,显示一段时间,可以选择 Ascii 码可视字符字库、字体前景色、字体背景色;

    void Paint_DrawTime(uint16_t Xstart, uint16_t Ystart, PAINT_TIME *pTime, sFONT* Font, uint16_t Color_Background, uint16_t Color_Foreground)
    参数:
    Xstart: 字符的左顶点 X 坐标
    Ystart: 字体的左顶点 Y 坐标
    pTime: 显示的时间,这里定义好了一个时间的结构体,只要把时分秒各位数传给参数;
    Font: Ascii 码可视字符字库,在 Fonts 文件夹中提供了以下字体:
    font8:5*8 的字体
    font12:7*12 的字体
    font16:11*16 的字体
    font20:14*20 的字体
    font24:17*24 的字体
    Color_Foreground: 字体颜色
    Color_Background: 背景颜色

【运行效果】


02_LVGL

【环境配置】

  1. 安装 LVGL 库


    1.点击左侧边栏第三个图标或点击菜单栏中的 “工具” > “管理库。..”
    2.在搜索框中输入 “lvgl”,找到 “lvgl” 库
    3.选择 8.4.0 版本
    4.点击 “INSTALL” 按钮进行安装

  2. 添加配置文件


    1.LVGL 有自己的配置文件,名为 lv_conf.h
    2.进入已安装的 Arduino 库的目录,在这里可以看到我们安装的 lvgl 库目录
    3.下载程序包,将程序包中 Arduino\lv_conf.h 复制到本地 Arduino 的库目录下
    4.最终布局 lv_conf.h 看起来应该是这样的:

    arduino
    |-libraries
    |-lvgl
    |-other_lib_1
    |-other_lib_2
    |-lv_conf.h

【程序说明】

  • 使用 SPI 与 液晶通讯,并通过 LVGL 实现显示文本和图片等功能。

【硬件连接】

  • 使用 USB 线把板子接入电脑

【代码分析】

源码结构

  • LVGL 库的源码位于工程文件夹的 lib\lvgl ,使用的版本号为 8.4,二次开发请参考对应版本的开发文档。

  • LVGL 库的相关设置在工程文件夹的 examples\inc\lv_conf.h 中,可以设置显示刷新频率、系统占用数据等。

  • LVGL 库的应用代码位于工程文件夹的 examples\src\02_LVGL.ino examples\src\lv_port_disp.c examples\src\lv_port_indev.c

    VSCode-Example-6

LVGL 初始化

在使用 LVGL 图像库之前,您需要先初始化 LVGL。

  • LVGL 库的初始化函数

    代码位置:examples\src\02_LVGL.ino

    实现功能:主要用于初始化 LVGL 所需的硬件和结构体变量。

    LVGL_Init();
  • LVGL 库核心初始化

    代码位置:examples\src\02_LVGL.ino

    /*2.Init LVGL core*/
    lv_init();

LVGL 运行

LVGL 库定时调用心跳接口函数 lv_tick_inc 来通知 LVGL 过去的时间,以便 LVGL 能够更新其内部的时间状态,处理与时间相关的任务,例如动画、定时器等。在主函数的循环中还需要调用 lv_task_handler 函数,以便 LVGL 及时处理事件和任务,保证用户界面的响应和刷新。

  • LVGL 心跳接口

    代码位置:examples\src\02_LVGL.ino

    实现方式:需要确保 lv_task_handler 的优先级低于 lv_tick_inc 的优先级,所以在本例中 lv_tick_inc 在定时器回调函数中调用。

    //每 5ms 调用一次定时器回调函数
    add_repeating_timer_ms(5, repeating_lvgl_timer_callback, NULL, &lvgl_timer);

    static bool repeating_lvgl_timer_callback(struct repeating_timer *t)
    {
    lv_tick_inc(5);
    return true;
    }
  • LVGL 任务处理器

    代码位置:examples\src\LCD_XinXX_LVGL_test.c

    实现方式:要处理 LVGL 的任务,需要定期调用 lv_timer_handler(),本例中在主函数的循环中进行调用。

    int main()
    {
    ...
    while(1)
    {
    lv_task_handler();
    DEV_Delay_ms(5);
    ...
    }
    }

LVGL 显示

要实现 LVGL 显示,必须初始化一个显示驱动,并设置显示驱动的各个属性,例如,颜色格式、绘制缓冲区、渲染模式以及显示回调函数。在每个 LV_DISP_DEF_REFR_PERIOD(在 lv_conf.h 中设置),LVGL 会检测 UI 上是否发生了一些需要重绘的事情。例如,按下按钮、更改图表、发生动画等。需要重新绘制时,LVGL 调用显示回调函数完成图像在刷新区的绘制。

  • LVGL 显示刷新率设置

    代码位置:examples\inc\lv_conf.h

    设置方式:在 lv_conf.h 中还能设置显示缓冲区刷新频率的时间,可以修改这个定义来改变屏幕的刷新时间。

    #define LV_DISP_DEF_REFR_PERIOD 10 // 单位:ms,这里为 10ms
  • LVGL 显示颜色设置

    代码位置:examples\inc\lv_conf.h

    设置目的:由于 lv_color_t 结构体在默认状态下所构建的像素颜色储存方式与本例需要传输的数据不一致,直接进行传输会导致显示的图像出现色差。

    #define LV_COLOR_16_SWAP 1
  • LVGL 显示相关变量定义

    代码位置:examples\src\lv_port_disp.c

    实现功能:定义显示驱动 disp_drv,绘制缓冲区 disp_buf。本例绘制缓冲区 buf0 设置为整个屏幕显示面积,能够在降低大面积刷屏锯齿的同时有效提高屏幕刷新率。

    static lv_disp_drv_t disp_drv;
    static lv_disp_draw_buf_t disp_buf;
    static lv_color_t *buf0;
  • LVGL 显示设备注册

    代码位置:examples\src\lv_port_disp.c

    实现功能:根据设计需求完善 LVGL 库核心结构体变量,初始化显示驱动 disp_drv,并设置绘制缓冲区,该缓冲区是 LVGL 用来渲染屏幕内容的简单数组。一旦渲染准备就绪,绘制缓冲区的内容将使用显示驱动程序中设置的 disp_drv_flush_cb 函数发送到显示器。


    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, buf_2, MY_DISP_HOR_RES * MY_DISP_VER_RES * 2); /*Initialize the display buffer*/

    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 = MY_DISP_HOR_RES;
    disp_drv.ver_res = MY_DISP_VER_RES;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;
    disp_drv.user_data = NULL;

    /*Set a display buffer*/
    disp_drv.draw_buf = &draw_buf_dsc_1;

    /*Required for Example 3)*/
    #if 1
    disp_drv.full_refresh = 1;
    #endif
    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);

  • LVGL 显示回调函数

    代码位置:examples\src\lv_port_disp.c

    实现功能:主要完成图像在刷新区的绘制。

    void disp_flush( lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p )
    参数:
    lv_disp_drv_t *disp_drv: 显示驱动结构体指针,包含了与显示相关的信息和函数指针。该参数常用于通知刷新完成
    const lv_area_t *area : 区域结构体指针,包含待刷新区域的位置信息。在本例中,用于创建 TFT 显示的窗口
    lv_color_t *color_p : 颜色结构体指针,表示要在刷新区域内显示的颜色数据。在本例中,作为 DMA 输入读取地址将数据传输到 SPI 总线,完成图像的绘制
  • LVGL 显示回调函数实现

    代码位置:examples\src\lv_port_disp.c

    static void disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p)
    {
    UWORD *image_data = (UWORD *)color_p;

    #if 1
    LCD_0IN85_Display(image_data);
    #else
    LCD_0IN85_DisplayWindows(
    area->x1,
    area->y1,
    area->x2,
    area->y2,
    image_data
    );
    #endif

    lv_disp_flush_ready(drv);
    }

  • LVGL 刷新完成通知实现

    代码位置:examples\src\lv_port_disp.c

    实现功能:每一次图像刷新完成后都需要通知 LVGL 核心,以便 LVGL 准备下个刷新图像的渲染。

    lv_disp_flush_ready(drv);

LVGL 输入

在 LVGL 中,允许用户注册输入设备,如触摸板、鼠标、键盘或编码器等设备。用户可以通过这些输入设备控制用户界面,实现更好的交互。

  • LVGL 调用输入设备回调函数的频率设置

    代码位置:examples\inc\lv_conf.h

    设置方式: LVGL 默认每 30ms 调用一次输入设备回调函数来更新输入设备所触发的事件,可以在 lv_conf.h 中进行设置。

    #define LV_INDEV_DEF_READ_PERIOD 30 // 单位:ms,这里为 30ms
  • LVGL 输入设备注册

    代码位置:examples\src\lv_port_indev.c

    设置方式:按键设备 indev_drv 并初始化。

    void lv_port_indev_init(void)
    {
    static lv_indev_drv_t indev_drv;

    keypad_init();

    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_KEYPAD;
    indev_drv.read_cb = keypad_read;
    indev_keypad = lv_indev_drv_register(&indev_drv);
    }
  • LVGL 的输入设备回调函数

    代码位置:examples\src\lv_port_indev.c

    实现功能:主要用于更新输入事件。

    static void keypad_read(lv_indev_drv_t * drv, lv_indev_data_t*data);
    参数:
    lv_indev_drv_t *indev_drv: LVGL 中的输入设备驱动结构体指针。在本例中,该结构体为按键输入设备驱动
    lv_indev_data_t *data : LVGL 中的输入设备数据结构体指针。在本例中,该结构体用于存储输入设备的状态和数据,包括当前的按键状态(按下或释放)

LVGL 控件布局

在 LVGL 中,我们能够建立各种不同的用户界面。界面的基本组成部分是对象,也称为控件(Widgets),比如按钮(Button)、标签(Label)、图像(Image)、列表(List)、图表或文本区域。在一个界面中,可以同时创建多个控件,并且我们可以设置它们的位置、尺寸、父对象、样式以及事件处理程序等基本属性。

  • LVGL 控件的对齐定位

    代码位置:examples\src\02_LVGL.ino

    实现功能:使控件能够基于参考点进行偏移定位。控件对齐偏移的参考点控件的中心。

    对齐标准: LVGL 库具备内部对齐和外部对齐两种方式。默认以左上角作为原点,向左为水平方向的正方向,向下为垂直方向的正方向。

    //将 btn 控件定位在中心点向左偏移 45 个像素
    lv_obj_align(sw, LV_ALIGN_CENTER, -45, 0);

    VSCode-Example-7

  • LVGL 控件切换字体大小

    代码位置:examples\inc\lv_conf.hexamples\src\02_LVGL.ino

    实现功能:在实际运用时一个界面可能需要运用多种字体大小,可以在 lv_conf.h 中使能多种字体大小,且可以设置默认字体大小。设置字体大小时需要对控件风格化,使控件能够按照设置的风格进行渲染。利用 lv_obj_add_style 函数可以实现对控件各个部位在不同状态下的渲染。

    #define LV_FONT_MONTSERRAT_16 1 // 使能 16 号字体
    #define LV_FONT_MONTSERRAT_18 1 // 使能 18 号字体
    #define LV_FONT_DEFAULT &lv_font_montserrat_18 // 设置默认字体大小为 18 号

    static lv_style_t style_label;
    lv_style_init(&style_label); // 初始化风格
    lv_style_set_text_font(&style_label, &lv_font_montserrat_16); // 设置字体大小为 16 号
    lv_obj_add_style(label,&style_label,0); // 设置 label 主题的风格
  • LVGL 控件事件处理

    代码位置:examples\src\02_LVGL.ino

    实现功能:在 LVGL 中,可以给控件添加事件处理回调函数,使控件发生被点击、滚动、重绘等事件时,触发事件从而进入事件处理回调函数。在程序中调用 lv_obj_add_event_cb(obj, event_cb, filter, user_data) 函数,为控件 obj 添加事件 filter 的处理函数 event_cb,当控件 obj 触发 filter 事件时,系统会自动调用 event_cb 函数。最后一个参数是指向事件中可用的任何自定义数据的指针。

    //为控件 sw 添加事件 LV_EVENT_VALUE_CHANGED 的处理函数 sw_event_cb
    lv_obj_add_event_cb(sw, sw_event_cb,LV_EVENT_VALUE_CHANGED,NULL);

【运行效果】

VSCode-Example-8


相关资料

1. 硬件资料

开发板设计文件

2. 技术手册

数据手册

3. 官方资料

4. 开发软件

5. 示例程序


技术支持

周一-周五(9:30-6:30)周六(9:30-5:30)

手机:13434470212

邮箱:services04@spotpear.cn

QQ:202004841