Skip to content

Instantly share code, notes, and snippets.

@dongfg
Last active December 18, 2025 14:01
Show Gist options
  • Select an option

  • Save dongfg/245f2276f15b47ebcd7f953104feed89 to your computer and use it in GitHub Desktop.

Select an option

Save dongfg/245f2276f15b47ebcd7f953104feed89 to your computer and use it in GitHub Desktop.
Raspberry Pi ST7796 SPI Demo
import time
import spidev
import RPi.GPIO as GPIO
from PIL import Image, ImageDraw, ImageFont
# --- 配置引脚 (BCM 编码) ---
DC_PIN = 24
RST_PIN = 25
BL_PIN = 17
SPI_BUS = 0
SPI_DEVICE = 0
# --- ST7796 初始化命令 ---
def init_display(spi):
def send_cmd(cmd):
GPIO.output(DC_PIN, GPIO.LOW)
spi.writebytes([cmd])
def send_data(data):
GPIO.output(DC_PIN, GPIO.HIGH)
spi.writebytes([data])
# --- 硬件复位 ---
GPIO.output(RST_PIN, GPIO.HIGH)
time.sleep(0.01)
GPIO.output(RST_PIN, GPIO.LOW)
time.sleep(0.01)
GPIO.output(RST_PIN, GPIO.HIGH)
time.sleep(0.12)
# --- 通用初始化 ---
send_cmd(0x01) # Software Reset
time.sleep(0.12)
send_cmd(0x11) # Sleep Out
time.sleep(0.12)
send_cmd(0xF0)
send_data(0xC3)
send_cmd(0xF0)
send_data(0x96)
# ★★★ 竖屏 左转 90 度竖屏 ★★★
send_cmd(0x36)
send_data(0x88)
send_cmd(0x3A)
send_data(0x55) # 16bit
send_cmd(0xB4)
send_data(0x01)
send_cmd(0xB7)
send_data(0xC6)
send_cmd(0xE8)
send_data(0x40)
send_data(0x8A)
send_data(0x00)
send_data(0x00)
send_data(0x29)
send_data(0x19)
send_data(0xA5)
send_data(0x33)
send_cmd(0x29) # Display ON
time.sleep(0.05)
# --- 竖屏图像写入 ---
def display_image(spi, image):
# ★★★ 竖屏分辨率(右转90度)★★★
w, h = 320, 480 # 替换原480,320
# 调整输出图像
img = image.resize((w, h), Image.BICUBIC)
img_raw = img.convert('RGB')
pixels = list(img_raw.getdata())
# 转换为 RGB565
buffer = []
for r, g, b in pixels:
val = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)
buffer.append(val >> 8)
buffer.append(val & 0xFF)
# 设置地址窗口
def cmd(c):
GPIO.output(DC_PIN, GPIO.LOW)
spi.writebytes([c])
def data(arr):
GPIO.output(DC_PIN, GPIO.HIGH)
spi.writebytes(arr)
# Column 地址(竖屏列范围:0~319)
cmd(0x2A)
data([0, 0, (w - 1) >> 8, (w - 1) & 0xFF])
# Page 地址(竖屏行范围:0~479)
cmd(0x2B)
data([0, 0, (h - 1) >> 8, (h - 1) & 0xFF])
# Memory Write
cmd(0x2C)
GPIO.output(DC_PIN, GPIO.HIGH)
# 分块写入
chunk = 4096
for i in range(0, len(buffer), chunk):
spi.writebytes(buffer[i:i + chunk])
# --- 主程序 ---
def main():
# GPIO 初始化
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(DC_PIN, GPIO.OUT)
GPIO.setup(RST_PIN, GPIO.OUT)
GPIO.setup(BL_PIN, GPIO.OUT)
GPIO.output(BL_PIN, GPIO.HIGH)
# SPI 初始化
spi = spidev.SpiDev()
spi.open(SPI_BUS, SPI_DEVICE)
spi.max_speed_hz = 40000000
spi.mode = 0b00
try:
print("Initializing Display...")
init_display(spi)
print("Drawing Image...")
# ★★★ 竖屏画布 320×480 ★★★
image = Image.new("RGB", (320, 480), "#008080")
draw = ImageDraw.Draw(image)
# 配置参数
block_size = 80 # 色块尺寸80×80
cols = 4 # 每行4个色块(4×80=320)
rows = 6 # 共6行(6×80=480)
# 定义两个交替的色块颜色(可自行修改)
color1 = (50, 150, 250) # 浅蓝色
color2 = (250, 100, 50) # 橙红色
# 字体配置(适配80×80色块的居中数字)
try:
font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 40
)
except:
font = ImageFont.load_default(size=40)
# 循环绘制4列×6行=24个色块
num = 1 # 数字从1开始
for row in range(rows):
for col in range(cols):
# 计算当前色块的坐标(左上角/右下角)
x0 = col * block_size
y0 = row * block_size
x1 = x0 + block_size
y1 = y0 + block_size
# 交替选择色块颜色(奇数数字用color1,偶数用color2)
bg_color = color1 if (row + col) % 2 == 0 else color2
# 绘制色块
draw.rectangle((x0, y0, x1, y1), fill=bg_color)
# 计算数字居中坐标(基于文字边界框)
text = str(num)
# 获取文字的宽高(bbox返回:左、上、右、下)
bbox = draw.textbbox((0, 0), text, font=font)
text_w = bbox[2] - bbox[0]
text_h = bbox[3] - bbox[1]
# 计算居中位置
text_x = x0 + (block_size - text_w) // 2
text_y = y0 + (block_size - text_h) // 2
# 绘制数字(白色字体,对比明显)
draw.text((text_x, text_y), text, fill=(255, 255, 255), font=font)
# 数字自增
num += 1
# 显示绘制好的图像
display_image(spi, image)
print("Done!")
except KeyboardInterrupt:
GPIO.cleanup()
spi.close()
if __name__ == "__main__":
main()
@dongfg
Copy link
Author

dongfg commented Dec 18, 2025

demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment