庐山派SPI_LCD模块API手册ST7789驱动配置与图形显示实战最近在玩庐山派开发板想接个小屏幕显示点信息发现官方提供的SPI_LCD模块用起来挺方便的尤其是驱动常见的ST7789芯片的屏幕。不过刚开始看API文档时有些地方不太明白调试也踩了几个坑。今天我就结合自己的使用经验手把手带你从硬件连接到代码编写完整走一遍SPI屏幕的驱动流程。这篇教程适合正在用庐山派做嵌入式GUI开发的朋友无论你是想显示传感器数据、做个简单界面还是学习MicroPython下的屏幕驱动都能从这里找到答案。咱们会从最基础的引脚连接开始讲到每个API的详细用法最后实现文字和图形的显示。1. 硬件连接与初始化1.1 认识你的SPI LCD屏幕首先得确认你手里的屏幕是不是ST7789主控的。市面上很多1.3寸、1.54寸、2.0寸的IPS TFT屏幕都用这个芯片通过4线SPI接口通信。所谓4线SPI除了时钟(SCLK)和数据(MOSI)这两根必需的线外还有数据/命令选择(DC)和片选(CS)线。有些屏幕还有复位(RST)和背光(BL)引脚。拿到屏幕后先看看背面的小芯片上面印着ST7789字样就对了。然后找到屏幕的引脚定义通常丝印上会标出VCC电源正极3.3V或5V看屏幕规格GND电源地SCL或SCLKSPI时钟线SDA或MOSISPI数据线主机输出从机输入DC或RS数据/命令选择CS或SS片选RST复位可选BL背光控制可选注意庐山派开发板的GPIO电压是3.3V如果你的屏幕是5V供电需要确认是否支持3.3V逻辑电平或者加电平转换电路。1.2 连接庐山派开发板根据官方示例代码我们来连接庐山派和屏幕。这里我以最常见的连接方式为例屏幕引脚庐山派GPIO功能说明VCC3.3V电源正极GNDGND电源地SCL/SCLKGPIO15SPI时钟SDA/MOSIGPIO16SPI数据输出DC/RSGPIO20数据/命令选择CS/SSGPIO19片选软件控制RSTGPIO44复位可选BL不接或接GPIO背光控制可选实际接线时我建议先用杜邦线把电源和地接好确保屏幕能正常点亮背光如果背光常亮的话。然后再接信号线这样不容易烧坏屏幕。1.3 基础代码初始化硬件接好后咱们开始写代码。首先导入必要的模块import time, image from machine import FPIOA, Pin, SPI, SPI_LCD庐山派的GPIO需要通过FPIOA现场可编程IO阵列来配置功能这个和传统的单片机直接操作寄存器不太一样算是庐山派的一个特色。第一步配置各个控制引脚# 创建FPIOA对象 fpioa FPIOA() # 配置CS引脚GPIO19为普通GPIO输出 fpioa.set_function(19, FPIOA.GPIO19) pin_cs Pin(19, Pin.OUT, pullPin.PULL_NONE, drive15) pin_cs.value(1) # 初始拉高不选中屏幕 # 配置DC引脚GPIO20为普通GPIO输出 fpioa.set_function(20, FPIOA.GPIO20) pin_dc Pin(20, Pin.OUT, pullPin.PULL_NONE, drive15) pin_dc.value(1) # 配置RST引脚GPIO44为普通GPIO输出内部上拉 fpioa.set_function(44, FPIOA.GPIO44, pu1) pin_rst Pin(44, Pin.OUT, pullPin.PULL_UP, drive15)这里有几个细节需要注意drive15设置GPIO的驱动能力为最大确保信号质量pullPin.PULL_NONE表示不启用内部上下拉电阻pin_cs.value(1)让片选处于高电平SPI设备在片选为低时才被选中RST引脚配置了内部上拉pu1这样复位引脚默认是高电平第二步配置SPI总线# 配置SPI时钟引脚GPIO15为QSPI0_CLK功能 fpioa.set_function(15, fpioa.QSPI0_CLK) # SCLK # 配置SPI数据输出引脚GPIO16为QSPI0_D0功能 fpioa.set_function(16, fpioa.QSPI0_D0) # MOSI # 创建SPI对象使用SPI1控制器 spi1 SPI(1, baudrate1000*1000*50, polarity1, phase1, bits8)SPI参数解释baudrate1000*1000*50通信速率50MHz这是庐山派SPI的最高速度之一polarity1时钟空闲时为高电平phase1数据在时钟的第二个边沿采样bits8每次传输8位数据ST7789芯片通常支持模式0polarity0, phase0或模式3polarity1, phase1这里用的是模式3。如果你发现屏幕不显示可以尝试改成模式0看看。2. SPI_LCD对象创建与配置2.1 创建LCD对象硬件和SPI都配置好后就可以创建LCD对象了lcd SPI_LCD(spi1, pin_dc, pin_cs, pin_rst)构造函数参数说明spi刚才创建的SPI对象dc数据/命令选择引脚对象cs片选引脚对象可选但强烈建议使用软件CSrst复位引脚对象可选bl背光引脚对象可选示例代码没用到typeLCD类型默认就是SPI_LCD.ST7789这里有个坑我踩过cs参数虽然是可选的但官方文档特别标注强烈建议用软件CS。这是因为有些屏幕对片选信号时序要求严格用软件控制更可靠。如果你不传cs参数模块可能会用硬件CS遇到奇怪的问题时可以检查这里。2.2 配置屏幕参数创建对象后需要配置屏幕的基本参数lcd.configure(320, 240, hmirrorFalse, vflipTrue, bgrFalse)configure方法的参数很重要配置错了屏幕可能显示异常参数说明示例值width屏幕宽度像素3202.0寸屏常见height屏幕高度像素2402.0寸屏常见hmirror水平镜像False正常显示vflip垂直翻转True上下颠倒显示bgr颜色格式FalseRGB565格式重要提示configure方法必须在init之前调用如果顺序反了屏幕初始化会失败。为什么示例代码中vflipTrue呢这是因为不同屏幕的安装方向可能不同。有些屏幕出厂时默认是倒着装的设置vflipTrue就能正过来显示。如果你发现文字上下颠倒了就调整这个参数。关于bgr参数ST7789支持RGB和BGR两种颜色格式。RGB565是红(5位)-绿(6位)-蓝(5位)BGR565是蓝(5位)-绿(6位)-红(5位)。如果颜色显示不对比如红色显示成蓝色就切换这个设置。2.3 初始化屏幕配置完成后初始化屏幕img lcd.init() print(lcd) # 打印LCD对象信息 print(img) # 打印Image对象信息init方法会发送复位信号如果接了RST引脚向ST7789芯片发送初始化命令序列清空屏幕返回一个Image对象这个Image对象就是屏幕的显示缓冲区。我们所有的绘图操作画点、画线、写字都是先在这个缓冲区里进行最后调用show()方法才真正显示到屏幕上。init方法有个可选参数custom_command默认是False。如果设为True模块就不会发送默认的初始化命令需要你自己用command方法发送。这个一般用不到除非你的屏幕比较特殊。3. 基本显示操作3.1 清屏与填充屏幕初始化后咱们先试试最简单的操作——清屏# 方法1使用Image对象的clear方法 img.clear() # 清为黑色 # 方法2使用LCD对象的fill方法填充颜色 lcd.fill(0xFFFF) # 填充白色RGB565的白色是0xFFFF lcd.show() # 将缓冲区内容显示到屏幕这里有个关键点img.clear()、lcd.fill()这些操作都是在缓冲区进行的必须调用lcd.show()才会真正更新到屏幕。你可以把缓冲区想象成画布show()就是把画布贴到屏幕上。RGB565颜色值怎么算一个16位的数前5位是红色中间6位是绿色后5位是蓝色。比如红色0xF800二进制11111 000000 00000绿色0x07E0二进制00000 111111 00000蓝色0x001F二进制00000 000000 11111白色0xFFFF二进制11111 111111 11111黑色0x0000二进制00000 000000 00000如果你觉得算起来麻烦也可以用元组形式(R, G, B)每个分量0-255模块会自动转换lcd.fill((255, 0, 0)) # 填充红色 lcd.fill((0, 255, 0)) # 填充绿色 lcd.fill((0, 0, 255)) # 填充蓝色3.2 绘制像素点画单个像素点有两个方法效果一样# 方法1使用set方法 lcd.set(100, 120, (255, 255, 255)) # 在(100,120)画白点 # 方法2使用pixel方法和set完全一样 lcd.pixel(100, 120, (255, 255, 255)) # 记得刷新显示 lcd.show()获取某个位置的像素颜色color lcd.get(100, 120) print(f位置(100,120)的颜色值是{color:#06x})get和set/pixel操作的都是同一个缓冲区所以你可以先读取某个位置的颜色修改后再写回去实现一些特效。3.3 显示文字显示文字要用到Image对象的方法因为文字绘制功能在image模块里# 清屏 img.clear() # 在位置(0,0)绘制红色文字字号32 img.draw_string_advanced(0, 0, 32, RED: 你好世界~, color(255, 0, 0)) # 在位置(0,40)绘制绿色文字 img.draw_string_advanced(0, 40, 32, GREEN: 你好世界~, color(0, 255, 0)) # 在位置(0,80)绘制蓝色文字 img.draw_string_advanced(0, 80, 32, BLUE: 你好世界~, color(0, 0, 255)) # 显示到屏幕 lcd.show()draw_string_advanced参数说明前两个参数文字起始位置的x、y坐标第三个参数字体大小像素高度第四个参数要显示的字符串color文字颜色可以用元组(R,G,B)格式这里有个细节draw_string_advanced是Image对象的方法不是SPI_LCD对象的方法。因为lcd.init()返回的就是一个Image对象所以我们用img.xxx来调用。3.4 显示图片除了绘制图形还可以显示图片。庐山派的image模块支持加载多种格式的图片# 从文件加载图片 img_data image.Image(/sd/test.jpg) # 将图片显示在屏幕的(50,50)位置 lcd.show(img_data, x50, y50) # 或者用show_image方法效果一样 lcd.show_image(img_data, 50, 50)如果不传图片参数lcd.show()就显示当前的缓冲区内容。如果传了图片参数会直接显示该图片不影响缓冲区。图片显示支持的位置参数可以让你在屏幕任意位置显示图片实现图标、贴图等效果。4. 高级功能与调试技巧4.1 屏幕方向与镜像控制有时候屏幕的显示方向不对或者需要镜像显示比如做镜子效果可以用这些方法# 获取当前配置 print(f水平镜像{lcd.hmirror()}) print(f垂直翻转{lcd.vflip()}) print(fBGR模式{lcd.bgr()}) # 设置新的配置 lcd.hmirror(True) # 启用水平镜像 lcd.vflip(False) # 禁用垂直翻转 lcd.bgr(True) # 切换到BGR颜色格式 # 重新初始化使配置生效 img lcd.init()这些设置会影响整个屏幕的显示方向。比如设置hmirror(True)后原本在左边的像素会显示在右边就像照镜子一样。还有一个get_direction()方法返回ST7789的方向寄存器通常是0x36的值。这个值包含了屏幕旋转、镜像的所有信息高级用户可以通过直接修改这个寄存器值来实现特殊效果。4.2 背光控制如果屏幕有背光控制引脚可以这样调节亮度# 背光最亮 lcd.light(100) # 背光中等亮度 lcd.light(50) # 关闭背光屏幕内容还在只是背光灭了 lcd.light(0) time.sleep(2) lcd.light(100) # 重新打开背光背光值范围是0-1000最暗关闭100最亮。有些屏幕的背光控制是PWM调光有些是简单的开关具体看屏幕规格。4.3 自定义命令发送对于高级用户可能需要直接操作ST7789寄存器# 发送软复位命令 lcd.command(0x01, b) # 发送进入睡眠模式命令 lcd.command(0x10, b) time.sleep(1) # 发送退出睡眠模式命令 lcd.command(0x11, b)command方法第一个参数是命令字节第二个参数是命令数据字节数组。ST7789的数据手册有所有命令的详细说明比如设置扫描方向、伽马校正、电源控制等。4.4 常见问题调试在实际使用中你可能会遇到这些问题问题1屏幕全白或全黑没有任何显示检查电源用万用表量一下VCC和GND之间是不是3.3V检查背光有些屏幕背光需要单独供电或控制检查接线特别是SCLK和MOSI有没有接反降低SPI速度把baudrate从50MHz降到10MHz试试问题2显示花屏、乱码检查屏幕参数configure的宽度高度是否和屏幕一致检查颜色格式试试切换bgr参数检查SPI模式ST7789通常支持模式0和模式3换个模式试试检查DC引脚确保DC引脚在发送命令时为低发送数据时为高问题3显示方向不对调整hmirror和vflip参数检查屏幕物理安装方向有些屏幕是倒着装的问题4显示内容刷新慢SPI速度是否够快可以尝试提高baudrate是否频繁调用lcd.show()可以积累一定变化后再刷新图片是否太大大图片解码和传输需要时间调试时我习惯加一些打印信息print(开始初始化LCD...) lcd SPI_LCD(spi1, pin_dc, pin_cs, pin_rst) print(LCD对象创建成功) lcd.configure(320, 240) print(屏幕配置成功) img lcd.init() print(f屏幕初始化成功缓冲区大小{lcd.width()}x{lcd.height()})这样哪个步骤出问题一目了然。5. 完整示例做一个简易信息显示器最后咱们用一个完整的例子结束。这个例子会在屏幕上显示系统运行时间、循环计数并画一个移动的小方块import time, image from machine import FPIOA, Pin, SPI, SPI_LCD # 初始化硬件 fpioa FPIOA() fpioa.set_function(19, FPIOA.GPIO19) pin_cs Pin(19, Pin.OUT, pullPin.PULL_NONE, drive15) pin_cs.value(1) fpioa.set_function(20, FPIOA.GPIO20) pin_dc Pin(20, Pin.OUT, pullPin.PULL_NONE, drive15) pin_dc.value(1) fpioa.set_function(44, FPIOA.GPIO44, pu1) pin_rst Pin(44, Pin.OUT, pullPin.PULL_UP, drive15) fpioa.set_function(15, fpioa.QSPI0_CLK) fpioa.set_function(16, fpioa.QSPI0_D0) spi1 SPI(1, baudrate1000*1000*30, polarity1, phase1, bits8) # 创建和配置LCD lcd SPI_LCD(spi1, pin_dc, pin_cs, pin_rst) lcd.configure(320, 240, hmirrorFalse, vflipTrue, bgrFalse) img lcd.init() # 背光最亮 lcd.light(100) # 清屏 img.clear() lcd.show() # 移动方块的位置和速度 block_x 0 block_y 100 speed_x 3 speed_y 2 block_size 20 # 循环计数 counter 0 start_time time.ticks_ms() while True: # 清屏用浅灰色背景 img.clear((200, 200, 200)) # 显示标题 img.draw_string_advanced(10, 10, 24, 庐山派LCD信息显示器, color(0, 0, 0)) # 显示运行时间 run_time (time.ticks_ms() - start_time) // 1000 time_str f运行时间: {run_time}秒 img.draw_string_advanced(10, 50, 20, time_str, color(255, 0, 0)) # 显示循环计数 counter 1 count_str f循环计数: {counter} img.draw_string_advanced(10, 80, 20, count_str, color(0, 100, 0)) # 更新方块位置 block_x speed_x block_y speed_y # 边界检测和反弹 if block_x 0 or block_x 320 - block_size: speed_x -speed_x if block_y 100 or block_y 240 - block_size: speed_y -speed_y # 绘制方块 img.draw_rectangle(block_x, block_y, block_size, block_size, color(0, 0, 255), fillTrue) # 显示方块坐标 pos_str f方块位置: ({block_x}, {block_y}) img.draw_string_advanced(10, 110, 18, pos_str, color(0, 0, 0)) # 刷新屏幕 lcd.show() # 控制帧率 time.sleep_ms(50)这个例子用到了清屏、画矩形、显示文字等基本操作还实现了简单的动画效果。你可以在此基础上添加传感器数据显示、按钮交互等功能做出自己的嵌入式GUI应用。实际项目中如果显示内容更新不频繁可以不用每次循环都全屏刷新只更新变化的部分这样效率更高。另外复杂的图形界面可以考虑用LVGL等GUI库SPI_LCD模块可以作为底层驱动。好了关于庐山派SPI_LCD模块的使用就介绍到这里。最关键的就是记住先configure再init绘图操作在缓冲区改完记得show。遇到问题先从电源、接线、SPI参数这几个基础点排查大部分问题都能解决。