RP2350-Touch-LCD-1.28 使用教程

说明

产品概述

RP2350-Touch-LCD-1.28 是一款微雪 (Waveshare) 设计的低成本,高性能的微控制器开发板。 在较小的板型下,板载了 1.28 英寸电容触摸 LCD 屏、锂电池充电芯片、六轴传感器(三轴加速度计与三轴陀螺仪)等外设,方便开发并嵌入应用到产品中。

产品特性

  • 采用了Raspberry Pi研发的 RP2350 微控制器芯片
  • 独特的双核、双架构,搭载了双核 ARM Cortex-M33 处理器和双核 Hazard3 RISC-V 核处理器,运行频率均高达 150MHz 灵活时钟
  • 内置 520KB 的 SRAM 和 4MB 的片上 Flash
  • 采用Type-C接口,紧跟时代潮流,无需纠结正反插
  • 板载 1.28 英寸电容触摸 LCD 屏,240×240 分辨率,65K 彩色
  • 板载锂电池充放电接口,有利于移动场景使用
  • USB1.1 主机和设备支持
  • 支持低功耗睡眠和休眠模式
  • 可通过 USB 识别为大容量存储器进行拖放式下载程序
  • 温度传感器
  • 片上加速浮点库
  • 通过 SH1.0 连接器引出 6 个 GPIO

产品参数

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


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

注意事项

  1. 圆形触摸屏的边缘,触摸灵敏和准确度会有所下降,这是圆形触摸屏的结构导致的。

引脚分布


尺寸图


Pico快速上手

基础介绍文字教程

Raspberry Pi Pico的基础介绍

MicroPython系列

安装Thonny IDE

为了方便在电脑上使用MicroPython开发Pico/Pico2板,建议下载Thonny IDE


  • 配置Micrpython环境及选择Pico/Pico2端口
    • 先将Pico/Pico2接入电脑,左键点击Thonny右下角的配置环境选项--》选择configture interpreter
    • 在弹出的窗口栏中选择MicroPython(Raspberry Pi Pico),同时选择对应的端口


  • 点击ok后返回到Thonny主界面,下载对应的固件库并烧录到设备中,然后点击停止按钮,在Shell窗口中即可显示当前使用到的环境
  • Pico/Pico2在windows下载固件库方法: 按住BOOT键后连接电脑后,松开BOOT键,电脑会出现一个可移动磁盘,将固件库复制进去即可
  • RP2040/RP2350在windows下载固件库方法: 连接电脑后,同时按下BOOT键跟RESET键,先松开RESET键再松开BOOT键,电脑会出现一个可移动磁盘,将固件库复制进去即可(用Pico/Pico2的方式也可以)


讲解视频

【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++,建议使用 Pico VS Code 进行开发,这是一款 Microsoft Visual Studio Code 扩展,旨在让您在为 Raspberry Pi Pico 系列开发板创建、开发和调试项目时更加轻松。无论您是初学者还是经验丰富的专业人士,此工具都可以帮助您自信而轻松地进行 Pico 开发。下面我们介绍如何安装该扩展并使用。

安装VSCode

  1. 首先,点击下载 pico-vscode 程序包,解压并打开程序包,双击安装 VSCode
    注意:如果已安装 vscode 注意检查版本是否为 v1.87.0 或更高版本

安装扩展

  1. 点击扩展,选择从 VSIX 安装

  2. 选择 vsix 后缀的软件包,点击安装

  3. 随后 vscode 会自动安装 raspberry-pi-pico 及其依赖扩展,可以点击刷新查看安装进度

  4. 右下角显示完成安装,关闭 vscode

配置扩展

  1. 打开目录 C:\Users\用户名,将整个 .pico-sdk 拷贝至该目录

  2. 拷贝完成
  3. 打开 vscode,对 Raspberry Pi Pico 扩展中各个路径进行配置

    配置如下:
    Cmake Path:
    ${HOME}/.pico-sdk/cmake/v3.28.6/bin/cmake.exe
    
    Git Path:
    ${HOME}/.pico-sdk/git/cmd/git.exe    
    
    Ninja Path:
    ${HOME}/.pico-sdk/ninja/v1.12.1/ninja.exe
    
    Python3 Path:
    ${HOME}/.pico-sdk/python/3.12.1/python.exe             
    

新建工程

  1. 配置完成,测试新建工程,输入工程名、选择路径后点击 Creat 创建工程
    测试官方示例,可以点击工程名旁的 Example 进行选择

  2. 创建工程成功

  3. 选择SDK版本

  4. 选择 Yes 进行高级配置

  5. 选择交叉编译链,13.2.Rel1 适用 ARM 核,RISCV.13.3 适用 RISCV 核,这里根据您的需求任意选择其中一个即可

  6. CMake 版本选择 Default(前面配置的路径)

  7. Ninja 版本选择 Default

  8. 选择开发板

  9. 点击 Complie 进行编译

  10. 成功编译出 uf2 格式文件即可

导入工程

  1. 导入工程的 Cmake 文件不能有中文(包括注释),否则可能导致导入失败
  2. 导入自己的工程需要在 Cmake 文件中加一行代码,才能正常切换 pico 和 pico2,否则即使选择 pico2,编译得到的固件仍是适用于 pico 的

    set(PICO_BOARD pico CACHE STRING "Board type")
    

更新扩展

  1. 离线包中的扩展版本为0.15.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/4.0.2/package_rp2040_index.json


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

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

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


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

第一次上传程序

  1. 按住Pico板上的BOOTSET按键,将pico通过Micro USB线接到电脑的USB接口,待电脑识别出一个可移动硬盘(RPI-RP2)后,松开按键。
    Pico连接数据线.gif
  2. 下载程序,打开arduino\PWM\D1-LED路径下的D1-LED.ino
  3. 点击工具>端口,记住已有的COM,不需要点击这个COM(不同电脑显示的COM不一样,记住自己电脑上已有的COM)

  4. 用USB线将驱动板和计算机连接起来,再点击工具>端口,第一次连接选择uf2 Board,上传完成后,再次连接就会多出一个COM口

  5. 点击工具>开发板>Raspberry Pi Pico>Raspberry Pi Pico或Raspberry Pi Pico 2

  6. 设置完成后,点击向右箭头上传将程序

  • 如果期间遇到了问题,需要重新安装或者更换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_ts;                       //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_ts); 
    indev_ts.type = LV_INDEV_TYPE_POINTER;    
    indev_ts.read_cb = ts_read_cb;            
    lv_indev_t * ts_indev = lv_indev_drv_register(&indev_ts);
    
    // 初始化编码器输入设备
    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 ts_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 中的输入设备数据结构体指针。在本例中,该结构体用于存储输入设备的状态和数据,包括当前的触摸状态(按下或释放)以及触摸点的坐标
    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 void touch_callback(uint gpio, uint32_t events)
    {
      if (gpio == Touch_INT_PIN)
      {
          CST816S_Get_Point();//更新Touch_CTS816全局变量
          ts_x = Touch_CTS816.x_point;
          ts_y = Touch_CTS816.y_point;
          ts_act = LV_INDEV_STATE_PRESSED;
      }
    }
    
    static void ts_read_cb(lv_indev_drv_t * drv, lv_indev_data_t*data)
    {
        data->point.x = ts_x;
        data->point.y = ts_y; 
        data->state = ts_act;
        ts_act = LV_INDEV_STATE_RELEASED;
    }
    
    
  • 六轴传感器输入设备回调函数实现
    • 操作方式:模拟编码器作为输入设备,上下抬触发切换事件,右抬触发确定事件。
    • 实现方式:由于六轴传感器的数据变换较为频繁,为了减少误操作的情况采用定时多次采样的方式来更新设备的切换事件和确定事件。
    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中

资料

配套资料

示例程序

原理图与位号图

3D 图纸

数据手册

官方资料

树莓派官方文档


树莓派开源例程

技术支持