本项目基于RP2350开发板,结合128×64分辨率的SSD1306 OLED显示屏,实现了简单的表情图案显示功能。通过MicroPython语言编写程序,并采用Thonny编译器进行开发和调试,完成了硬件驱动与图像显示的整合。
硬件平台
- 核心控制器:RP2350微控制器
- 显示模块:128×64分辨率SSD1306 OLED屏,采用I2C通信接口
- 连接方式:I2C总线,SCL连接GPIO5,SDA连接GPIO4

软件环境
- 开发语言:MicroPython
- 主要库:machine(硬件控制),ssd1306(OLED驱动)
- 开发工具:Thonny IDE,支持代码编写、上传及串口调试
功能实现
- 初始化I2C接口,自动扫描并确认OLED设备地址
- 若打印出的是别的,需要在程序中修改,此处“60”对应的16进制是“0x3C”
- 利用SSD1306_I2C类控制OLED屏幕的显示
- 通过预定义的像素坐标数组(如Sad_lit_pixels)绘制点阵表情图案
- 编写通用绘图函数,实现动态刷新和切换显示内容
- 在主循环中以固定时间间隔显示选定表情,实现持续展示效果
- 完整代码:
代码
import machine
import time
from ssd1306 import SSD1306_I2C
# OLED 参数
WIDTH = 128
HEIGHT = 64
# 初始化 I2C(请确认引脚符合您的接线)
i2c = machine.I2C(0, scl=machine.Pin(5), sda=machine.Pin(4), freq=400000)
print("I2C设备地址列表:", i2c.scan()) # 打印确认设备地址
# OLED地址为0x3C
oled_addr = 0x3C
# 初始化OLED对象,指定地址
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=oled_addr)
# 清屏
oled.fill(0)
# 表情数据定义
Sad_lit_pixels = [
(22, 28), (22, 29), (22, 30), (22, 31), (22, 32), (22, 33),
(23, 28), (23, 29), (23, 30), (23, 31), (23, 32), (23, 33),
(23, 34), (24, 28), (24, 29), (24, 30), (24, 31), (24, 32),
(24, 33), (24, 34), (24, 35), (25, 28), (25, 29), (25, 30),
(25, 31), (25, 32), (25, 33), (25, 34), (25, 35), (25, 36),
(26, 28), (26, 29), (26, 30), (26, 31), (26, 32), (26, 33),
(26, 34), (26, 35), (26, 36), (27, 28), (27, 29), (27, 30),
(27, 31), (27, 32), (27, 33), (27, 34), (27, 35), (27, 36),
(27, 37), (28, 28), (28, 29), (28, 30), (28, 31), (28, 32),
(28, 33), (28, 34), (28, 35), (28, 36), (28, 37), (29, 27),
(29, 28), (29, 29), (29, 30), (29, 31), (29, 32), (29, 33),
(29, 34), (29, 35), (29, 36), (29, 37), (29, 38), (30, 27),
(30, 28), (30, 29), (30, 30), (30, 31), (30, 32), (30, 33),
(30, 34), (30, 35), (30, 36), (30, 37), (30, 38), (31, 27),
(31, 28), (31, 29), (31, 30), (31, 31), (31, 32), (31, 33),
(31, 34), (31, 35), (31, 36), (31, 37), (31, 38), (32, 27),
(32, 28), (32, 29), (32, 30), (32, 31), (32, 32), (32, 33),
(32, 34), (32, 35), (32, 36), (32, 37), (32, 38), (33, 27),
(33, 28), (33, 29), (33, 30), (33, 31), (33, 32), (33, 33),
(33, 34), (33, 35), (33, 36), (33, 37), (33, 38), (34, 27),
(34, 28), (34, 29), (34, 30), (34, 31), (34, 32), (34, 33),
(34, 34), (34, 35), (34, 36), (34, 37), (34, 38), (35, 26),
(35, 27), (35, 28), (35, 29), (35, 30), (35, 31), (35, 32),
(35, 33), (35, 34), (35, 35), (35, 36), (35, 37), (35, 38),
(36, 26), (36, 27), (36, 28), (36, 29), (36, 30), (36, 31),
(36, 32), (36, 33), (36, 34), (36, 35), (36, 36), (36, 37),
(36, 38), (37, 26), (37, 27), (37, 28), (37, 29), (37, 30),
(37, 31), (37, 32), (37, 33), (37, 34), (37, 35), (37, 36),
(37, 37), (37, 38), (38, 26), (38, 27), (38, 28), (38, 29),
(38, 30), (38, 31), (38, 32), (38, 33), (38, 34), (38, 35),
(38, 36), (38, 37), (38, 38), (39, 26), (39, 27), (39, 28),
(39, 29), (39, 30), (39, 31), (39, 32), (39, 33), (39, 34),
(39, 35), (39, 36), (39, 37), (39, 38), (40, 26), (40, 27),
(40, 28), (40, 29), (40, 30), (40, 31), (40, 32), (40, 33),
(40, 34), (40, 35), (40, 36), (40, 37), (40, 38), (41, 25),
(41, 26), (41, 27), (41, 28), (41, 29), (41, 30), (41, 31),
(41, 32), (41, 33), (41, 34), (41, 35), (41, 36), (41, 37),
(41, 38), (42, 25), (42, 26), (42, 27), (42, 28), (42, 29),
(42, 30), (42, 31), (42, 32), (42, 33), (42, 34), (42, 35),
(42, 36), (42, 37), (42, 38), (43, 25), (43, 26), (43, 27),
(43, 28), (43, 29), (43, 30), (43, 31), (43, 32), (43, 33),
(43, 34), (43, 35), (43, 36), (43, 37), (43, 38), (44, 25),
(44, 26), (44, 27), (44, 28), (44, 29), (44, 30), (44, 31),
(44, 32), (44, 33), (44, 34), (44, 35), (44, 36), (44, 37),
(44, 38), (45, 25), (45, 26), (45, 27), (45, 28), (45, 29),
(45, 30), (45, 31), (45, 32), (45, 33), (45, 34), (45, 35),
(45, 36), (45, 37), (45, 38), (46, 25), (46, 26), (46, 27),
(46, 28), (46, 29), (46, 30), (46, 31), (46, 32), (46, 33),
(46, 34), (46, 35), (46, 36), (46, 37), (46, 38), (47, 25),
(47, 26), (47, 27), (47, 28), (47, 29), (47, 30), (47, 31),
(47, 32), (47, 33), (47, 34), (47, 35), (47, 36), (47, 37),
(47, 38), (48, 24), (48, 25), (48, 26), (48, 27), (48, 28),
(48, 29), (48, 30), (48, 31), (48, 32), (48, 33), (48, 34),
(48, 35), (48, 36), (48, 37), (48, 38), (49, 24), (49, 25),
(49, 26), (49, 27), (49, 28), (49, 29), (49, 30), (49, 31),
(49, 32), (49, 33), (49, 34), (49, 35), (49, 36), (49, 37),
(49, 38), (50, 24), (50, 25), (50, 26), (50, 27), (50, 28),
(50, 29), (50, 30), (50, 31), (50, 32), (50, 33), (50, 34),
(50, 35), (50, 36), (50, 37), (50, 38), (51, 24), (51, 25),
(51, 26), (51, 27), (51, 28), (51, 29), (51, 30), (51, 31),
(51, 32), (51, 33), (51, 34), (51, 35), (51, 36), (51, 37),
(51, 38), (52, 24), (52, 25), (52, 26), (52, 27), (52, 28),
(52, 29), (52, 30), (52, 31), (52, 32), (52, 33), (52, 34),
(52, 35), (52, 36), (52, 37), (52, 38), (53, 24), (53, 25),
(53, 26), (53, 27), (53, 28), (53, 29), (53, 30), (53, 31),
(53, 32), (53, 33), (53, 34), (53, 35), (53, 36), (53, 37),
(53, 38), (54, 23), (54, 24), (54, 25), (54, 26), (54, 27),
(54, 28), (54, 29), (54, 30), (54, 31), (54, 32), (54, 33),
(54, 34), (54, 35), (54, 36), (54, 37), (55, 23), (55, 24),
(55, 25), (55, 26), (55, 27), (55, 28), (55, 29), (55, 30),
(55, 31), (55, 32), (55, 33), (55, 34), (55, 35), (55, 36),
(55, 37), (56, 23), (56, 24), (56, 25), (56, 26), (56, 27),
(56, 28), (56, 29), (56, 30), (56, 31), (56, 32), (56, 33),
(56, 34), (56, 35), (56, 36), (57, 23), (57, 24), (57, 25),
(57, 26), (57, 27), (57, 28), (57, 29), (57, 30), (57, 31),
(57, 32), (57, 33), (57, 34), (57, 35), (57, 36), (57, 37),
(57, 38), (58, 23), (58, 24), (58, 25), (58, 26), (58, 27),
(58, 28), (58, 29), (58, 30), (58, 31), (58, 32), (58, 33),
(58, 34), (59, 23), (59, 24), (59, 25), (59, 26), (59, 27),
(59, 28), (59, 29), (59, 30), (59, 31), (59, 32), (59, 33),
(60, 23), (60, 24), (60, 25), (60, 26), (60, 27), (60, 28),
(60, 29), (60, 30), (60, 31), (60, 32), (68, 24), (68, 25),
(68, 26), (68, 27), (68, 28), (68, 29), (68, 30), (68, 31),
(68, 32), (69, 23), (69, 24), (69, 25), (69, 26), (69, 27),
(69, 28), (69, 29), (69, 30), (69, 31), (69, 32), (69, 33),
(69, 34), (70, 23), (70, 24), (70, 25), (70, 26), (70, 27),
(70, 28), (70, 29), (70, 30), (70, 31), (70, 32), (70, 33),
(70, 34), (70, 35), (71, 23), (71, 24), (71, 25), (71, 26),
(71, 27), (71, 28), (71, 29), (71, 30), (71, 31), (71, 32),
(71, 33), (71, 34), (71, 35), (71, 36), (72, 23), (72, 24),
(72, 25), (72, 26), (72, 27), (72, 28), (72, 29), (72, 30),
(72, 31), (72, 32), (72, 33), (72, 34), (72, 35), (72, 36),
(73, 23), (73, 24), (73, 25), (73, 26), (73, 27), (73, 28),
(73, 29), (73, 30), (73, 31), (73, 32), (73, 33), (73, 34),
(73, 35), (73, 36), (73, 37), (74, 23), (74, 24), (74, 25),
(74, 26), (74, 27), (74, 28), (74, 29), (74, 30), (74, 31),
(74, 32), (74, 33), (74, 34), (74, 35), (74, 36), (74, 37),
(75, 23), (75, 24), (75, 25), (75, 26), (75, 27), (75, 28),
(75, 29), (75, 30), (75, 31), (75, 32), (75, 33), (75, 34),
(75, 35), (75, 36), (75, 37), (75, 38), (76, 24), (76, 25),
(76, 26), (76, 27), (76, 28), (76, 29), (76, 30), (76, 31),
(76, 32), (76, 33), (76, 34), (76, 35), (76, 36), (76, 37),
(76, 38), (77, 24), (77, 25), (77, 26), (77, 27), (77, 28),
(77, 29), (77, 30), (77, 31), (77, 32), (77, 33), (77, 34),
(77, 35), (77, 36), (77, 37), (77, 38), (78, 24), (78, 25),
(78, 26), (78, 27), (78, 28), (78, 29), (78, 30), (78, 31),
(78, 32), (78, 33), (78, 34), (78, 35), (78, 36), (78, 37),
(78, 38), (79, 24), (79, 25), (79, 26), (79, 27), (79, 28),
(79, 29), (79, 30), (79, 31), (79, 32), (79, 33), (79, 34),
(79, 35), (79, 36), (79, 37), (79, 38), (80, 24), (80, 25),
(80, 26), (80, 27), (80, 28), (80, 29), (80, 30), (80, 31),
(80, 32), (80, 33), (80, 34), (80, 35), (80, 36), (80, 37),
(80, 38), (81, 24), (81, 25), (81, 26), (81, 27), (81, 28),
(81, 29), (81, 30), (81, 31), (81, 32), (81, 33), (81, 34),
(81, 35), (81, 36), (81, 37), (81, 38), (82, 25), (82, 26),
(82, 27), (82, 28), (82, 29), (82, 30), (82, 31), (82, 32),
(82, 33), (82, 34), (82, 35), (82, 36), (82, 37), (82, 38),
(83, 25), (83, 26), (83, 27), (83, 28), (83, 29), (83, 30),
(83, 31), (83, 32), (83, 33), (83, 34), (83, 35), (83, 36),
(83, 37), (83, 38), (84, 25), (84, 26), (84, 27), (84, 28),
(84, 29), (84, 30), (84, 31), (84, 32), (84, 33), (84, 34),
(84, 35), (84, 36), (84, 37), (84, 38), (85, 25), (85, 26),
(85, 27), (85, 28), (85, 29), (85, 30), (85, 31), (85, 32),
(85, 33), (85, 34), (85, 35), (85, 36), (85, 37), (85, 38),
(86, 25), (86, 26), (86, 27), (86, 28), (86, 29), (86, 30),
(86, 31), (86, 32), (86, 33), (86, 34), (86, 35), (86, 36),
(86, 37), (86, 38), (87, 25), (87, 26), (87, 27), (87, 28),
(87, 29), (87, 30), (87, 31), (87, 32), (87, 33), (87, 34),
(87, 35), (87, 36), (87, 37), (87, 38), (88, 26), (88, 27),
(88, 28), (88, 29), (88, 30), (88, 31), (88, 32), (88, 33),
(88, 34), (88, 35), (88, 36), (88, 37), (88, 38), (89, 26),
(89, 27), (89, 28), (89, 29), (89, 30), (89, 31), (89, 32),
(89, 33), (89, 34), (89, 35), (89, 36), (89, 37), (89, 38),
(90, 26), (90, 27), (90, 28), (90, 29), (90, 30), (90, 31),
(90, 32), (90, 33), (90, 34), (90, 35), (90, 36), (90, 37),
(90, 38), (91, 26), (91, 27), (91, 28), (91, 29), (91, 30),
(91, 31), (91, 32), (91, 33), (91, 34), (91, 35), (91, 36),
(91, 37), (91, 38), (92, 26), (92, 27), (92, 28), (92, 29),
(92, 30), (92, 31), (92, 32), (92, 33), (92, 34), (92, 35),
(92, 36), (92, 37), (92, 38), (93, 26), (93, 27), (93, 28),
(93, 29), (93, 30), (93, 31), (93, 32), (93, 33), (93, 34),
(93, 35), (93, 36), (93, 37), (93, 38), (94, 27), (94, 28),
(94, 29), (94, 30), (94, 31), (94, 32), (94, 33), (94, 34),
(94, 35), (94, 36), (94, 37), (94, 38), (95, 27), (95, 28),
(95, 29), (95, 30), (95, 31), (95, 32), (95, 33), (95, 34),
(95, 35), (95, 36), (95, 37), (95, 38), (96, 27), (96, 28),
(96, 29), (96, 30), (96, 31), (96, 32), (96, 33), (96, 34),
(96, 35), (96, 36), (96, 37), (96, 38), (97, 27), (97, 28),
(97, 29), (97, 30), (97, 31), (97, 32), (97, 33), (97, 34),
(97, 35), (97, 36), (97, 37), (97, 38), (98, 27), (98, 28),
(98, 29), (98, 30), (98, 31), (98, 32), (98, 33), (98, 34),
(98, 35), (98, 36), (98, 37), (98, 38), (99, 27), (99, 28),
(99, 29), (99, 30), (99, 31), (99, 32), (99, 33), (99, 34),
(99, 35), (99, 36), (99, 37), (99, 38), (100, 28), (100, 29),
(100, 30), (100, 31), (100, 32), (100, 33), (100, 34), (100, 35),
(100, 36), (100, 37), (100, 38), (101, 28), (101, 29), (101, 30),
(101, 31), (101, 32), (101, 33), (101, 34), (101, 35), (101, 36),
(101, 37), (102, 28), (102, 29), (102, 30), (102, 31), (102, 32),
(102, 33), (102, 34), (102, 35), (102, 36), (102, 37), (103, 28),
(103, 29), (103, 30), (103, 31), (103, 32), (103, 33), (103, 34),
(103, 35), (103, 36), (104, 28), (104, 29), (104, 30), (104, 31),
(104, 32), (104, 33), (104, 34), (104, 35), (105, 28), (105, 29),
(105, 30), (105, 31), (105, 32), (105, 33), (105, 34), (106, 28),
(106, 29), (106, 30), (106, 31), (106, 32)
]
# 定义显示带Y轴偏移的表情函数
def display_emoj_with_offset(pixel_array, y_offset):
oled.fill(0) # 清屏
for (x, y) in pixel_array:
new_y = y + y_offset
# 边界检查,防止越界绘制
if 0 <= new_y < HEIGHT and 0 <= x < WIDTH:
oled.pixel(x, new_y, 1)
oled.show()
# 定义上下移动动画函数
def display_emoj_up_and_down(pixel_array):
animation_steps = 5 # 上下移动像素数
frame_delay = 0.1 # 每帧延迟秒数(100ms)
# 向上移动动画
for offset in range(0, -animation_steps - 1, -1):
display_emoj_with_offset(pixel_array, offset)
time.sleep(frame_delay)
# 向下移动动画
for offset in range(-animation_steps, animation_steps + 1):
display_emoj_with_offset(pixel_array, offset)
time.sleep(frame_delay)
# 回到中间位置
for offset in range(animation_steps, -1, -1):
display_emoj_with_offset(pixel_array, offset)
time.sleep(frame_delay)
# 中心位置停留2秒
display_emoj_with_offset(pixel_array, 0)
time.sleep(2)
# 主循环
while True:
display_emoj_up_and_down(Sad_lit_pixels)
"""
视频效果:
具体效果是表情会上下晃动最后回到中间位置。
其它代码:ssd1306.py
代码
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
from micropython import const
import framebuf
# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xA4)
SET_NORM_INV = const(0xA6)
SET_DISP = const(0xAE)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xA0)
SET_MUX_RATIO = const(0xA8)
SET_COM_OUT_DIR = const(0xC0)
SET_DISP_OFFSET = const(0xD3)
SET_COM_PIN_CFG = const(0xDA)
SET_DISP_CLK_DIV = const(0xD5)
SET_PRECHARGE = const(0xD9)
SET_VCOM_DESEL = const(0xDB)
SET_CHARGE_PUMP = const(0x8D)
# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1306(framebuf.FrameBuffer):
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
self.buffer = bytearray(self.pages * self.width)
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
self.init_display()
def init_display(self):
for cmd in (
SET_DISP | 0x00, # off
# address setting
SET_MEM_ADDR,
0x00, # horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO,
self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET,
0x00,
SET_COM_PIN_CFG,
0x02 if self.width > 2 * self.height else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV,
0x80,
SET_PRECHARGE,
0x22 if self.external_vcc else 0xF1,
SET_VCOM_DESEL,
0x30, # 0.83*Vcc
# display
SET_CONTRAST,
0xFF, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
# charge pump
SET_CHARGE_PUMP,
0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01,
): # on
self.write_cmd(cmd)
self.fill(0)
self.show()
def poweroff(self):
self.write_cmd(SET_DISP | 0x00)
def poweron(self):
self.write_cmd(SET_DISP | 0x01)
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)
def invert(self, invert):
self.write_cmd(SET_NORM_INV | (invert & 1))
def show(self):
x0 = 0
x1 = self.width - 1
if self.width == 64:
# displays with width of 64 pixels are shifted by 32
x0 += 32
x1 += 32
self.write_cmd(SET_COL_ADDR)
self.write_cmd(x0)
self.write_cmd(x1)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_data(self.buffer)
class SSD1306_I2C(SSD1306):
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
self.write_list = [b"\x40", None] # Co=0, D/C#=1
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.temp[0] = 0x80 # Co=1, D/C#=0
self.temp[1] = cmd
self.i2c.writeto(self.addr, self.temp)
def write_data(self, buf):
self.write_list[1] = buf
self.i2c.writevto(self.addr, self.write_list)
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
import time
self.res(1)
time.sleep_ms(1)
self.res(0)
time.sleep_ms(10)
self.res(1)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(0)
self.cs(0)
self.spi.write(bytearray([cmd]))
self.cs(1)
def write_data(self, buf):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(1)
self.cs(0)
self.spi.write(buf)
self.cs(1)
评论