Pico-LCD-1.14

来自Waveshare Wiki
跳转至: 导航搜索
Pico-LCD-1.14
{{{name2}}}
{{{name3}}}
功能简介
特性 无特性,不解释
显示尺寸 1.14英寸
分辨率 135×240
' 无特性,不解释
' 无特性,不解释
接口 SPI

产品概述

提供Pico C语言例程

产品参数

参数名称 参数
供电电压 2.6V ~ 5.5V
工作电流 40mA
屏幕类型 IPS
控制芯片 ST7789V
通信接口 4-wire SPI
分辨率 135(H)RGB x 240(V) Pixels
像素大小 0.1101(H)x 0.1035(V)mm
显示尺寸 14.864(H)x 24.912(V)mm
产品尺寸 25.00(H)x52.00(V) mm

接口说明

Pico-LCD-1.14-details-inter.jpg

LCD 及其控制器

本款LCD使用的内置控制器为ST7789VW,是一款240 x RGB x 320像素的LCD控制器,而本LCD本身的像素为135(H)RGB x 240(V),同时由于初始化控制可以初始化为横屏和竖屏两种,因此LCD的内部RAM并未完全使用。
该LCD支持12位,16位以及18位每像素的输入颜色格式,即RGB444,RGB565,RGB666三种颜色格式,本例程使用RGB565的颜色格式,这也是常用的RGB格式
LCD使用四线SPI通信接口,这样可以大大的节省GPIO口,同时通信是速度也会比较快

通信协议

0.96inch lcd module spi.png
注:与传统的SPI协议不同的地方是:由于是只需要显示,故而将从机发往主机的数据线进行了隐藏,该表格详见Datasheet Page 66。
RESX为复位,模块上电时拉低,通常情况下置1;
CSX为从机片选, 仅当CS为低电平时,芯片才会被使能。
D/CX为芯片的数据/命令控制引脚,当DC = 0时写命令,当DC = 1时写数据
SDA为传输的数据,即RGB数据;
SCL为SPI通信时钟。
对于SPI通信而言,数据是有传输时序的,即时钟相位(CPHA)与时钟极性(CPOL)的组合:
CPHA的高低决定串行同步时钟是在第一时钟跳变沿还是第二个时钟跳变沿数据被采集,当CPHA = 0,在第一个跳变沿进行数据采集;
CPOL的高低决定串行同步时钟的空闲状态电平,CPOL = 0,为低电平。
从图中可以看出,当SCLK第一个下降沿时开始传输数据,一个时钟周期传输8bit数据,使用SPI0,按位传输,高位在前,低位在后。


Pico-LCD-1.14连接与例程

硬件连接

连接Pico的时候,请注意对应方向不要接反。可以观察模块上有USB丝印的一端与Pico的USB接口一端来判断方向(也可以根据模块上的排母的引脚标号与Pico的引脚标号判断)
您可以对照以下表格连线。

Pico连接引脚对应关系
LCD Pico 功能
VCC VSYS 电源输入
GND GND 电源地
DIN GP11 SPI通信MOSI引脚,从设备数据输入
CLK GP10 SPI通信SCK引脚,从设备时钟输入
CS GP9 SPI片选引脚(低电平有效)
DC GP8 数据/命令控制引脚(高电平数据,低电平命令)
RST GP12 外部复位引脚(电平有效)
BL GP13 背光控制

直连

Pico-LCD-1.14-details-3.jpg

扩展板连接

Pico-LCD-1.14-wiki-2.jpg

程序下载

如果您购买的是V1版本(不带摇杆) 打开树莓派终端,执行:

sudo apt-get install p7zip-full
cd ~
sudo wget  https://www.waveshare.net/w/upload/2/28/Pico_code.7z
7z x Pico_code.7z -o./Pico_code
cd ~/Pico_code
cd c/build/

如果您购买的是V2版本(带摇杆) 打开树莓派终端,执行:

sudo apt-get install p7zip-full
cd ~
sudo wget  https://www.waveshare.net/w/upload/0/06/Pico-LCD-1.14.zip
7z x Pico-LCD-1.14.zip -o./Pico-LCD-1.14
cd ~/Pico-LCD-1.14
cd c/build/

例程使用

C部分

  • 以下教程为在树莓派上操作,但由于cmake的多平台、可移植的特点,在PC上也是能成功编译,但操作略有不同,需要客户自行判断。

进行编译,请确保在c目录:

cd ~/Pico_code/c/

创建并进入build目录,并添加SDK: 其中 ../../pico-sdk 是你的SDK的目录。 我们示例程序中是有build的,直接进入即可

cd build
export PICO_SDK_PATH=../../pico-sdk
(注意:务必写对你自己的SDK所在路径)

执行cmake自动生成Makefile文件

cmake ..

打开c文件夹下面的main.c,可以更改你需要的例程,该例程可以驱动本公司Pico系列的显示屏且源码会一直更新,请选择对应的LCD或OLED测试函数,注释掉无关函数
Pico-lcd-0.96-img-main.png
执行make生成可执行文件,第一次编译时间比较久

make -j9

编译完成,会生成uf2文件。 按住Pico板上的按键,将pico通过Micro USB线接到树莓派的USB接口,然后松开按键。接入之后,树莓派会自动识别到一个可移动盘(RPI-RP2),将build文件夹下的main.uf2 文件复制到识别的可移动盘(RPI-RP2)中即可。

cp main.uf2 /media/pi/RPI-RP2/

Python部分

windows环境下的使用

  • 1.按住Pico板上的BOOTSET按键,将pico通过Micro USB线接到电脑的USB接口,待电脑识别出一个可移动硬盘(RPI-RP2)后,松开按键。
  • 2.将python目录中pico_micropython_20210121.uf2 文件复制到识别的可移动盘(RPI-RP2)中
  • 3.打开Thonny IDE(注意:要使用最新版本的Thonny,否则是没有Pico的支持包的,当前Windows下的最新版本为v3.3.3)
  • 4.点击工具->设置->解释器,如图所示选择Pico及对应的端口

Pico-lcd-0.96-img-config.png

  • 5.文件->打开->pico-lcd-0.96.py,点击运行即可,如下图所示:

Pico-lcd-0.96-img-run.png
本例程提供了一个简单的程序...

树莓派环境下的使用

  • 1.刷固件的过程与Windows上一样,你可以选择在PC或者树莓派上将pico_micropython_20210121.uf2 文件拷入pico中。
  • 2.在树莓派上打开Thonny IDE (点击树莓logo -> Programming -> Thonny Python IDE ),你可以在Help->About Thonny查看版本信息

以确保你的版本是有Pico支持包的,同样你可以点击Tools -> Options... -> Interpreter选择MicroPython(Raspberry Pi Pico 和ttyACM0端口
如图所示:
Pico-lcd-0.96-img-config2.png
如果你当前的Thonny版本没有pico支持包,输入以下指令来更新Thonny IDE

sudo apt upgrade thonny

3.点击File->Open...->python/Pico-LCD-0.96/Pico-LCD-0.96.py,运行脚本即可

代码简析

如果您以前使用过我们的SPI屏幕应该会对这份例程比较熟悉

C

底层硬件接口

我们进行了底层的封装,由于硬件平台不一样,内部的实现是不一样的,如果需要了解内部实现可以去对应的目录中查看
在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的处理。
  • GPIO读写:
void 	DEV_Digital_Write(UWORD Pin, UBYTE Value);
UBYTE 	DEV_Digital_Read(UWORD Pin);
  • SPI写数据
void DEV_SPI_WriteByte(UBYTE Value);

上层应用

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

  • 新建图像属性:新建一个图像属性,这个属性包括图像缓存的名称、宽度、高度、翻转角度、颜色
void Paint_NewImage(UWORD *image, UWORD Width, UWORD Height, UWORD Rotate, UWORD Color)
参数:
 	image : 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
 	Width : 图像缓存的宽度;
 	Height: 图像缓存的高度;
 	Rotate:图像的翻转的角度
 	Color :图像的初始颜色;
  • 选择图像缓存:选择图像缓存,选择的目的是你可以创建多个图像属性,图像缓存可以存在多个,你可以选择你所创建的每一张图像
void Paint_SelectImage(UBYTE *image)
参数:
 	image: 图像缓存的名称,实际上是一个指向图像缓存首地址的指针;
  • 图像旋转:设置选择好的图像的旋转角度,最好使用在Paint_SelectImage()后,可以选择旋转0、90、180、270
void Paint_SetRotate(UWORD Rotate)
参数:
 	Rotate: 图像选择角度,可以选择ROTATE_0、ROTATE_90、ROTATE_180、ROTATE_270分别对应0、90、180、270度
【说明】不同选择角度下,坐标对应起始像素点不同,这里以1.14为例,四张图,按顺序为0°, 90°, 180°, 270°。仅做为参考
Pico LCD Rotate.jpg
  • 图像镜像翻转:设置选择好的图像的镜像翻转,可以选择不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像。
void Paint_SetMirroring(UBYTE mirror)
参数:
 	mirror: 图像的镜像方式,可以选择MIRROR_NONE、MIRROR_HORIZONTAL、MIRROR_VERTICAL、MIRROR_ORIGIN分别对应不镜像、关于水平镜像、关于垂直镜像、关于图像中心镜像
  • 设置点在缓存中显示位置和颜色:这里是GUI最核心的一个函数、处理点在缓存中显示位置和颜色;
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: 填充的颜色
  • 画点:在图像缓存中,在(Xpoint, Ypoint)上画点,可以选择颜色,点的大小,点的风格
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;
  • 画线:在图像缓存中,从 (Xstart, Ystart) 到 (Xend, Yend) 画线,可以选择颜色,线的宽度,线的风格
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;
  • 画矩形:在图像缓存中,从 (Xstart, Ystart) 到 (Xend, Yend) 画一个矩形,可以选择颜色,线的宽度,是否填充矩形内部
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;
  • 画圆:在图像缓存中,以 (X_Center Y_Center) 为圆心,画一个半径为Radius的圆,可以选择颜色,线的宽度,是否填充圆内部
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;
  • 写Ascii字符:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一个Ascii字符,可以选择Ascii码可视字符字库、字体前景色、字体背景色
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: 背景颜色
  • 写英文字符串:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串英文字符,可以选择Ascii码可视字符字库、字体前景色、字体背景色
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: 背景颜色
  • 写中文字符串:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串中文字符,可以选择GB2312编码字符字库、字体前景色、字体背景色;
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: 背景颜色
  • 写数字:在图像缓存中,在 (Xstart Ystart) 为左顶点,写一串数字,可以选择Ascii码可视字符字库、字体前景色、字体背景色
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: 背景颜色
  • 显示时间:在图像缓存中,在 (Xstart Ystart) 为左顶点,显示一段时间,可以选择Ascii码可视字符字库、字体前景色、字体背景色;
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: 背景颜色


LVGL 示例程序

功能介绍

本例程兼容多款 LCD ,依据设备是否配备摇杆及配备按键数量来定制功能实现。通过摇杆实现虚拟指针移动,通过按键实现界面切换、模拟指针点击、开关状态反转等功能。各 LCD 示例功能概览表格如下:

Pico-LCD LVGL 示例功能介绍
型号 界面1 界面2 界面3
Pico-LCD-0.96 一张图片 一个虚拟的指针、一个按钮、一个标签记录点击按钮次数
Pico-LCD-1.14 一张图片 一个虚拟的指针、一个按钮、一个标签记录点击按钮次数
Pico-LCD-1.3 一张图片 一个虚拟的指针、一个按钮、一个标签记录点击按钮次数 两个开关
Pico-LCD-1.44 一张图片 一个按钮、一个标签记录点击按钮次数 两个开关
Pico-LCD-1.8 一张图片 一张图片
Pico-LCD-2 一张图片 一个按钮、一个标签记录点击按钮次数 两个开关

示例简介

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

实现功能

  1. 本例使用 DMA 传输颜色数据到 SPI 总线,降低 CPU 的利用率,在进行简单交互时可以控制 CPU 的占用率在 35% 以下,内存占用在 20% 以下。
  2. 本例系统时钟为 150MHz ,设置 SPI 的外围时钟频率与系统时钟一致,同时使用 LVGL 库的双缓冲区机制,在进行一个缓冲区的数据传输时另一个缓冲区进行渲染,保证了动画的流畅度。
  3. 本例使用摇杆控制指针移动,通过按键模拟指针点击和切换界面,展示了 LVGL 控件的简单运用。

编译运行

  • Windows
    • 参考Windows环境搭建教程完成环境搭建
    • 打开 VS 2022->工具栏->命令行->开发者 Powershell
    • 将你的 pico-sdk 所在绝对地址设置为 PICO_SDK_PATH,如我的 pico-sdk 地址为“D:\pico\pico-sdk”
      setx PICO_SDK_PATH "D:\pico\pico-sdk"
    • 下载例程,进入源码目录,如果 build 目录已经存在,则可以直接进入。如没有则创建该目录:
      mkdir build
      cd build
    • 执行 cmake ,自动生成 Makefile 文件:
      cmake -G "NMake Makefiles" ..
    • 执行 nmake 生成可执行文件,然后在终端中输入:
      nmake
      等待编译好后将生成的 .uf2 格式的文件复制到pico中即可。
  • 树莓派/Ubuntu
    • 参考Pico入门使用手册的 Chapter 2. The SDK 完成环境搭建
    • 打开一个 terminal,设置环境变量 PICO_SDK_PATH 的值为 pico-sdk 所在绝对地址,如我的 pico-sdk 地址为“/home/pi/pico/pico-sdk”
      nano ~/.bashrc
      #将以下内容添加到最后一行
      export PICO_SDK_PATH="/home/pi/pico/pico-sdk"
    • 设置完后保存退出,使配置立即生效
      source ~/.bashrc
    • 下载例程,进入源码目录,如果 build 目录已经存在,则可以直接进入。如没有则创建该目录:
      mkdir build
      cd build
    • 执行 cmake ,自动生成 Makefile 文件:
      cmake ..
    • 执行 make 生成可执行文件,然后在终端中输入:
      make
      等待编译好后将生成的 .uf2 格式的文件复制到pico中即可。

源码解析

源码结构

  • LVGL 库的源码位于工程文件夹的 lib/lvgl ,使用的版本号为8.1,二次开发请参考对应版本的开发文档。
  • LVGL 库的相关设置在工程文件夹的 examples/inc/lv_conf.h 中,可以设置显示刷新频率、系统占用数据等。
    Pico-LCD-LVGL-inc.png
  • LVGL 库的应用代码位于工程文件夹的 examples/src/LVGL_example.cexamples/src/LCD_XinXX_LVGL_test.c,XinXX 表示 LCD 尺寸,如 0in96 对应的文件为 LCD_0in96_LVGL_test.c 。
    Pico-LCD-LVGL-src.png

数据存储

本例使用了一个数据结构体,用于存储和管理与 LVGL 相关的数据。它包含了指向不同界面的指针、各个界面中控件(按钮、标签、开关)的指针,以及用于记录按钮点击次数和按键状态的变量。

  • 数据结构体
    • 代码位置:examples/inc/LVGL_example.h
    • 功能介绍:用于存储和管理所需的数据。
typedef struct {
    lv_obj_t *scr[4];     // 用于存储不同界面
    lv_obj_t *cur;        // 指针
    lv_obj_t *btn;        // 按钮
    lv_obj_t *label;      // 标签
    lv_obj_t *sw_1;       // 开关 1 
    lv_obj_t *sw_2;       // 开关 2
    uint16_t click_num;   // 按钮点击次数
    uint16_t KEY_now;     // 按键当前状态
    uint16_t KEY_old;     // 按键上一状态
} lvgl_data_struct;

按键读取

对于按键读取,本例使用按键扫描的方法实现,下面我们进行详细的介绍,程序中也提供了相应的注释。

  • 按键初始化
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 功能介绍:初始化模块所有物理按键。
LCD_XINXX_KEY_Init();
  • 按键相关宏定义
    • 代码位置:lib/Config/DEV_Config.h
    • 使用方法:本例程兼容多款 LCD ,有摇杆需要将 LCD_HAS_JOY 的值设置为 1,无摇杆则置 0。所有按键的状态用一个 16 进制变量存储,该变量的每一位都可以用来表示一个按键的状态,如用第一位表示 KEY_A 的状态,用第二位表示 KEY_B 状态。每个位有 1 或 0 两种状态,分别表示按键按下或松开,如第一位为 1 则表示 KEY_A 按下,为 0 则表示 KEY_A 松开。该方式支持检测多个按键同时按下。
#define LCD_HAS_JOY  1

#define KEY_A     0x0001
#define KEY_B     0x0002
#define KEY_X     0x0004
#define KEY_Y     0x0008
#define KEY_UP    0x0010
#define KEY_DOWN  0x0020
#define KEY_LEFT  0x0040
#define KEY_RIGHT 0x0080
#define KEY_CTRL  0x0100
#define KEY_0     0x0200
#define KEY_1     0x0400
#define KEY_2     0x0800
#define KEY_3     0x1000
  • 按键读取
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现方式:定义一个 16 进制变量 KEY_Value,初始化为 0,若检测到按键按下,则按键对应的数据位置 1,读取完所有按键的状态后,返回 KEY_Value。由于每个模块搭载的按键数量存在差异,所以按键读取函数也会有所不同,这里仅以 Pico-LCD-0.96 为例演示,其他型号请参考完整示例。
static uint16_t LCD_0IN96_Read_KEY(void) 
{
    uint16_t KEY_Value = 0;

    if (DEV_Digital_Read(LCD_KEY_A)  == 0)          KEY_Value |= KEY_A;    
    if (DEV_Digital_Read(LCD_KEY_B)  == 0)          KEY_Value |= KEY_B;    

    if (DEV_Digital_Read(LCD_KEY_UP) == 0)          KEY_Value |= KEY_UP;
    else if (DEV_Digital_Read(LCD_KEY_DOWN)  == 0)  KEY_Value |= KEY_DOWN;
    else if (DEV_Digital_Read(LCD_KEY_LEFT)  == 0)  KEY_Value |= KEY_LEFT;
    else if (DEV_Digital_Read(LCD_KEY_RIGHT) == 0)  KEY_Value |= KEY_RIGHT;
    else if (DEV_Digital_Read(LCD_KEY_CTRL)  == 0)  KEY_Value |= KEY_CTRL;

    return KEY_Value;
}
  • 键值存储
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现方式:读取当前按键值并保存到 dat->KEY_now 中。按键处理后,将当前按键值保存到 dat->KEY_old 中。在下一次按键处理时,这个值将作为按键的先前状态,用于判断按键状态的变化。如果某一位上一循环是 0,当前是 1,则表示该按键新按下。如果某一位上一循环是 1,当前是 0,则表示该按键按下后松开。
while(1)
{
    dat->KEY_now = LCD_XINXX_Read_KEY();  // 读取当前键值
    handle_key_press(dat);                // 按键处理
    dat->KEY_old = dat->KEY_now;          // 保存为旧键值
}
  • 按键处理
    • 代码位置:examples/src/LVGL_example.c
    • 实现方式:使用 dat->KEY_now 通过与运算判断当前按键是否按下,结合 dat->KEY_old 可判断当前按键是否为新按下。
void handle_key_press(lvgl_data_struct *dat) 
{
    // 判断 KEY_UP 按键是否按下
    if(dat->KEY_now & KEY_UP) 
    ....
    // 判断 KEY_A 按键是否新按下
    if((dat->KEY_now & KEY_A) && !(dat->KEY_old & KEY_A)) 
    ....
    // 判断 KEY_A 按键是否松开
    else if(!(dat->KEY_now & KEY_A))
    ....
}

LCD 参数配置

为了适配多款 LCD 显示屏,本例设置了三个关键参数,允许用户根据目标 LCD 的具体特性进行外部配置。

  • LCD 参数定义
    • 代码位置:examples/src/LVGL_example.c
    • 实现功能:DISP_HOR_RES 、DISP_VER_RES 主要用于初始化 LVGL 显示缓冲区;LCD_SetWindows 是一个函数指针,指向 LCD 设置显示位置函数,主要用于设置 LVGL 界面显示位置。
// LCD 
LCD_SetWindowsFunc LCD_SetWindows;
uint16_t DISP_HOR_RES;
uint16_t DISP_VER_RES;
  • LCD 参数配置
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现功能:根据使用的 LCD 型号配置参数。
LCD_SetWindows = LCD_XINXX_SetWindows; // 指向LCD显示函数
DISP_HOR_RES = LCD_XINXX_WIDTH;        // LCD水平分辨率
DISP_VER_RES = LCD_XINXX_HEIGHT;       // LCD垂直分辨率

LVGL 初始化

LVGL 库的初始化流程主要就是对几个 LVGL 核心结构体变量的初始化,LVGL库的运行依靠核心结构体变量。

  • LVGL 库的初始化函数
    • 代码位置:examples/src/LVGL_example.c
    • 实现功能:主要用于初始化 LVGL 所需的硬件和结构体变量。
void LVGL_Init(void);
  • LVGL 库核心结构体变量定义
    • 代码位置:examples/src/LVGL_example.c
    • 定义方式:buf0 和 buf1 大小设置为屏幕显示面积的一半是为了实现 LVGL 双缓冲机制,能够在降低大面积刷屏锯齿的同时有效提高屏幕刷新率;在使用单缓冲区时最好设置为屏幕显示面积的10%,可以有效降低系统占用但在大面积图像刷新时会出现较明显的锯齿。
// LVGL
static lv_disp_draw_buf_t disp_buf;   // LVGL绘制缓冲区
static lv_color_t *buf0;              // LVGL颜色数据缓冲区0
static lv_color_t *buf1;              // LVGL颜色数据缓冲区1
static lv_disp_drv_t disp_drv;        // LVGL显示驱动                
  • LVGL 库的初始化函数实现
    • 代码位置:examples/src/LVGL_example.c
    • 实现功能:根据设计需求完善 LVGL 库核心结构体变量,初始化绘制缓冲区。绘制缓冲区 disp_buf 通过调用 lv_disp_draw_buf_init 实现初始化,该缓冲区是 LVGL 用来渲染屏幕内容的简单数组。 一旦渲染准备就绪,绘制缓冲区的内容将使用显示驱动程序中设置的 flush_cb 函数发送到显示器。
// 初始化LVGL核心
lv_init();

// 初始化LVGL显示缓冲区结构体变量disp_buf
buf0 = (lv_color_t *)malloc(DISP_HOR_RES * DISP_VER_RES / 2 * sizeof(lv_color_t));
buf1 = (lv_color_t *)malloc(DISP_HOR_RES * DISP_VER_RES / 2 * sizeof(lv_color_t));
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);   

LVGL 运行

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

  • LVGL 心跳接口
    • 代码位置:examples/src/LVGL_example.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 显示

在每个 LV_DISP_DEF_REFR_PERIOD(在 lv_conf.h 中设置),LVGL 会检测 UI 上是否发生了一些需要重绘的事情。例如,按下按钮、更改图表、发生动画等。需要重新绘制时,LVGL 调用显示回调函数完成图像在刷新区的绘制。

  • LVGL 显示回调函数
    • 代码位置:examples/src/LVGL_example.c
    • 实现功能:主要完成图像在刷新区的绘制。
static void disp_flush_cb(lv_disp_drv_t * disp, 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/inc/lv_conf.h
    • 设置目的:由于 lv_color_t 结构体在默认状态下所构建的像素颜色储存方式与本例需要传输的数据不一致,直接进行传输会导致显示的图像出现色差。
#define LV_COLOR_16_SWAP 1
  • LVGL 显示刷新率设置
    • 代码位置:examples/inc/lv_conf.h
    • 设置方式:在 lv_conf.h 中还能设置显示缓冲区刷新频率的时间,可以修改这个定义来改变屏幕的刷新时间。
#define LV_DISP_DEF_REFR_PERIOD  10  // 单位:ms,这里为10ms
  • LVGL 显示回调函数实现
    • 代码位置:examples/src/LVGL_example.c
    • 实现方式:在本例中为了最大化降低处理器的利用率,使用 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_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);
}
  • LVGL 刷新完成通知实现
    • 代码位置:examples/src/LVGL_example.c
    • 实现功能:每一次图像刷新完成后都需要通知 LVGL 核心,以便 LVGL 准备下个刷新图像的渲染。
    • 实现方式:本例在 DMA 传输完成中断服务函数中通知 LVGL 图像刷新完成,如果使用阻塞通知的机制就无法利用双缓冲机制来提高刷新速度。
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 控件布局

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

  • LVGL 控件初始化函数
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现功能:实现风格化控件和布局控件,参数 dat 作为传入传出参数,用于存储初始化后的界面和各个控件。
static void Widgets_Init(lvgl_data_struct *dat);
  • LVGL 创建界面
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现功能:创建一个界面。
//lv_obj_t *scr[4]是一个指针数组,每个元素都可以用来指向一个界面
dat->scr[0] = lv_obj_create(NULL); 
  • LVGL 创建控件
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现功能:创建控件,不同控件需要使用不同的函数接口,可以选择父对象进行创建。
//创建一个控件,其中dat->scr[1]为该按键的父对象,可以替换为list、title等可以有子对象的控件
dat->btn = lv_btn_create(dat->scr[1]); 
  • LVGL 控件的对齐定位
    • 代码位置:examples/src/LCD_XinXX_LVGL_test.c
    • 实现功能:使控件能够基于参考点进行偏移定位。控件对齐偏移的参考点控件的中心。
    • 对齐标准: LVGL 库具备内部对齐和外部对齐两种方式。默认以左上角作为原点,向左为水平方向的正方向,向下为垂直方向的正方向。
//将btn控件定位在中心点向左偏移50个像素,向下偏移50个像素的位置
lv_obj_align(btn, LV_ALIGN_CENTER, -50 , 50);
RP2040-Touch-LCD-1.28-LVGL-align.png
  • LVGL 控件切换字体大小
    • 代码位置:examples/inc/lv_conf.hexamples/src/LVGL_example.c
    • 实现功能:在实际运用时一个界面可能需要运用多种字体大小,可以在 lv_conf.h 中使能多种字体大小,且可以设置默认字体大小。设置字体大小时需要对控件风格化,使控件能够按照设置的风格进行渲染。利用 lv_obj_add_style 函数可以实现对控件各个部位在不同状态下的渲染。
#define LV_FONT_MONTSERRAT_14 1                                // 使能14号字体
#define LV_FONT_MONTSERRAT_16 1                                // 使能16号字体
#define LV_FONT_DEFAULT &lv_font_montserrat_14                 // 设置默认字体大小为14号

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 接口函数

本例自定义了一些函数,主要用于指针的移动和点击。

  • LVGL 控件相关的自定义接口函数
    • 代码位置:examples/src/LVGL_example.c
    • 实现功能:主要用于移动控件、判断指针点击是否有效,这里仅做简单描述,详情请查看完整示例。
static void widgets_up(lv_obj_t *widgets);                          // 控件上移
static void widgets_down(lv_obj_t *widgets, uint16_t DISP_VER_RES); // 控件下移
static void widgets_left(lv_obj_t *widgets);                        // 控件左移
static void widgets_right(lv_obj_t *widgets, uint16_t DISP_HOR_RES);// 控件右移
static bool click_valid(lv_obj_t *cur, lv_obj_t *widgets);          // 判断指针点击是否有效


Pico快速上手

固件下载

MicroPython固件下载
Pico MicroPython.gif
C_Blink固件下载
Pico Blink.gif
教程名3
列表3
教程名4
列表4
教程名5
列表5
教程名6
列表6
教程名7
列表7
教程名8
列表8

文字教程

基础介绍

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的安装包。
    Arduino下载2.0版本.jpg
  2. 这里选择仅下载就可以了。
    仅下载不捐赠.png
  3. 下载完成后,点击安装。
    IDE安装水印-1.gif
    注意:安装过程中会提示你安装驱动,我们点击安装即可
    Arduino驱动安装水印.jpg

Arduino IDE中文界面

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

在Arduino IDE中安装Arduino-Pico Core

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

    Pico首选项.png
    注意:如果您已经有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,由于我的电脑已经安装过了,所以显示已安装
    开发板管理器.png
    开发板管理器-1.png
国内用户
  • 因为网络原因,国内用户连接github并不稳定,我们另外提供了一份安装包,可以跳过在线的过程
  • 若已经成功配置了pico环境,可以直接跳过本章
  1. 下载rp2040压缩包,将解压的rp2040文件夹复制到如下路径下
    C:\Users\[username]\AppData\Local\Arduino15\packages

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

第一次上传程序

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


  1. 下载程序,打开arduino\PWM\D1-LED路径下的D1-LED.ino
  2. 点击工具>端口,记住已有的COM,不需要点击这个COM(不同电脑显示的COM不一样,记住自己电脑上已有的COM)
    Pico连接前端口.png
  3. 用USB线将驱动板和计算机连接起来,再点击工具>端口,第一次连接选择uf2 Board,上传完成后,再次连接就会多出一个COM口
    Pico连接后uf2.png
  4. 点击工具>开发板>Raspberry Pi Pico/RP2040>Raspberry Pi Pico
    工具pico开发板.png
    Arduono-Raspberrypi pico.png
  5. 设置完成后,点击向右箭头上传将程序
    Pico上传程序.png
  • 如果期间遇到了问题,需要重新安装或者更换Arduino IDE版本时,卸载Arduino IDE需要卸载干净,卸载软件后需要手动删除C:\Users\[name]\AppData\Local\Arduino15这个文件夹内的所有内容(需要显示隐藏文件才能看到) 再重新安装

开源例程

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



技术支持


联系人:彭工
EMAIL:2851966006@qq.com
电话:0755-83040712
QQ:2851966006
微信:扫下方二维码添加
Pqy.png

说明:进行售后服务前,请准备好客户信息(定货单位、定货人等),以供验证