Last active
December 18, 2025 14:01
-
-
Save dongfg/245f2276f15b47ebcd7f953104feed89 to your computer and use it in GitHub Desktop.
Raspberry Pi ST7796 SPI Demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() |
Author
dongfg
commented
Dec 18, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment