RP2040-LCD-1.28教程


产品概述

RP2404-LCD-1.28 是一款Waveshare设计的高性能的微控制器开发板,其在较小的板型情况下,板载了1.28inch LCD、锂电池充电芯片、六轴传感器(三轴加速度与三轴陀螺仪)等外设,并且引出了所有的GPIO与Debug接口,方便用户开发,并嵌入应用到产品中。

产品特性

  • 采用了 Raspberry Pi 官方设计的 RP2040 微控制器芯片
  • 搭载了双核 ARM Cortex M0 + 处理器,运行频率高达 133MHz 灵活时钟
  • 内置了 264KB 的 SRAM 和 2MB 的片上 Flash
  • 采用Type-C接口,紧跟时代潮流,无需纠结正反插
  • 板载一个1.28英寸的LCD显示屏
  • 全部GPIO(共30个,但是有引脚已经连接内bu电路,复用时需要注意,详情请参考)经过1.27间距排母引出
  • USB1.1 主机和设备支持
  • 支持低功耗睡眠和休眠模式
  • 可通过 USB 识别为大容量存储器进行拖放式下载程序
  • 2 个 SPI,2 个 I2C,2 个 UART,4 个 12 位 ADC,16 个可控 PWM 通道
  • 精确的片上时钟和定时器
  • 温度传感器
  • 片上加速浮点库
  • 8 个可编程 I/O (PIO) 状态机,用于自定义外设支持
  • 板载锂电池充放电接口,有利于RP2040-LCD-1.28使用在一些移动场景。

产品参数

LCD参数
控制芯片GC9A01A分辨率240(H)RGB x 240(V)
通信接口SPI显示尺寸Φ32.4mm
显示面板IPS像素大小0.135(H)x0.135(V)mm


IMU参数
加速度计特性分辨率:16 位
量程 (可选):±2、±4、±8、±16g
陀螺仪特性分辨率:16 位
量程 (可选):±16、±32、±64、±128、±256、±512、 ±1024、±2048°/sec

引脚分布



尺寸图


Pico快速上手

Pico百科

固件下载:http://spotpear.cn/public/index/study/detail/id/547.html


文字教程

基础介绍

Raspberry Pi Pico的基础介绍

MicroPython系列

【MicroPython】machine.Pin类函数详解
【MicroPython】machine.PWM类函数详解
【MicroPython】machine.ADC类函数详解
【MicroPython】machine.UART类函数详解
【MicroPython】machine.I2C类函数详解
【MicroPython】machine.SPI类函数详解
【MicroPython】rp2.StateMachine类函数详解

C/C++系列

【C/C++】 Windows教程1——环境搭建
【C/C++】 Windows教程2——创建工程

Arduino IDE 系列

安装Arduino IDE

  1. 首先到Arduino官网下载Arduino IDE的安装包。
  2. 这里选择仅下载就可以了。
  3. 下载完成后,点击安装。

    注意:安装过程中会提示你安装驱动,我们点击安装即可

Arduino IDE中文界面

  1. 第一次安装完成后,打开Arduino IDE全是英文界面,我们可以在File>Preferences切换成简体中文。
  2. 在Language里面选择简体中文,点击OK。

在Arduino IDE中安装Arduino-Pico Core

  1. 打开Arduino IDE,点击左上角的文件,选择首选项
  2. 在附加开发板管理器网址中添加如下链接,然后点击OK
    https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json


    注意:如果您已经有ESP32板URL,您可以使用逗号分隔 URL,如下所示:

    https://dl.espressif.com/dl/package_esp32_index.json,https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
  3. 点击工具>开发板>开发板管理器>搜索pico,由于我的电脑已经安装过了,所以显示已安装

    开发板管理器-1.png
国内用户
  • 因为网络原因,国内用户连接github并不稳定,我们另外提供了一份安装包,可以跳过在线的过程
  • 若已经成功配置了pico环境,可以直接跳过本章
  1. 下载rp2040压缩包,将解压的rp2040文件夹复制到如下路径下
    C:\Users\[username]\AppData\Local\Arduino15\packages


    注意:将里面用户名:[username]替换成自己的用户名

第一次上传程序

  1. 按住Pico板上的BOOTSET按键,将pico通过Micro USB线接到电脑的USB接口,待电脑识别出一个可移动硬盘(RPI-RP2)后,松开按键。


  1. 下载程序,打开arduino\PWM\D1-LED路径下的D1-LED.ino
  2. 点击工具>端口,记住已有的COM,不需要点击这个COM(不同电脑显示的COM不一样,记住自己电脑上已有的COM)
  3. 用USB线将驱动板和计算机连接起来,再点击工具>端口,第一次连接选择uf2 Board,上传完成后,再次连接就会多出一个COM口
  4. 点击工具>开发板>Raspberry Pi Pico/RP2040>Raspberry Pi Pico

    Arduono-Raspberrypi pico.png
  5. 设置完成后,点击向右箭头上传将程序
  • 如果期间遇到了问题,需要重新安装或者更换Arduino IDE版本时,卸载Arduino IDE需要卸载干净,卸载软件后需要手动删除C:\Users\[name]\AppData\Local\Arduino15这个文件夹内的所有内容(需要显示隐藏文件才能看到) 再重新安装

开源例程

MircoPython视频例程(github)
MicroPython固件/Blink例程(C)
树莓派官方C/C++示例程序 (github)
树莓派官方micropython示例程序 (github)
Arduino官方C/C++示例程序 (github)

应用示例

LVGL 示例程序

示例效果

本例显示的效果为两个可以通过触摸屏滑动或六轴传感器抬动切换的界面。

  • 第一个界面
    • 显示内容:微雪电子的 Logo。

  • 第二个界面
    • 显示内容:六轴传感器的数据。
    • 刷新频率:每 500ms 更新一次。
    • 切换方式:利用六轴传感器右抬触发输入设备确定事件选中界面,再向上抬触发切换事件实现界面切换。

示例简介

本例用于测试 LVGL 控件交互、样式美化等, LVGL 的具体开发请参考LVGL开发文档

源码结构

  • LVGL 库的源码位于工程文件夹的 ./lib/lvgl ,使用的版本号为8.1,二次开发请参考对应版本的开发文档。
  • LVGL 库的相关设置在工程文件夹的 ./examples/inc/lv_conf.h 中,可以设置显示刷新频率、系统占用数据等。

  • LVGL 库的应用代码位于工程文件夹的 ./examples/src/LVGL_example.c 。

实现功能

  1. 本例使用 DMA 传输颜色数据到 SPI 总线,降低 CPU 的利用率,在进行简单交互时可以控制 CPU 的占用率在 20% 以下,内存占用在 30% 以下。
  2. 本例系统时钟为 270MHz ,设置 SPI 的外围时钟频率与系统时钟一致,同时使用 LVGL 库的双缓冲区机制,在进行一个缓冲区的数据传输时另一个缓冲区进行渲染,保证了动画的流畅度。
  3. 本例使用六轴模拟器利用陀螺仪数据模拟为编码器输入设备,可以应用于多个交互场景。

编译运行

  • 进入源码目录,如果 build 目录已经存在,则可以直接进入。如果没有,执行:
mkdir build
  • 进入 build 目录,并添加SDK的地址:
cd build
export PICO_SDK_PATH=../../pico-sdk

注意:pico-sdk 的路径需要按照实际情况进行调整

  • 执行 cmake ,自动生成 Makefile 文件:
cmake ..
  • 执行 make 生成可执行文件,然后在终端中输入:
make

等待编译好后将生成的 .uf2 格式的文件复制到pico中即可。

源码解析

LVGL 初始化

  • LVGL 库的初始化函数
    • 实现功能:主要用于初始化 LVGL 所需的硬件和结构体变量。
void LVGL_Init(void);
  • LVGL 库核心结构体变量定义
    • 定义功能:LVGL 库的初始化流程主要就是对几个 LVGL 核心结构体变量的初始化,LVGL库的运行依靠核心结构体变量。
    • 定义方式:buf0 和 buf1 大小设置为屏幕显示面积的一半是为了实现 LVGL 双缓冲机制,能够在降低大面积刷屏锯齿的同时有效提高屏幕刷新率;在使用单缓冲区时最好设置为屏幕显示面积的10%,可以有效降低系统占用但在大面积图像刷新时会出现较明显的锯齿。
// LVGL
static lv_disp_draw_buf_t disp_buf;                   //LVGL显示缓冲区
static lv_color_t buf0[DISP_HOR_RES * DISP_VER_RES/2];//LVGL颜色数据缓冲区0
static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES/2];//LVGL颜色数据缓冲区1
static lv_disp_drv_t disp_drv;                        //LVGL显示驱动

static lv_indev_drv_t indev_en;                       //LVGL六轴传感器模拟编码器输入设备驱动
static lv_group_t *group;                             //编码器控件组                  
  • LVGL 库的初始化函数实现
    • 实现功能:根据设计需求完善 LVGL 库核心结构体变量。
    • 实现方式: LVGL 库的编码器输入设备拥有编辑模式和浏览模式,在浏览模式下触发切换事件就会在控件组内切换选中的控件,触发确认事件进入选中控件的编辑模式。所以让六轴传感器模拟编码器时必须要引入 lv_group_t 结构体变量作为六轴传感器的控件组。
// 初始化LVGL核心
lv_init();

// 初始化LVGL显示缓冲区结构体变量disp_buf
lv_disp_draw_buf_init(&disp_buf, buf0, buf1, DISP_HOR_RES * DISP_VER_RES / 2); 
lv_disp_drv_init(&disp_drv);    
disp_drv.flush_cb = disp_flush_cb;
disp_drv.draw_buf = &disp_buf;        
disp_drv.hor_res = DISP_HOR_RES;
disp_drv.ver_res = DISP_VER_RES;
lv_disp_t *disp= lv_disp_drv_register(&disp_drv);   

// 初始化编码器输入设备
lv_indev_drv_init(&indev_en);   
indev_en.type = LV_INDEV_TYPE_ENCODER;  
indev_en.read_cb = encoder_read_cb;         
lv_indev_t * encoder_indev = lv_indev_drv_register(&indev_en);
group = lv_group_create();
lv_indev_set_group(encoder_indev, group);//将编码器控制设备添加控件组
  • LVGL 库运行实现
    • 实现功能:LVGL 库定时调用函数 lv_tick_inc 来通知LVGL过去的时间,以便 LVGL 能够更新其内部的时间状态,处理与时间相关的任务,例如动画、定时器等。在主函数的循环中还需要调用 lv_task_handler 函数来处理一些设定好的任务。
    • 实现方式:需要确保 lv_task_handler 的优先级低于 lv_tick_inc 的优先级,所以在本例中 lv_tick_inc 在定时器回调函数中调用。
add_repeating_timer_ms(5, repeating_lvgl_timer_callback, NULL, &lvgl_timer);//每5ms调用一次定时器回调函数

static bool repeating_lvgl_timer_callback(struct repeating_timer *t) 
{
    lv_tick_inc(5);
    return true;
}

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

}

LVGL 显示

  • LVGL 显示回调函数
    • 实现功能:主要完成图像在刷新区的绘制。
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_color_t 结构体在默认状态下所构建的像素颜色储存方式与本例需要传输的数据不一致,直接进行传输会导致显示的图像出现色差。
    • 设置方式:在 lv_conf.h 文件夹中修改设置改变颜色的储存方式。
#define LV_COLOR_16_SWAP 1
  • LVGL 显示刷新率设置
    • 设置方式:在 lv_conf.h 中还能设置显示缓冲区刷新频率的时间,可以修改这个定义来改变屏幕的刷新时间。
#define LV_DISP_DEF_REFR_PERIOD  10     /*[ms]*/
  • LVGL 显示回调函数实现
    • 实现方式:在本例中为了最大化降低处理器的利用率,使用 DMA 来进行颜色数据的传输,设置 color_p 作为读地址,SPI 总线的输出数据寄存器为写地址。
static void disp_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{

    LCD_1IN28_SetWindows(area->x1, area->y1, area->x2 , area->y2);//设置图像的显示区域
    dma_channel_configure(dma_tx,
                          &c,
                          &spi_get_hw(LCD_SPI_PORT)->dr,          //SPI总线的输出数据寄存器地址
                          color_p,                                //待刷新的颜色数据数组地址
                          ((area->x2 + 1 - area-> x1)*(area->y2 + 1 - area -> y1))*2,
                          true                                    //设置完毕后立刻进行传输
                          );
}
  • LVGL 刷新完成通知实现
    • 实现功能:每一次图像刷新完成后都需要通知 LVGL 核心,以便 LVGL 准备下个刷新图像的渲染。
    • 实现方式:本例在 DMA 传输完成中断服务函数中通知 LVGL 图像刷新完成,如果使用阻塞通知的机制就无法利用双缓冲机制来提高刷新速度。
static void dma_handler(void)
{
    if (dma_channel_get_irq0_status(dma_tx)) {
        dma_channel_acknowledge_irq0(dma_tx);
        lv_disp_flush_ready(&disp_drv);         
    }
}

LVGL 输入

  • LVGL 的输入设备回调函数
    • 实现功能:主要用于更新输入事件。
static void encoder_read_cb(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 默认每 30ms 调用一次输入设备回调函数来更新输入设备所触发的事件,可以在 lv_conf.h 中进行设置。
#define LV_INDEV_DEF_READ_PERIOD 30     /*[ms]*/
  • 六轴传感器输入设备回调函数实现
    • 操作方式:六轴传感器模拟编码器作为输入设备,上下抬触发切换事件,右抬触发确定事件。
    • 实现方式:由于六轴传感器的数据变换较为频繁,为了减少误操作的情况采用定时多次采样的方式来更新设备的切换事件和确定事件。
static bool repeating_imu_diff_timer_callback(struct repeating_timer *t);//每隔50ms更新一次输入事件
{
    get_diff_data();//多次采样识别输入事件更新全局变量encoder_diff和encoder_act
    return true;
}

static void encoder_read_cb(lv_indev_drv_t * drv, lv_indev_data_t*data)
{
  data->enc_diff = encoder_diff;
  data->state    = encoder_act; 
}

LVGL 控件布局

  • LVGL 控件初始化函数
    • 实现功能:主要用于风格化控件和布局控件。
void Widgets_Init(void);
  • LVGL 控件创建函数
    • 实现功能:创建控件,不同控件需要使用不同的函数接口,可以选择父对象进行创建。
lv_obj_t *btn = lv_btn_create(lv_scr_act()); //创建一个控件,其中lv_scr_act层为该按键的父对象,可以替换为list、title等可以有子对象的控件
  • LVGL 控件的对齐定位
    • 实现功能:使控件能够基于参考点进行偏移定位。控件对齐偏移的参考点控件的中心。
    • 对齐标准: LVGL 库具备内部对齐和外部对齐两种方式。默认以左上角作为原点,向左为水平方向的正方向,向下为垂直方向的正方向。
lv_obj_align(btn, LV_ALIGN_CENTER, -50 , 50);//将btn控件定位在中心点向左偏移50个像素,向下偏移50个像素的位置

  • LVGL 控件的风格化
    • 实现功能:使控件能够按照设置的风格进行渲染。利用 lv_obj_add_style 函数可以实现对控件各个部位在不同状态下的渲染。
static lv_style_t style_base;
lv_style_init(&style_base);                                                          //初始化风格
lv_style_set_bg_color(&style_base, lv_palette_main(LV_PALETTE_LIGHT_GREEN));         //设置背景颜色
lv_style_set_border_color(&style_base, lv_palette_darken(LV_PALETTE_LIGHT_GREEN, 3));//设置边界的颜色
lv_style_set_border_width(&style_base, 2);                                           //设置编辑的宽度
lv_style_set_radius(&style_base, 10);                                                //设置倒角的尺寸
lv_style_set_shadow_width(&style_base, 10);                                          //设置阴影的宽度

lv_obj_add_style(btn,&style_base,0);                                                 //设置btn主题的风格,0可以替换为位置和状态

  • LVGL 控件组添加函数
    • 实现功能:将 LVGL 控件并入控件组,使编码器输入设备可以进入编辑模式对控件的状态进行修改。
lv_group_add_obj(group, btn);//将btn控件添加到控件组group中