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

2025 年最新树莓派 Pico 连接 OLED 显示字模汉字详细教程

OLED 概述

OLED(Organic Light-Emitting Diode,有机发光二极管)是一种基于有机材料的发光技术,通过电流驱动有机薄膜发光,具有自发光、高对比度、柔性可弯曲等特点。

在这里插入图片描述

4 针脚 OLED 硬件电路如图所示,GND 接 GND,VCC 接 3.3V,给 OLED 供电,剩下的是 SCL 和 SDA 是 I2C 的通信引脚,需要接在单片机 I2C 通信的引脚上,由于驱动函数模块用的是 GPIO 口模拟的 I2C 通信,所以这两个端口就可以接在任意的 GPIO 口上。

在这里插入图片描述
附加:Arduino 连接

在这里插入图片描述

SCL / SDA

SCL 和 SDA 是 I²C(Inter-Integrated Circuit,集成电路总线) 通信协议中的两条关键信号线,用于连接主设备(Master)和从设备(Slave)进行数据交换。

SCL(Serial Clock Line,串行时钟线)

由主设备控制,用于同步数据传输的时钟信号。决定数据传输的速率(频率通常为 100kHz(标准模式)、400kHz(快速模式)、1MHz(高速模式)或更高)。

SDA(Serial Data Line,串行数据线)

双向数据线,用于主从设备之间的实际数据传输。数据在SCL的上升沿或下降沿被采样(具体取决于协议模式)。

数据传输概述

主机写数据到从机
在这里插入图片描述

主机由从机中读数据
在这里插入图片描述

12C 通讯复合格式
在这里插入图片描述
其中 S 表示由主机的 I2C 接口产生的传输起始信号(S),这时连接到 I2C 总线上的所有从机都会接收到这个信号。 起始信号产生后,所有从机就开始等待主机紧接下来广播的从机地址信号 (SLAVE_ADDRESS)。

在 I2C 总线上,每个设备的地址都是唯一的,当主机广播的地址与某个设备地址相同时,根据 I2C 协议,这个从机地址可以是 7 位或 10 位。 在地址位之后,是传输方向的选择位,该位为 0 即主机向从机写数据。该位为 1 时,则相反,即主机由从机读数据。在此传输后选择数据寄存器和命令寄存器两种,传输到对应寄存器表示要传输数据 / 命令。

从机接收到匹配的地址后,主机或从机会返回一个应答 (ACK) 或非应答 (NACK) 信号, 只有接收到应答信号后,主机才能继续发送或接收数据。重复这个过程,可以向从机传输 N 个数据, 这个 N 没有大小限制

① 起始信号与停止信号 ② 应答信号 ③ 数据的有效性 ④ 数据传输

SSD1306

# MicroPython SSD1306 OLED driver, I2C and SPI interfacesfrom 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 = widthself.height = heightself.external_vcc = external_vccself.pages = self.height // 8self.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 settingSET_MEM_ADDR,0x00,  # horizontal# resolution and layoutSET_DISP_START_LINE | 0x00,SET_SEG_REMAP | 0x01,  # column addr 127 mapped to SEG0SET_MUX_RATIO,self.height - 1,SET_COM_OUT_DIR | 0x08,  # scan from COM[N] to COM0SET_DISP_OFFSET,0x00,SET_COM_PIN_CFG,0x02 if self.width > 2 * self.height else 0x12,# timing and driving schemeSET_DISP_CLK_DIV,0x80,SET_PRECHARGE,0x22 if self.external_vcc else 0xF1,SET_VCOM_DESEL,0x30,  # 0.83*Vcc# displaySET_CONTRAST,0xFF,  # maximumSET_ENTIRE_ON,  # output follows RAM contentsSET_NORM_INV,  # not inverted# charge pumpSET_CHARGE_PUMP,0x10 if self.external_vcc else 0x14,SET_DISP | 0x01,):  # onself.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 = 0x1 = self.width - 1if self.width == 64:# displays with width of 64 pixels are shifted by 32x0 += 32x1 += 32self.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 = i2cself.addr = addrself.temp = bytearray(2)self.write_list = [b"\x40", None]  # Co=0, D/C#=1super().__init__(width, height, external_vcc)def write_cmd(self, cmd):self.temp[0] = 0x80  # Co=1, D/C#=0self.temp[1] = cmdself.i2c.writeto(self.addr, self.temp)def write_data(self, buf):self.write_list[1] = bufself.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 * 1024dc.init(dc.OUT, value=0)res.init(res.OUT, value=0)cs.init(cs.OUT, value=1)self.spi = spiself.dc = dcself.res = resself.cs = csimport timeself.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)

SSD1306_I2C

import machine
import ssd1306i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
oled.fill(1)
oled.show()oled.fill(0)
oled.show()oled.text("Hello World!", 0, 9, 1)
oled.text("Huanxingshouwan!", 0, 18, 1)
oled.show()

字模编码

推荐字模编码网站:https://www.23bei.com/tool/216.html

输出格式:C51
数据排列:从左到右从上到下
取模方式:横向8点左高位
黑白取反:正常
字体种类:[HZK1616宋体]
import machine
import ssd1306
import framebufi2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400_000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)oled.fill(1)
oled.show()oled.fill(0)
oled.show()fontlib = {"唤": [0x00,0x40,0x08,0x40,0x7C,0xF8,0x49,0x10,0x4A,0x24,0x49,0xFE,0x49,0x24,0x49,0x24,
0x49,0x24,0x49,0x24,0x4F,0xFE,0x78,0x20,0x48,0x50,0x00,0x88,0x01,0x06,0x06,0x04],"醒": [0x04,0x04,0xFE,0xFE,0x28,0x84,0x28,0xFC,0xFE,0x84,0xAA,0xFC,0xAA,0x20,0xAE,0xA0,
0xC2,0xFC,0x83,0x20,0x82,0x20,0xFE,0xFC,0x82,0x20,0x82,0x24,0xFF,0xFE,0x82,0x00],"手": [0x00,0x10,0x00,0xF8,0x7F,0x00,0x01,0x00,0x01,0x10,0x3F,0xF8,0x01,0x00,0x01,0x00,
0x01,0x04,0xFF,0xFE,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00],"腕": [0x08,0x40,0x7C,0x20,0x4B,0xFE,0x4A,0x02,0x4D,0x04,0x79,0xDC,0x49,0x54,0x49,0x54,
0x4A,0x54,0x7A,0x54,0x4D,0x5C,0x48,0x94,0x48,0x90,0x49,0x12,0x4A,0x0E,0x9C,0x00]
}def text_hz(hz, x, y):zm = bytearray(fontlib[hz])buf = framebuf.FrameBuffer(zm, 16, 16, framebuf.MONO_HLSB)oled.blit(buf, x, y)(x, y) = (0, 0)
for hz in "唤醒手腕":text_hz(hz, x, y)x += 16oled.show()

OSError 常见问题

OSError: [Errno 5] EIO

Traceback (most recent call last):File "<stdin>", line 7, in <module>File "ssd1306.py", line 113, in __init__File "ssd1306.py", line 35, in __init__File "ssd1306.py", line 70, in init_displayFile "ssd1306.py", line 118, in write_cmd
OSError: [Errno 5] EIO

OSError: [Errno 110] ETIMEDOUT

Traceback (most recent call last):File "<stdin>", line 6, in <module>File "ssd1306.py", line 110, in __init__File "ssd1306.py", line 36, in __init__File "ssd1306.py", line 73, in init_displayFile "ssd1306.py", line 101, in showFile "ssd1306.py", line 119, in write_data
OSError: [Errno 110] ETIMEDOUT

解决方案

i2c = machine.I2C(0, sda=machine.Pin(0), scl=machine.Pin(1), freq=400000)

相关文章:

  • 飞致云开源社区月度动态报告(2025年4月)
  • 轻松养生:让健康融入生活
  • react路由使用方法
  • 【Python】GIS及点云处理十讲
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】5.3 相关性分析(PEARSON/SPEARMAN相关系数)
  • Day11 训练
  • Python项目源码57:数据格式转换工具1.0(csv+json+excel+sqlite3)
  • 比较两种判断相同二叉树的方法:递归与遍历序列对比
  • 《哪吒面经》4万字102道Java多线程经典面试题
  • VTK 交互类介绍
  • 【AI入门】Cherry入门1:Cherry Studio的安装及配置
  • 精益数据分析(39/126):SaaS与移动应用商业模式的关键要点剖析
  • 5月5日日记
  • 【计算机视觉】3d人体重建:PIFu/PIFuHD:高精度三维人体数字化技术指南
  • OpenCV 第6课 图像处理之几何变换(透视)
  • EF Core 中,AsEnumerable 和 AsQueryable 的区别
  • 排序用法(Arrays.sort)
  • ABAP 导入Excel形成内表
  • 基于 Spark 和 Hadoop 的空气质量数据分析与预测系统
  • canal同步mysql到mysql主要配置
  • “五一”假期预计全社会跨区域人员流动累计14.67亿人次
  • 云南禄丰一尾矿干堆场坍塌致5人被埋
  • 日产淡水10万吨、全自动运行,万华化学蓬莱海水淡化厂投产
  • 孙一凡的东欧狂想音乐会:一场穿越东欧的听觉绮梦
  • 贵州赤水丹霞大瀑布附近山体塌方车辆被埋,景区:无伤亡,道路已恢复
  • 中国队夺跳水世界杯总决赛首金