简介这份资源面向嵌入式开发初学者与需要快速集成小尺寸显示屏的工程师提供基于IIC接口的0.91英寸OLED模组128×32像素全套字符显示函数。内容围绕6×8与8×16两种字符字库展开涵盖初始化、光标定位、字符写入、清屏以及文本颜色、背景色、方向设置与滚动显示等常用功能帮助在资源受限的单片机上实现清晰直观的文本与简单图形输出。压缩包共5个文件包含3个.h头文件与2个.c源文件分别用于驱动声明、字库定义与显示逻辑实现整体约9KB结构精简便于直接移植。目前已有1605人学习下载适合作为IIC OLED驱动参考与字符显示功能扩展的起点。1. 0.91 寸 OLED 12832 IIC 全套显示函数从点亮到字符滚动的完整路径手里拿到一块 0.91 寸 OLED 模组驱动芯片是 SSD1306分辨率 128×32通信接口只有 IIC 两根线。很多人第一次上电就卡住——屏幕不亮、花屏、字符乱码甚至怀疑模块坏了。其实这类模组的驱动逻辑非常固定真正让人翻车的是初始化序列、页地址模式和字库取模方式这三件事。这份资源把整套显示函数打包好了包含初始化、清屏、画点、字符显示、数字显示、字符串显示以及滚动效果直接面向 IIC OLED 字符显示场景。适合刚接触嵌入式显示的新手照着接线就能跑也适合熟手拿来当字符显示层的参考实现省去重复造轮子的时间。下面按“硬件怎么接、驱动怎么写、坑怎么避”的顺序拆开讲。2. SSD1306 的 IIC 时序与初始化序列为什么你的屏幕不亮2.1 IIC 地址与硬件连接SSD1306 的 IIC 从机地址由模块上的电阻跳线决定常见是 0x78 或 0x7A8 位写地址。0.91 寸模组通常只引出 VCC、GND、SCL、SDA 四根线没有复位脚和地址选择脚地址在出厂时就固定了。接线时 VCC 接 3.3V 或 5V 要看模组背面的稳压芯片有些模组标称 3.3V 但实际带了 LDO接 5V 也能工作不过稳妥起见先用 3.3V 试。IIC 总线上必须接上拉电阻很多开发板的 IIC 引脚内部已经有弱上拉但 0.91 寸 OLED 的驱动电流需求不大内部上拉通常够用。如果屏幕时亮时不亮优先怀疑上拉不足或线太长。SCL 和 SDA 的走线尽量短超过 20cm 就容易出现通信失败。初始化之前先确认 IIC 地址。用下面这段扫描代码可以快速确认模组是否在线# IIC 地址扫描适用于 MicroPython 环境 from machine import I2C, Pin i2c I2C(0, sclPin(22), sdaPin(21), freq400000) devices i2c.scan() if devices: for d in devices: print(发现 IIC 设备地址, hex(d)) else: print(未发现设备检查接线和上拉电阻)逻辑说明i2c.scan()会遍历 0x08 到 0x77 的地址返回应答的从机地址。参数freq400000是 400kHzSSD1306 支持标准模式 100kHz 和快速模式 400kHz先用 400kHz 试不稳定就降到 100kHz。如果扫描不到设备先查 VCC 和 GND再查 SCL/SDA 是否接反最后查上拉电阻。2.2 初始化命令序列逐条拆解SSD1306 上电后必须按固定顺序写入一系列命令顺序错了屏幕就不亮或者显示异常。下面是一份经过验证的初始化序列按功能分组说明# SSD1306 初始化命令序列128x32 INIT_CMDS [ 0xAE, # 关闭显示 0xD5, 0x80, # 设置时钟分频因子和振荡频率 0xA8, 0x1F, # 设置多路复用比为 320x1F 31即 32 行 0xD3, 0x00, # 设置显示偏移为 0 0x40, # 设置显示起始行号为 0 0x8D, 0x14, # 使能电荷泵0x14 表示开启 0x20, 0x00, # 设置内存寻址模式为水平寻址 0xA1, # 段重映射左右方向 0xC8, # 扫描方向上下方向 0xDA, 0x02, # 设置 COM 引脚硬件配置128x32 用 0x02 0x81, 0x8F, # 设置对比度0x8F 是中等偏上 0xD9, 0xF1, # 设置预充电周期 0xDB, 0x40, # 设置 VCOMH 电压 0xA4, # 全局显示开启 0xA6, # 正常显示非反色 0xAF, # 开启显示 ]逻辑说明每条命令通过 IIC 写入控制字节 0x00 表示命令0x40 表示数据。0xA8, 0x1F这一条最关键128×32 模组的多路复用比必须是 31写成 0x3F64 行会导致只显示一半或者花屏。0xDA, 0x02是 COM 引脚配置128×32 用 0x02128×64 用 0x12这个参数搞错屏幕会分成上下两半显示同样的内容。0x8D, 0x14是电荷泵使能没有这一条屏幕完全不亮因为 SSD1306 需要内部升压才能驱动 OLED 像素。参数调整建议对比度0x81后面的值可以在 0x00 到 0xFF 之间调0x8F 适合室内户外强光下可以调到 0xCF。如果屏幕有轻微闪烁把时钟分频0xD5后面的 0x80 改成 0xF0 试试。3. 页地址模式与显存映射字符显示函数的底层逻辑3.1 128×32 的显存组织方式SSD1306 的显存按页组织128×32 模组分为 4 页每页 8 行像素每页有 128 个字节每个字节对应一列 8 个像素。也就是说显存总大小是 128×4 512 字节。写入一个字节就控制了某一页某一列的 8 个像素的亮灭。水平寻址模式下写入一个数据字节后列地址自动加一写到第 127 列后自动跳到下一页的第 0 列。这个模式适合连续写入整屏数据。页寻址模式下列地址写到 127 后回到 0但页地址不变需要手动换页。字符显示函数通常用页寻址模式因为一个 8×16 的字符正好占两页按页写入更方便。下面这段代码演示了如何设置页地址和列地址// 设置页地址和列地址页寻址模式 void OLED_SetPos(uint8_t page, uint8_t col) { IIC_WriteCmd(0xB0 page); // 设置页地址0xB0 到 0xB3 IIC_WriteCmd(0x00 (col 0x0F)); // 设置列地址低 4 位 IIC_WriteCmd(0x10 ((col 4) 0x0F)); // 设置列地址高 4 位 }逻辑说明0xB0 page设置页地址page 范围 0 到 3。列地址分两次写入低 4 位用0x00 (col 0x0F)高 4 位用0x10 ((col 4) 0x0F)。这是 SSD1306 的固定格式不能合并成一条命令。参数 col 范围 0 到 127超出会回绕。3.2 字符取模与显示函数实现字符显示的核心是把字模数据按页写入显存。一个 8×16 的 ASCII 字符占 16 列、2 页字模数据通常是 16 个字节前 8 个字节是上半部分后 8 个字节是下半部分。取模方式必须选“列行式”或“页式”顺向取模不能选“行列式”。下面是一个完整的字符显示函数// 显示一个 8x16 ASCII 字符 void OLED_ShowChar(uint8_t page, uint8_t col, char ch) { uint8_t i; uint8_t idx ch - ; // 字库从空格开始 OLED_SetPos(page, col); for (i 0; i 8; i) { IIC_WriteData(F8X16[idx * 16 i]); // 上半部分 } OLED_SetPos(page 1, col); for (i 0; i 8; i) { IIC_WriteData(F8X16[idx * 16 i 8]); // 下半部分 } }逻辑说明F8X16是字库数组每个字符 16 字节。idx ch - 把 ASCII 码映射到字库索引空格是第一个字符。先写上半页 8 个字节再换到下一页写下半部分。参数 page 范围 0 到 2因为要占两页page1 不能超过 3col 范围 0 到 120留出 8 列宽度。字符串显示就是循环调用字符显示函数每显示一个字符列地址加 8void OLED_ShowString(uint8_t page, uint8_t col, char *str) { while (*str) { OLED_ShowChar(page, col, *str); col 8; if (col 120) { // 超出屏幕宽度换行 col 0; page 2; } } }数字显示可以先转成字符串再调用字符串显示也可以单独写一个数字显示函数。滚动效果则是通过连续改变显示起始行或者整体搬移显存来实现后面章节会展开。4. 避坑与排查IIC OLED 字符显示最常见的五个翻车点4.1 屏幕完全不亮现象上电后屏幕没有任何反应背光也没有OLED 自发光本来就没有背光。原因电荷泵没有使能或者初始化序列里0x8D, 0x14这一条被漏掉。另一个常见原因是 IIC 地址写错比如把 0x78 写成了 0x3C7 位地址和 8 位地址混淆。解决先用扫描代码确认地址再逐条核对初始化命令。如果地址正确、命令完整还是不亮用万用表量 VCC 和 GND 之间的电压确认模组供电正常。有些模组需要 VCC 和 VDD 都接但 0.91 寸四线模组通常只有 VCC。4.2 屏幕亮但显示花屏或乱码现象屏幕有显示但像素杂乱字符看不清。原因多路复用比设置错误128×32 模组写成了 0x3F。或者 COM 引脚配置写成了 0x12导致上下半屏映射错乱。还有一种可能是 IIC 通信速率太高数据丢包。解决确认0xA8后面跟的是 0x1F0xDA后面跟的是 0x02。把 IIC 速率从 400kHz 降到 100kHz 试试。如果花屏只出现在屏幕下半部分检查页地址是否超出了 0 到 3 的范围。4.3 字符显示上下颠倒或左右镜像现象字符能显示但方向不对。原因段重映射命令0xA1和扫描方向命令0xC8的组合不对。0xA1控制左右0xC8控制上下。两个都写或者都不写方向会反过来。解决如果字符上下颠倒把0xC8改成0xC0。如果左右镜像把0xA1改成0xA0。两个都反了就把两条命令都改。这个没有统一标准取决于模组的玻璃封装方向以实际显示为准。4.4 字符串显示到边缘不换行或覆盖现象字符串太长时超出屏幕宽度的部分直接消失或者覆盖了上一行的内容。原因字符串显示函数没有处理列地址回绕或者页地址加得不对。128×32 只有 4 页一个 8×16 字符占两页所以最多显示两行字符。如果 page 加到 4 就会写到不存在的页数据丢失。解决在字符串显示函数里加边界判断col 超过 120 时换行page 超过 2 时停止写入或者回到第 0 页。如果只想显示一行把 page 固定为 0col 超过 120 就截断。4.5 滚动效果卡顿或撕裂现象滚动显示时画面不流畅有撕裂感。原因滚动是通过连续搬移显存实现的每次搬移都要读写 512 字节IIC 速率低的时候搬移一次要几十毫秒看起来就卡。另外如果在搬移过程中同时写新数据会出现撕裂。解决用 SSD1306 内置的硬件滚动命令而不是软件搬移。硬件滚动只需要设置一次屏幕自己滚动不占用 IIC 带宽。或者降低滚动帧率每 100ms 搬移一次虽然卡但不会撕裂。5. 进阶技巧用硬件滚动和局部刷新把字符显示做稳5.1 硬件滚动命令的配置方法SSD1306 内置了水平滚动和垂直滚动命令配置好之后屏幕自动滚动不需要 MCU 持续搬移显存。下面是一个水平向右滚动的配置示例// 配置水平向右滚动 void OLED_ScrollRight(uint8_t start_page, uint8_t end_page, uint8_t speed) { IIC_WriteCmd(0x26); // 水平向右滚动 IIC_WriteCmd(0x00); // 虚拟字节固定为 0 IIC_WriteCmd(start_page); // 起始页 IIC_WriteCmd(speed); // 滚动速度0 到 70 最快 IIC_WriteCmd(end_page); // 结束页 IIC_WriteCmd(0x00); // 虚拟字节 IIC_WriteCmd(0xFF); // 虚拟字节 IIC_WriteCmd(0x2F); // 开启滚动 }逻辑说明0x26是水平向右滚动命令0x27是水平向左。start_page和end_page指定滚动的页范围128×32 模组有效范围是 0 到 3。speed是滚动帧率0 最快7 最慢。最后一条0x2F开启滚动0x2E关闭滚动。配置一次之后屏幕会一直滚动直到收到0x2E。参数调整建议如果只想让某几行滚动把 start_page 和 end_page 设成对应的页。比如只让第 0 页滚动start_page0end_page0。速度根据实际观感调一般 3 到 5 比较适中。5.2 局部刷新与显存缓冲直接写显存的方式每次都要通过 IIC 发送数据字符多了之后刷新率上不去。更好的做法是在 MCU 内存里开一块 512 字节的缓冲区所有绘制操作先写到缓冲区最后一次性刷到屏幕。这样 IIC 上只传输一次效率高很多。uint8_t oled_buffer[128 * 4]; // 512 字节显存缓冲 // 绘制字符到缓冲区 void OLED_DrawCharToBuffer(uint8_t page, uint8_t col, char ch) { uint8_t i; uint8_t idx ch - ; for (i 0; i 8; i) { oled_buffer[page * 128 col i] F8X16[idx * 16 i]; oled_buffer[(page 1) * 128 col i] F8X16[idx * 16 i 8]; } } // 把缓冲区整体刷到屏幕 void OLED_Refresh(void) { uint8_t page, col; for (page 0; page 4; page) { OLED_SetPos(page, 0); for (col 0; col 128; col) { IIC_WriteData(oled_buffer[page * 128 col]); } } }逻辑说明oled_buffer按页优先排列page * 128 col定位到具体字节。绘制函数只改缓冲区不碰 IIC。OLED_Refresh遍历 4 页 128 列一次性把 512 字节全部发出。这样字符显示和滚动效果都可以在缓冲区里做最后统一刷新画面不会撕裂。参数说明缓冲区大小固定 512 字节对应 128×32 的显存。如果换成 128×64 模组缓冲区要改成 1024 字节页数改成 8。刷新频率建议不低于 30Hz低于这个值滚动会看出卡顿。5.3 字符显示函数的验证方法写完显示函数之后用下面这个测试序列验证每个功能是否正常void OLED_Test(void) { OLED_Init(); OLED_Clear(); OLED_ShowString(0, 0, OLED 12832); OLED_ShowString(2, 0, IIC Ready); OLED_Refresh(); delay_ms(2000); OLED_Clear(); OLED_ShowString(0, 0, Scroll Test); OLED_Refresh(); OLED_ScrollRight(0, 3, 3); delay_ms(5000); OLED_ScrollStop(); }逻辑说明先初始化并清屏显示两行字符验证基本显示功能。延时 2 秒后清屏显示一行字符并开启硬件滚动验证滚动功能。最后停止滚动。如果每一步都符合预期说明初始化、字符显示、刷新和滚动都正常。如果某一步不对回到对应章节排查。我自己的习惯是每次拿到新的 OLED 模组先跑一遍这个测试序列确认硬件和驱动都没问题再往项目里集成。从那以后我每次写显示驱动都强制走一遍这个流程省得在项目后期被显示问题拖住。希望帮到你。本文还有配套的精品资源点击获取