RP2350-Touch-LCD-2 是一款微雪(Waveshare)设计的低成本,高性能的微控制器开发板。在较小的板型下,板载了2英寸电容触摸LCD屏、摄像头接口、Micro SD卡槽、锂电池充电芯片、六轴传感器(三轴加速度计与三轴陀螺仪)等外设,便于开发和集成到产品中。
| LCD参数 | |||
| 触摸芯片 | CST816D | 触摸接口 | I2C | 
| 显示芯片 | ST7789T3 | 显示接口 | SPI | 
| 分辨率 | 240(H)RGB x 320(V) | 显示尺寸 | 30.6mm × 40.8mm | 
| 显示面板 | IPS | 像素间距 | 0.1275mm × 0.1275mm | 
| IMU参数 | |||
| 传感器名称 | QMI8658 | ||
| 加速度计特性 | 分辨率:16 位 量程 (可选):±2、±4、±8、±16g | ||
| 陀螺仪特性 | 分辨率:16 位 量程 (可选):±16、±32、±64、±128、±256、±512、 ±1024、±2048°/sec | ||


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




【MicroPython】machine.Pin类函数详解
【MicroPython】machine.PWM类函数详解
【MicroPython】machine.ADC类函数详解
【MicroPython】machine.UART类函数详解
【MicroPython】machine.I2C类函数详解
【MicroPython】machine.SPI类函数详解
【MicroPython】rp2.StateMachine类函数详解
对于 C/C++,建议使用 Pico VS Code 进行开发,这是一款 Microsoft Visual Studio Code 扩展,旨在让您在为 Raspberry Pi Pico 系列开发板创建、开发和调试项目时更加轻松。无论您是初学者还是经验丰富的专业人士,此工具都可以帮助您自信而轻松地进行 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             











set(PICO_BOARD pico CACHE STRING "Board type")








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


C:\Users\[username]\AppData\Local\Arduino15\packages

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






MircoPython视频例程(github)
MicroPython固件/Blink例程(C)
树莓派官方C/C++示例程序 (github)
树莓派官方micropython示例程序 (github)
Arduino官方C/C++示例程序 (github)
如果您以前使用过我们的SPI屏幕应该会对这份例程比较熟悉
我们进行了底层的封装,由于硬件平台不一样,内部的实现是不一样的,如果需要了解内部实现可以去对应的目录中查看
在DEV_Config.c(.h)可以看到很多定义,在目录:c\lib\Config
#define UBYTE uint8_t #define UWORD uint16_t #define UDOUBLE uint32_t
void DEV_Module_Init(void); void DEV_Module_Exit(void); 注意: 1.这里是处理使用液晶屏前与使用完之后一些GPIO的处理。
void DEV_Digital_Write(UWORD Pin, UBYTE Value); UBYTE DEV_Digital_Read(UWORD Pin);
void DEV_SPI_WriteByte(UBYTE Value);
对于屏幕而言,如果需要进行画图、显示中英文字符、显示图片等怎么办,这些都是上层应用做的。这有很多小伙伴有问到一些图形的处理,我们这里提供了一些基本的功能 在如下的目录中可以找到GUI,在目录:c\lib\GUI\GUI_Paint.c(.h)
在如下目录下是GUI依赖的字符字体,在目录:c\lib\Fonts
void Paint_NewImage(UWORD *image, UWORD Width, UWORD Height, UWORD Rotate, UWORD Color) 参数: image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针; Width: 图像缓存的宽度; Height: 图像缓存的高度; Rotate: 图像的翻转的角度 Color: 图像的初始颜色;
void Paint_SelectImage(UBYTE *image) 参数: image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
void Paint_SetRotate(UWORD Rotate) 参数: Rotate: 图像选择角度,可以选择ROTATE_0、ROTATE_90、ROTATE_180、ROTATE_270分别对应0、90、180、270度

void Paint_SetMirroring(UBYTE mirror) 参数: mirror: 图像的镜像方式,可以选择MIRROR_NONE、MIRROR_HORIZONTAL、MIRROR_VERTICAL、MIRROR_ORIGIN分别对应不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像
void Paint_SetPixel(UWORD Xpoint, UWORD Ypoint, UWORD Color) 参数: Xpoint: 点在图像缓存中X位置 Ypoint: 点在图像缓存中Y位置 Color: 点显示的颜色
void Paint_Clear(UWORD Color) 参数: Color: 填充的颜色
void Paint_ClearWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color) 参数: Xstart: 窗口的X起点坐标 Ystart: 窗口的Y起点坐标 Xend: 窗口的X终点坐标 Yend: 窗口的Y终点坐标 Color: 填充的颜色
void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD 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;
void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD 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;
void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD 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;
void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius, UWORD 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;
void Paint_DrawChar(UWORD Xstart, UWORD Ystart, const char Ascii_Char, sFONT* Font, UWORD Color_Foreground, UWORD 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: 背景颜色
void Paint_DrawString_EN(UWORD Xstart, UWORD Ystart, const char * pString, sFONT* Font, UWORD Color_Foreground, UWORD 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: 背景颜色
void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font, UWORD Color_Foreground, UWORD 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: 背景颜色
void Paint_DrawNum(UWORD Xpoint, UWORD Ypoint, double Nummber, sFONT* Font, UWORD Digit,UWORD Color_Foreground, UWORD 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: 背景颜色
void Paint_DrawTime(UWORD Xstart, UWORD Ystart, PAINT_TIME *pTime, sFONT* Font, UWORD Color_Background, UWORD 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: 背景颜色
unsigned char QMI8658_init(void);
void QMI8658_read_xyz(float acc[3], float gyro[3], unsigned int *tim_count); 参数: float acc[3]: 存储加速度值的数组,表示为浮点数,包含三个元素,分别是 X、Y 和 Z 轴上的加速度 float gyro[3]: 存储陀螺仪值的数组,表示为浮点数,包含三个元素,分别是 X、Y 和 Z 轴上的角速度
def __init__(self)
def write_cmd(self, cmd)
def write_data(self, buf)
def set_bl_pwm(self,duty)
import framebuf
自定义类 LCD_1inch28 继承 MicroPython 中的 framebuf.FrameBuffer 类,这个类提供了许多绘制图像的方法,我们先创建 LCD_1inch28 类对象
LCD = LCD_1inch28()
LCD.line(x1, y1, x2, y2, color) 参数: x1, y1: 起始点的 x 和 y 坐标 x2, y2: 终点的 x 和 y 坐标 color: 线的颜色
LCD.fill_rect(x1, y1, w, h, color)
参数:
	x1, y1: 矩形左上角的 x 和 y 坐标
        w, h:   矩形的宽度和高度
        color:  矩形的填充颜色
LCD.text(str, x, y, color)
参数:
         str:   显示文本
	 x, y:  文本左上角的 x 和 y 坐标
         color: 文本的颜色
LCD.write_text(str, x, y, size, color) 参数: size: 该函数与 LCD.text 的区别是支持自定义字体大小,该参数用于指定字体大小
LCD.show()
qmi8658=QMI8658()
xyz=qmi8658.Read_XYZ()
返回值:
          xyz[0]~xyz[2]: 函数返回一个数组,前三个元素表示 X、Y 和 Z 轴上的加速度
	  xyz[3]~xyz[5]: 这三个元素表示 X、Y 和 Z 轴上的角速度
本例显示的效果为四个可以通过触摸屏滑动切换的界面。



本例用于测试 LVGL 控件交互、样式美化等, LVGL 的具体开发请参考LVGL开发文档。
setx PICO_SDK_PATH "D:\pico\pico-sdk"
mkdir build cd build
cmake -G "NMake Makefiles" ..
nmake编译好后会生成一个 .uf2 格式的文件。
nano ~/.bashrc #将以下内容添加到最后一行 export PICO_SDK_PATH="/home/pico/pico-sdk"
source ~/.bashrc
mkdir build cd build
cmake ..
nmake编译好后会生成一个 .uf2 格式的文件。


在使用 LVGL 图像库之前,您需要先初始化 LVGL。
LVGL_Init();
/*2.Init LVGL core*/ lv_init();
LVGL 库定时调用心跳接口函数 lv_tick_inc 来通知LVGL过去的时间,以便 LVGL 能够更新其内部的时间状态,处理与时间相关的任务,例如动画、定时器等。在主函数的循环中还需要调用 lv_task_handler 函数,以便 LVGL 及时处理事件和任务,保证用户界面的响应和刷新。
//每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;
}
int main()
{
    ...
    while(1)
    {
      lv_task_handler();
      DEV_Delay_ms(5); 
      ...
    }
}
要实现 LVGL 显示,必须初始化一个显示驱动,并设置显示驱动的各个属性,例如,颜色格式、绘制缓冲区、渲染模式以及显示回调函数。在每个 LV_DISP_DEF_REFR_PERIOD(在 lv_conf.h 中设置),LVGL 会检测 UI 上是否发生了一些需要重绘的事情。例如,按下按钮、更改图表、发生动画等。需要重新绘制时,LVGL 调用显示回调函数完成图像在刷新区的绘制。
#define LV_DISP_DEF_REFR_PERIOD 10 // 单位:ms,这里为10ms
#define LV_COLOR_16_SWAP 1
static lv_disp_drv_t disp_drv; static lv_disp_draw_buf_t disp_buf; static lv_color_t buf0[DISP_HOR_RES * DISP_VER_RES/2]; static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES/2];
/*3.Init LVGL display*/ 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);
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总线,完成图像的绘制
static void disp_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
    LCD_SetWindows(area->x1, area->y1, area->x2+1, area->y2+1);
    DEV_Digital_Write(LCD_DC_PIN, 1);
    DEV_Digital_Write(LCD_CS_PIN, 0);
    dma_channel_configure(dma_tx,
                          &c,
                          &spi_get_hw(LCD_SPI_PORT)->dr, 
                          color_p, // read address
                          ((area->x2 + 1 - area-> x1)*(area->y2 + 1 - area -> y1))*2,
                          true);
}
static void dma_handler(void)
{
    if (dma_channel_get_irq0_status(dma_tx)) {
        dma_channel_acknowledge_irq0(dma_tx);
        DEV_Digital_Write(LCD_CS_PIN, 1);
        lv_disp_flush_ready(&disp_drv);     
    }
}
在 LVGL 中,允许用户注册输入设备,如触摸板、鼠标、键盘或编码器等设备。用户可以通过这些输入设备控制用户界面,实现更好的交互。
#define LV_INDEV_DEF_READ_PERIOD 30 // 单位:ms,这里为30ms
/*4.Init touch screen as input device*/ 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); // 注册设备 DEV_IRQ_SET(Touch_INT_PIN, GPIO_IRQ_EDGE_RISE, &touch_callback); //使能触摸中断
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 touch_callback(uint gpio, uint32_t events)
{
    if (gpio == Touch_INT_PIN)
    {
        CST816S_Get_Point();
        gesture = CST816S_Get_Gesture();
        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;
}
在 LVGL 中,我们能够建立各种不同的用户界面。界面的基本组成部分是对象,也称为控件(Widgets),比如按钮(Button)、标签(Label)、图像(Image)、列表(List)、图表或文本区域。在一个界面中,可以同时创建多个控件,并且我们可以设置它们的位置、尺寸、父对象、样式以及事件处理程序等基本属性。
void Widgets_Init(void);
//在 (0,0) 创建一个图块,支持向下滑动到 (0,1) tile1 = lv_tileview_add_tile(tv, 0, 0, LV_DIR_BOTTOM);
//创建一个控件,其中 tab1 为该按键的父对象,可以替换为list、title等可以有子对象的控件 sw = lv_switch_create(tab1);
//将btn控件定位在中心点向左偏移45个像素 lv_obj_align(sw, LV_ALIGN_CENTER, -45, 0);
#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主题的风格
//为控件 sw 添加事件 LV_EVENT_VALUE_CHANGED 的处理函数 sw_event_cb lv_obj_add_event_cb(sw, sw_event_cb,LV_EVENT_VALUE_CHANGED,NULL);
本例显示的效果为四个可以通过触摸屏滑动切换的界面。



本例用于测试 LVGL 控件交互、样式美化等,使用的版本号为9.1,LVGL V9 的开发文档中没有提供 Python 示例,具体开发请参考LVGL开发文档。




在使用 LVGL 图像库之前,您需要导入 LVGL 库并初始化 LVGL 对象
import lvgl as lv
# Init LVGL LVGL(LCD=LCD,TSC=TSC)
if not lv.is_initialized(): lv.init()
LVGL 库定时调用心跳接口函数 lv.tick_inc 来通知 LVGL 过去的时间,以便 LVGL 能够更新其内部的时间状态,处理与时间相关的任务,例如动画、定时器等。此外还需要调用 lv.task_handler 函数,以便 LVGL 及时处理事件和任务,保证用户界面的响应和刷新。
# Create event loop if not yet present if not lv_utils.event_loop.is_running(): self.event_loop=lv_utils.event_loop()
#每 5ms 调用一次定时器回调函数
self.timer.init(mode=Timer.PERIODIC, period=self.delay, callback=self.timer_cb) // 本例中 self.delay = 5
def timer_cb(self, t):
    lv.tick_inc(self.delay)
    if self.scheduled < self.max_scheduled:
        try:
            micropython.schedule(self.task_handler_ref, 0)
            self.scheduled += 1 # 正在处理的任务数增加
        except:
            pass
def task_handler(self, _):
    try:
        if lv._nesting.value == 0:
            lv.task_handler()
            if self.refresh_cb: self.refresh_cb()
        self.scheduled -= 1 # 正在处理的任务数减少
    except Exception as e:
        if self.exception_sink:
            self.exception_sink(e)
要实现 LVGL 显示,必须初始化一个显示驱动,并设置显示驱动的各个属性,例如,颜色格式、绘制缓冲区、渲染模式以及显示回调函数。在每个 LV_DEF_REFR_PERIOD(在 lv_conf.h 中设置),LVGL 会检测 UI 上是否发生了一些需要重绘的事情。例如,按下按钮、更改图表、发生动画等。需要重新绘制时,LVGL 调用显示回调函数完成图像在刷新区的绘制。
#define LV_DEF_REFR_PERIOD 10 // 单位:ms,这里为10ms
# Init LVGL display buf1 = lv.draw_buf_create(self.LCD.width, self.LCD.height // 3 , color_format, 0) buf2 = lv.draw_buf_create(self.LCD.width, self.LCD.height // 3, color_format, 0)
self.disp_drv = lv.display_create(self.LCD.width, self.LCD.height) # 创建显示驱动器对象,并设置宽度和高度 self.disp_drv.set_color_format(color_format) # 设置颜色格式为 RGB565 self.disp_drv.set_draw_buffers(buf1, buf2) # 设置绘制缓冲区 self.disp_drv.set_render_mode(lv.DISPLAY_RENDER_MODE.PARTIAL) # 设置渲染模式为部分刷新模式 self.disp_drv.set_flush_cb(self.disp_drv_flush_cb) # 设置显示回调函数
def disp_drv_flush_cb(self,disp_drv,area,color_p)
参数:
    disp_drv : 显示驱动结构体指针,包含了与显示相关的信息和函数指针。该参数常用于通知刷新完成
    area     : 区域结构体指针,包含待刷新区域的位置信息。在本例中,用于创建 TFT 显示的窗口
    color_p  : 颜色结构体指针,表示要在刷新区域内显示的颜色数据。在本例中,作为DMA输入读取地址将数据传输到SPI总线,完成图像的绘制
def disp_drv_flush_cb(self,disp_drv,area,color_p):
    self.rp2_wait_dma() # 等待 DMA 空闲
    
    ......
    self.rgb565_swap_func(data_view, size)  # 转换颜色格式
    
    self.LCD.setWindows(area.x1, area.y1, area.x2+1, area.y2+1) # 设置 LVGL 界面显示位置
    
    ...... # DMA 配置
    self.rp2_dma.enable() # 使能 DMA
    self.rp2_wait_dma() # 等待 DMA 空闲
           
    self.disp_drv.flush_ready() # 通知 LVGL 数据传输完成
}
在 LVGL 中,允许用户注册输入设备,如触摸板、鼠标、键盘或编码器等设备。用户可以通过这些输入设备控制用户界面,实现更好的交互。
#define LV_DEF_REFR_PERIOD 10 // 单位:ms,这里为10ms
# Init touch screen as input device self.indev_drv = lv.indev_create() # 创建对象 self.indev_drv.set_type(lv.INDEV_TYPE.POINTER) # 注册触摸屏设备 self.indev_drv.set_read_cb(self.indev_drv_read_cb) # 设置回调函数
def indev_drv_read_cb(indev_drv, data) 参数: indev_drv : LVGL 中的输入设备驱动结构体指针。在本例中,该结构体为触摸屏输入设备驱动 data : LVGL 中的输入设备数据结构体指针。在本例中,该结构体用于存储输入设备的状态和数据,包括当前的触摸状态(按下或释放)以及触摸点的坐标
def Int_Callback(self,pin):
    if self.Mode == 0 :
        self.Gestures = self._read_byte(0x01)
    elif self.Mode == 1 :           
        self.Flag = 1
        self.get_point()
    
    elif self.Mode == 2 :           
        self.Flag = 1
        self.get_point()
        self.Gestures = self._read_byte(0x01)
def indev_drv_read_cb( self, indev_drv, data):
    self.rp2_wait_dma()  
    data.point.x = self.TSC.X_point
    data.point.y = self.TSC.Y_point
    
    data.state = 1 if self.TSC.Flag == 1 else 0 
    self.TSC.Flag = 0
在 LVGL 中,我们能够建立各种不同的用户界面。界面的基本组成部分是对象,也称为控件(Widgets),比如按钮(Button)、标签(Label)、图像(Image)、列表(List)、图表或文本区域。在一个界面中,可以同时创建多个控件,并且我们可以设置它们的位置、尺寸、父对象、样式以及事件处理程序等基本属性。
# Init WIDGETS WIDGETS(LCD=LCD,TSC=TSC,IMU=IMU)
//在 (0,0) 创建一个图块,支持向下滑动到 (0,1) self.tv = lv.tileview(self.scr) self.tile1 = self.tv.add_tile(0, 0, lv.DIR.BOTTOM)
//创建一个 table 控件,其中 tile2 为该控件的父对象,可以替换为list、title等可以有子对象的控件 self.table_imu_data = lv.table(self.tile2)
//将控件定位在中心点右偏移15个像素 self.table_imu_data.align(lv.ALIGN.CENTER, 15 ,0)
#define LV_FONT_MONTSERRAT_16 1 // 使能16号字体 #define LV_FONT_MONTSERRAT_18 1 // 使能18号字体 #define LV_FONT_DEFAULT &lv_font_montserrat_18 // 设置默认字体大小为18号 table_imu_data= lv.style_t() // 创建对象 table_imu_data.init() // 初始化 table_imu_data.set_text_font(lv.font_montserrat_16) // 设置字体大小为16 self.table_imu_data.add_style(style_imu_table, 0) // 设置风格
//为控件 sw 添加事件 LV_EVENT_VALUE_CHANGED 的处理函数 sw_event_cb self.sw.add_event_cb(self.sw_event_cb, lv.EVENT.VALUE_CHANGED, None)
周一-周五(9:30-6:30)周六(9:30-5:30)
手机:13434470212
邮箱:services04@spotpear.cn
QQ:202004841
