当前位置: 首页 > news >正文

MicroPython测试 ESP32-S3 + 8MB PSRAM + ST7789 屏幕显示GIF动画

1.准备一个GIF动画文件,可以去百度图片里随便搜索一个下载,然后在电脑上把 GIF 拆成一堆.raw二进制文件上传。可以用我下面提供的这个python代码进行转换。

# convert_gif.py (在电脑上运行) from PIL import Image import os def convert_gif_to_raw(gif_path, output_folder="raw_frames"): if not os.path.exists(output_folder): os.makedirs(output_folder) print(f"Opening {gif_path}...") im = Image.open(gif_path) # 调整大小为 240x240 (根据你的屏幕) target_size = (240, 240) frame_count = 0 try: while True: # 转换为 RGB rgb_im = im.convert('RGB') rgb_im = rgb_im.resize(target_size, Image.Resampling.LANCZOS) # 转换为 RGB565 二进制数据 data = bytearray() for y in range(target_size[1]): for x in range(target_size[0]): r, g, b = rgb_im.getpixel((x, y)) # RGB888 to RGB565 color = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3) data.append((color >> 8) & 0xFF) data.append(color & 0xFF) # 保存为 raw 文件 filename = f"{output_folder}/frame_{frame_count:03d}.raw" with open(filename, 'wb') as f: f.write(data) print(f"Saved {filename} ({len(data)} bytes)") frame_count += 1 try: im.seek(im.tell() + 1) except EOFError: break except Exception as e: print(f"Error: {e}") print(f"Done! Converted {frame_count} frames.") if __name__ == "__main__": #我测试的gif文件名称:animation.gif convert_gif_to_raw("animation.gif")

运行结果:

生成好的文件放在指定的目录下的:

例如我这里是放在了:raw_frames 目录下。

2.将生成好的 raw_frames 通过Thonny上传到esp32 s3 的 MicroPython 根目录,如下图所示:

3.在Thonny里的 MicroPython 设备下面新建一个文件,例如我这里创建的 GIF动画测试.py文件,复制粘贴我下面的代码,运行,观察屏幕是否有正常显示动画效果。

import machine import time import framebuf import os import gc # ================= 配置 ================= PIN_SCL = 9 PIN_SDA = 8 PIN_CS = 5 PIN_DC = 6 PIN_RST = 7 PIN_BL = 4 SCREEN_W = 240 SCREEN_H = 240 # 👇 修改这里:设置子目录名称 FRAME_DIR = "raw_frames" # 文件夹名字 FRAME_PREFIX = "frame_" FRAME_EXT = ".raw" # ======================================= # --- 屏幕驱动类 (保持不变) --- class ST7789: def __init__(self, spi, cs, dc, rst, w, h): self.spi = spi; self.cs = cs; self.dc = dc; self.rst = rst self.w = w; self.h = h for p in [cs, dc, rst]: p.init(machine.Pin.OUT, value=1) rst.value(0); time.sleep_ms(10); rst.value(1); time.sleep_ms(120) cmds = [(0x01,[]),(0x11,[]),(0x36,[0x00]),(0x3A,[0x05]),(0xB2,[0x0C,0x0C,0x00,0x33,0x33]), (0xB7,[0x35]),(0xBB,[0x19]),(0xC0,[0x2C]),(0xC2,[0x01]),(0xC3,[0x12]),(0xC4,[0x20]), (0xC6,[0x0F]),(0xD0,[0xA4,0xA1]), (0xE0,[0xD0,0x00,0x02,0x07,0x0A,0x28,0x32,0x44,0x42,0x06,0x0E,0x12,0x14,0x17]), (0xE1,[0xD0,0x00,0x02,0x07,0x0A,0x28,0x31,0x54,0x47,0x0E,0x1C,0x17,0x1B,0x1E]), (0x21,[]),(0x29,[])] for cmd, data in cmds: self._tx(cmd, False) if data: self._tx(bytes(data), True) if cmd == 0x11: time.sleep_ms(120) self.set_window(0, 0, w-1, h-1) def _tx(self, data, is_data=False): self.dc(is_data); self.cs(0) if isinstance(data, int): data = bytes([data]) self.spi.write(data); self.cs(1) def set_window(self, x0, y0, x1, y1): self._tx(0x2A, False); self._tx(bytes([x0>>8, x0&0xff, x1>>8, x1&0xff]), True) self._tx(0x2B, False); self._tx(bytes([y0>>8, y0&0xff, y1>>8, y1&0xff]), True) self._tx(0x2C, False) def write(self, buffer): self.dc(1); self.cs(0); self.spi.write(buffer); self.cs(1) # --- 主程序 --- print("Initializing...") spi = machine.SPI(1, baudrate=90000000, polarity=0, phase=0, sck=machine.Pin(PIN_SCL), mosi=machine.Pin(PIN_SDA)) lcd = ST7789(spi, machine.Pin(PIN_CS), machine.Pin(PIN_DC), machine.Pin(PIN_RST), SCREEN_W, SCREEN_H) machine.Pin(PIN_BL, machine.Pin.OUT).value(1) # 1. 分配 PSRAM 双缓冲 print("Allocating PSRAM buffers...") buf1 = bytearray(SCREEN_W * SCREEN_H * 2) buf2 = bytearray(SCREEN_W * SCREEN_H * 2) fb1 = framebuf.FrameBuffer(buf1, SCREEN_W, SCREEN_H, framebuf.RGB565) fb2 = framebuf.FrameBuffer(buf2, SCREEN_W, SCREEN_H, framebuf.RGB565) print(f"Free RAM: {gc.mem_free()/1024:.1f} KB") # 2. 👇 修改这里:扫描子目录下的文件 full_dir_path = "/" + FRAME_DIR # 构建完整路径,例如 "/frames" # 检查目录是否存在 if full_dir_path not in ["/" + d for d in os.listdir()]: # 尝试直接列出目录内容来验证,如果报错说明目录不存在 try: files_in_dir = os.listdir(full_dir_path) except OSError: raise RuntimeError(f"Directory '{FRAME_DIR}' not found! Please create it and upload files.") else: files_in_dir = os.listdir(full_dir_path) # 筛选出 .raw 文件 frame_files = sorted([f for f in files_in_dir if f.startswith(FRAME_PREFIX) and f.endswith(FRAME_EXT)]) TOTAL_FRAMES = len(frame_files) if TOTAL_FRAMES == 0: raise RuntimeError(f"No frames found in '{FRAME_DIR}'! Please upload {FRAME_PREFIX}*{FRAME_EXT} files there.") print(f"Found {TOTAL_FRAMES} frames in '{FRAME_DIR}'. Starting playback...") frame_idx = 0 fps_count = 0 start_time = time.ticks_ms() while True: t_start = time.ticks_ms() # 选择缓冲区 idx = frame_idx % 2 buf = buf1 if idx == 0 else buf2 # 3. 👇 修改这里:读取时加上目录路径 fname_relative = frame_files[frame_idx % TOTAL_FRAMES] fname_full = full_dir_path + "/" + fname_relative # 例如:"/frames/frame_000.raw" try: with open(fname_full, 'rb') as f: f.readinto(buf) except OSError as e: print(f"Error reading {fname_full}: {e}") # 可以选择 break 或者跳过 break # 4. 发送到屏幕 lcd.set_window(0, 0, SCREEN_W-1, SCREEN_H-1) lcd.write(buf) frame_idx += 1 fps_count += 1 # 计算 FPS elapsed = time.ticks_diff(time.ticks_ms(), start_time) if elapsed >= 1000: print(f"FPS: {fps_count}") fps_count = 0 start_time = time.ticks_ms()

运行结果:

显示效果:

备注:由于我的gif尺寸问题,屏幕地方是空白的,这块优化下即可

http://www.jsqmd.com/news/450944/

相关文章:

  • Bidili Generator案例分享:SDXL+LoRA在游戏角色设计中的应用
  • 雪女-斗罗大陆-造相Z-Turbo硬件选择指南:GPU显存、CPU与内存配置推荐
  • 方舟服务器管理不再难:Ark Server Tools如何解决3大运维痛点?
  • 告别重复造轮子:用快马平台AI一键生成点餐小程序核心模块
  • Qwen3-4B模型解析Java八股文:核心概念与高频考点精讲
  • 三轴传感器IIS3DWB适合的应用 场景有哪些?
  • cv_unet_image-colorization模型蒸馏实践:打造轻量级移动端上色模型
  • 设计资产无缝迁移:Figma-HTML双向转换工具的全栈解决方案
  • Pentaho Kettle 企业级数据集成平台构建指南:场景化实施与架构优化
  • 比迪丽WebUI界面详解:左右分区逻辑、正向/负向提示词协同机制
  • bge-large-zh-v1.5效果展示:高维中文语义向量生成真实案例集
  • pkNX宝可梦编辑器进阶指南:从基础操作到深度定制
  • SDXL 1.0电影级绘图工坊企业案例:品牌VI系统扩展图形AI生成
  • Mac M1用户必看:UTM免费安装Win11 ARM虚拟机全攻略(附高清优化技巧)
  • RedisDesktopManager:全方位提升Redis数据库管理效率的开源解决方案
  • RedisDesktopManager:全类型Redis数据管理效率提升80%的可视化工具
  • 墨语灵犀Hunyuan-MT知识蒸馏:小模型保持33语种能力的轻量化实践
  • Ollama助力Qwen2.5-VL:一键部署多模态AI,图片识别超简单
  • 如何守护3DS游戏存档:JKSM的全方位数据安全方案
  • C++语音识别模块开发指南:从零构建到性能优化
  • VibeVoice安全性说明:防止语音克隆滥用的技术措施
  • 电力电子工程师必看:用平均电流控制法优化Boost PFC的5个关键步骤
  • 折腾笔记[45]-导入及导出ollama模型
  • cv_resnet101_face-detection模型与Java八股文精粹:深入JVM内存管理与多线程调用
  • 智能工作流调度:重新定义多任务处理的效率革命
  • BAAI/bge-m3企业应用:文档去重与知识库语义验证方案
  • 效率工具重塑设计协作:如何通过HTML转Figma实现工作流无缝迁移
  • CosyVoice入门必看:C语言基础概念语音教学课件生成
  • 高效管理《方舟:生存进化》服务器的开源自动化运维工具全解析
  • 游戏存档丢失怎么办?3DS玩家必备的JKSM工具拯救指南