ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OLED字模提取实战:PCtoLCD2013配置与驱动代码避坑指南

OLED字模提取实战:PCtoLCD2013配置与驱动代码避坑指南 刚开始接触 OLED 屏幕的时候最劝退我的其实不是 I2C 通信时序也不是 SPI 接线翻车而是“字模”这个东西。你兴致勃勃点亮了屏幕想显示一行字结果发现要往显存里塞一堆十六进制数组每个字节都像是天书。那时候我就在想到底有没有一个工具能像写 Word 一样把字打进去点一下鼠标就直接生成代码里能用的数组后来我找到了 PCtoLCD2013这个问题就彻底解决了。这篇文章我就把手上的 PCtoLCD2013 从安装到压箱底的操作技巧完整过一遍再带上 OLED 驱动代码里字模到底怎么用、常见“加了 OLED 函数卡死”这类坑的排查思路。无论你是用 STM32 的 HAL 库、标准库还是 ESP32 的 ESP-IDF只要你的 OLED 屏是 SSD1306 或者 SH1106 驱动的这篇文章的思路都能直接用。1. 字模提取这件事到底在做什么很多人第一次接触字模提取的时候总以为这玩意儿是什么玄学操作觉得把一个汉字变成一串 0x00、0xFF 很神秘。其实你只要理解了 OLED 屏幕的工作原理就会明白字模提取无非就是把一个字符的“轮廓”翻译成显存里的二进制数据。OLED 屏幕本质上是一个像素点阵比如 0.91 寸的 OLED 常见分辨率是 128x320.96 寸的是 128x64。屏幕上每个像素点只有两个状态亮或者不亮。那要显示一个汉字“电”本质上就是要告诉屏幕哪些像素点亮、哪些不亮。而 MCU 和 OLED 屏幕之间通过 I2C 通信你不可能一个一个像素点去设置太浪费通信带宽了。所以通常的做法是把屏幕划成一个个 8 像素高的“页”page每一列用一个字节表示这个字节的 8 个 bit 从上到下对应 8 个像素。一个字模数组本质上就是把这个字拆成一张张 8x16、16x16 的像素图然后按列或者按行扫描把每一列的亮灭状态记录成十六进制字节。这就是为什么你会看到网上很多 OLED 例程里有类似这样的东西const unsigned char F16x16[][32] { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };这数组里的每一个字节都对应着字模中某一列或某一行的 8 个像素点状态。手工去算这些数据几乎不可能特别是你要显示一整套 GB2312 汉字库的时候没有工具辅助纯粹是浪费生命。PCtoLCD2013 干的就是这件事你把字打进去选好取模方式它批量生成你复制粘贴到代码里的数组。本质上这是标准做法而不是什么黑客技巧。PCtoLCD2013 这个工具本身是硬件社区里流传多年的老软件体积小、免安装、界面老派但功能扎实。它支持从单个字符到整个文本文件的批量取模也支持图片转码用来在 OLED 上显示 BMP 图片。最关键的是它支持非常细腻的取模参数调节包括逐行式、逐列式、行列式、顺向、逆向等这些参数如果和显示驱动的扫描方式不匹配字就会“躺”着或者“倒”着。理解了这一层后面所有的设置都是顺理成章的事。2. 准备工作和工具选型2.1 你需要的硬件和软件清单做 OLED 字模实验你不需要一套极其昂贵的装备很多东西都是手边就有的。我自己的常用配置供参考OLED 屏幕一块优先选 SSD1306 驱动的 0.96 寸128x64资料最多遇到问题也最好查。1.3 寸的 SH1106 驱动也可以但 I2C 地址和显存偏移有微小差异新手建议先用 SSD1306 练手。主控板STM32F103C8T6 或者 ESP32 都行。如果只是想快速验证字模效果ESP32 用 IDF 或者 Arduino 框架都行如果想深入学 HAL 库就 STM32。杜邦线若干I2C 上拉电阻很多模块已经板载不用额外加。PCtoLCD2013 软件Windows 环境下直接运行兼容性很好Win7 到 Win11 都能跑不需要安装解压即用。一个顺手的串口调试助手用来打印调试信息排查卡死问题的时候很有用。我见过很多人在工具选择上纠结半天其实没必要。PCtoLCD2013 被用得最多不是因为它界面多漂亮而是因为它默认配置上基本贴合主流 OLED 驱动芯片的取模习惯。OLED 屏幕驱动的资料里字模数组大多都是“横向取模高位在前字节正序”这种格式而 PCtoLCD2013 的默认选项里“横向取模”就是直接可选的这一点比某些需要自己摸索半天参数的开源软件要省心很多。2.2 字模格式的底层逻辑你选的不只是“横竖”在进入实际操作之前我特别想说一下“字模格式”里最容易踩坑的几个概念。PCtoLCD2013 的取模方式里有一大堆名词逐行式、逐列式、行列式、顺向、逆向、字节正序、字节倒序、高位在前、低位在前。新手看到这堆选项直接懵掉。这里我建议你用一句话理解什么叫逐行式就是按一行一行的顺序扫描。所谓逐列式就是一列一列地来。以 16x16 的汉字为例如果采用逐行式那么前两个字节是第一行的前 8 个像素和第一行的后 8 个像素如果采用逐列式那么前两个字节是第一列的 8 个像素和第二列的 8 个像素。而 OLED 驱动芯片 SSD1306 的显存结构是按页组织的也就是说如果你用 I2C 连续写显存地址显存地址增加时读取顺序是按照“同一页从左到右”来的。SSD1306 一个页有 128 个字节8 个页构成完整 128x64 的显示区域。所以在 OLED 上显示字模通常 SSD1306 例程的“显示一个 16x16 汉字”函数是把字模数据一列一列写进显存的也就是“纵向取模”或者叫逐列式取模。这也是为什么你在网上拷贝的 OLED 字模数组大多是逐列式而不是逐行式的。不过这不代表逐行式就不能用。如果你把 OLED 的驱动函数改成按行绘制同样也能显示只是多数现成例程不会这么做。所以最稳妥的方法就是直接用 PCtoLCD2013 的“逐列式”生成字模和网上大多数例程保持一致调试成本最低。“高位在前”和“低位在前”这个东西也很有意思。一个字节里bit0 是低位、bit7 是高位。如果高位在前表示这个字节的最左边或者说最上面的像素对应 bit7如果低位在前则反之。OLED 例程里常写的那种“从上到下扫描一个字节对应列方向 8 个点”的布局一般要求高位在前。切莫小看这个选项选反了会看到字是“镜像”的或者在垂直方向上被拧过去。后续我会详细讲如何在 PCtoLCD2013 里做这些选择。2.3 为什么我推荐 PCtoLCD2013 而不是别的工具目前做字模的工具不算少比如 Image2Lcd 也能生成 C 语言数组还有一些在线网页工具也能出字模。但它们在 OLED 这个场景下各有各的不顺手。Image2Lcd 更适合做图形取模处理文字反而要先把文字转成图片多一道工序。在线网页工具虽然方便但每次都要联网批量生成大量汉字的时候体验非常差而且参数可调性一般。PCtoLCD2013 的优势在于本地运行完全离线批量生成几千个汉字的字库都没问题自带汉字输入和文本导入功能直接输入多个字符一次生成取模方式和编码细节可调项非常丰富能够覆盖几乎所有主流屏幕驱动方案软件自带“反色”、“镜像”、“逐行/逐列”、“字节正序/倒序”等高级选项方便快速适配不同的驱动代码。当然PCtoLCD2013 也不是没有缺点。毕竟发布时间早界面是祖传的灰色窗口DPI 缩放下偶尔会有字体发虚的情况在 4K 屏上看起来比较费眼。但只要功能稳定这些都可以忍。我用了这么多年总体上认为它是做 OLED 字模最顺手的工具。3. PCtoLCD2013 实操第一次提取字模3.1 设置界面里的关键选项逐个说打开 PCtoLCD2013默认界面很简单。顶部是菜单栏左边白色画布用来预览字模点阵右边是参数设置区域。初次上手你不需要全部看懂真正要动的地方就几个字模选项选择“汉字”模式如果你要生成字符则选“字符”模式点阵格式选“阴码”。这个名词乍一看很怪其实就是“1 显 0 隐”还是“0 显 1 隐”的区别。常规 OLED 点亮是写 1所以选阴码。如果你选阳码显示出来正好反色字是黑的背景是亮的取模走向选“逐列式”。一行显示字节数这里“16”就是字宽 16 像素对应 16x16 汉字“8”对应 8x16 ASCII 字符。它决定取模软件里每一行输出多少个字节。还有一个“每行显示点数”类似的参数你要结合自己的字体大小填。很多人忽略这里结果生成出来的数组长度不对代码里显示一堆乱码。自定义格式这是控制输出数组长什么样的地方。选 C51 格式是比较通用的生成的效果类似0x00,0x1F,...再勾上“行尾逗号”和“行尾结束符”之后输出结果直接可以粘贴进 C 语言数组。其它选项里“字节正序”一般保持默认“低位在前”不要勾选“逐行式/逐列式”选择后“逆向”选项根据实际显示效果决定不是必须。以我当时第一次实验为例我取了“电”字设置的参数是字模选项汉字点阵格式阴码模向取模逐列式取模走向顺向输出数制十六进制自定义格式C51点击“生成字模”按钮之后下方输出窗口就直接出现了{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}这个就是可以直接往工程里粘贴的数组。注意一个 16x16 的汉字逐列式取模后应该是 32 个字节。如果你生成的结果不是 32 字节那大概率是“每行显示字节数”或“每行显示点数”设置有了偏差。3.2 批量生成字库一次搞掂常用汉字前面说的是生成单个汉字的情况。实际上做项目的时候你往往需要显示很多个汉字比如温湿度计要显示“温度”、“湿度”、“当前时间”等。一个个去点生成按钮很浪费时间。PCtoLCD2013 支持批量操作你可以在文本输入框里一次性输入一串文字然后再点击“生成字模”软件会把整个文本里的所有字符按顺序全部生成出来。注意PCtoLCD2013 对中文输入支持依赖操作系统的编码环境。如果你在简体中文 Windows 下运行通常没问题。如果你用的是英文系统或者非中文地区可能会出现中文输入乱码或者无法生成题字。解决办法是临时把系统区域切换成中文或者换一台中文 Windows 环境生成好再拷贝到工程里。在 Linux 下可以用 Wine 跑但体验不是很好我不建议折腾。批量生成汉字的时候还有一个小技巧你可以在文本里包含换行或空格来分行输出窗口里生成的数组是一个接一个的你复制到代码里后每个数组之间的字节数是固定的。比如 16x16 的字每 32 字节分割一次就能自动切分成独立数组。如果你想要“字库”结构体也可以参照这个思路用一个索引表保存每个汉字在字库数组里的偏移省去单独定义几十个数组的麻烦。我自己比较习惯的做法是把一个项目里所有可能用到的汉字全收集起来生成一个大的字库数组然后用一个查找函数定位汉字编码。这样不管界面显示什么文案只需要调用查找函数传一个中文字符串进去就能显示不用频繁改代码。这种做法在 OLED 显示菜单、多级界面的时候特别实用。3.3 生成 ASCII 字符字模汉字字模搞定之后字符字母、数字、标点的处理也是常有的事。在 PCtoLCD2013 里生成 ASCII 字符字模的时候记得切换“字模选项”为“字符”。ASCII 字符一般是 8x16 或 6x12、8x8 等尺寸你需要根据字库类型来选。我用 8x16 的 ASCII 比较多因为它在 0.96 寸 OLED 上看起来大小适中和 16x16 的汉字搭配比较协调。生成 8x16 ASCII 的时候PCtoLCD2013 设置字模选项字符点阵格式阴码取模走向逐列式每行显示字节数1这样每个 ASCII 字符生成 16 个字节。和 16x16 汉字不一样的是ASCII 字模通常是把字符在 8x16 的格子里面靠左或者居中看你的设计绘制。在代码里显示的时候你的驱动函数要按 8 像素宽、16 像素高去处理。有一个容易踩的坑很多人生成 ASCII 字模之后发现字母只占了左边一半右边一半是空的。这是正常的因为 8x16 的格子本来就只有 8 个像素宽加上字符本身笔画简单周围留白会比较多。如果你希望字符看起来更饱满可以在 PCtoLCD2013 画布上调整字符的偏移或者在生成后手动修改数组但这属于进阶操作不是必须。3.4 图片转字模在 OLED 上显示 BMP 图片字模提取不只限于汉字。OLED 显示 logo 或简单图片同样需要“图片字模”。PCtoLCD2013 也支持打开图片文件然后转换成 C 语言数组。具体操作方式是在菜单里选择“打开图片”导入一张 BMP 或 JPG 图片。注意图片最好是黑白的尺寸对齐 OLED 分辨率比如 128x64 的屏幕就准备一张 128x64 的黑白图。如果你用的是彩色图片软件会做灰度转换但效果一般不建议在 OLED 这种单色屏上处理彩色图转换完会有大量噪点。打开图片后同样设置“取模走向”为逐列式“点阵格式”为阴码然后生成。生成出来的数组就是整屏图片的显存数据。显示时你直接把这个数组写进 OLED 的 GDDRAM 即可。大尺寸字库数组或图片数组往往比较大对 MCU 的 Flash 空间有要求。STM32F103C8T6 是 64KB Flash如果你放大量 128x64 的图片数组很快就会发现存储空间吃力。这也是为什么很多屏小的项目只用几张小尺寸的图片或者只放几个汉字字库的原因。4. OLED 驱动代码里的字模怎么用4.1 SSD1306 显存与取模方向的对应关系字模生成只是一部分代码里能不能正确显示是另一部分。这里我把 SSD1306 的显存和字模之间的对应关系再说透一点。SSD1306 内置 1KB GDDRAM组织结构是 8 页Page0 到 Page7每页有 128 个字节。一个字节的 8 个 bit 对应同一列上垂直排列的 8 个像素bit0 是页内最下面的像素bit7 是最上面的像素取决于 SSD1306 的数据手册定义实际显示方向以你的坐标映射为准。所以当你用 I2C 连续往 GDDRAM 里写数据时写入顺序是先 Page0 的第 0 列、第 1 列……一直写到第 127 列然后切换到 Page1继续从第 0 列开始。如果 PCtoLCD2013 里选择了“逐列式”取模字模的第二个字节是“第二列”的 8 个像素那么这个字模放在 SSD1306 上正好和显存地址序列一致。也就是说你写显存的时候只需要从字模起始坐标的 (x, page) 开始连续把 32 个字节写入这个汉字就显示出来了。这是最省事的方案。如果你是按“逐行式”取模的那就得在驱动函数里做矩阵转置把行数据转换成列数据再写进显存。虽然也能实现但没这个必要。我看到有人折腾半天搞不定显示最后发现就是取模方向跟驱动不匹配换成“逐列式”立刻就好了。4.2 HAL 库工程中显示字模的代码思路在 STM32 HAL 库工程里OLED 的 I2C 驱动大致分为三层底层 I2C 发送接口、OLED 写命令/写数据接口、上层画点/显示字符串接口。字模显示主要涉及上层接口。先看最底层的 I2C 发送。如果用的是软件模拟 I2C核心是起始信号、停止信号和字节发送如果用的是硬件 I2CHAL 库的HAL_I2C_Mem_Write可以直接用。我自己在实际项目里更偏向软件 I2C因为调起来直观、不依赖具体的 I2C 外设映射代码在 STM32、ESP32、51 之间搬来搬去都不用大改。当然硬件 I2C 效率更高中断/ DMA 模式下 CPU 占用更低适合做大刷新率的动画。OLED 写命令的示例比如设置页地址void OLED_Set_Pos(uint8_t x, uint8_t y) // y: 页地址0~7 { OLED_WR_CMD(0xB0 y); OLED_WR_CMD(((x 0xF0) 4) | 0x10); OLED_WR_CMD(x 0x0F); }这里把列地址拆成高 4 位和低 4 位是因为 SSD1306 的列地址指针是 7 位的需要分成两次命令写入。这个步骤是 OLED 驱动里最容易写错的地方之一很多人显示错位、花屏往往就是列地址设置不对。显示一个 16x16 汉字的函数典型写法void OLED_ShowChinese(uint8_t x, uint8_t y, uint8_t no, const uint8_t *font) { uint8_t t; OLED_Set_Pos(x, y); for (t 0; t 16; t) { OLED_WR_Data(font[no * 32 t]); } OLED_Set_Pos(x, y 1); for (t 0; t 16; t) { OLED_WR_Data(font[no * 32 t 16]); } }这里的 y 是页号不是像素行号。如果是 0.96 寸 128x64 屏幕总共有 8 页y 取值 0~7。显示 16x16 的汉字需要占两页上半部分 8 像素放到第 y 页下半部分放到第 y1 页。数组中前 16 个字节是上半部分逐列数据后 16 个字节是下半部分逐列数据这是逐列式取模的自然结果。你拿 PCtoLCD2013 生成的数组对比一下就会发现前 16 个字节正好对应汉字的上半部分。显示字符串的函数类似只是要循环调用字符显示函数。ASCII 字符 8x16 只需要一页比汉字简单一些。我更习惯的做法是维护两个函数一个专门画 16x16 汉字一个专门画 8x16 的 ASCII 字符上层再封装一个OLED_ShowString。4.3 加了 OLED 函数之后程序卡死排查思路“加了 OLED 函数卡死”是热词里一个非常真实的痛点我排查过太多次了。现象通常有两种一种是一调用 OLED 显示函数程序就卡在某个地方跑不动另一种是 OLED 能亮但主循环里的其他任务全部停止响应。第一种情况最常见的根因是 I2C 通信死等。如果你用的是 HAL 库的阻塞式 I2C 发送比如HAL_I2C_Mem_Write里面的HAL_MAX_DELAY一旦 OLED 没有正确响应 ACK函数就会一直等导致看起来程序卡死。排查方法很简单在 OLED 初始化函数之后加一个延时然后挨个调用显示函数用串口打印调试信息定位卡住的位置。如果发现是某个OLED_WR_Data卡住先检查 OLED 地址是否正确SSD1306 的 7 位地址常见是 0x3C 或 0x3D有些模块的地址引脚 SA0 电平会改变地址。再检查接线SDA 和 SCL 有没有接反上拉电阻是否存在。第二种情况程序的“卡死”往往不是真的死锁而是阻塞式 I2C 发送占用了太长时间导致其他任务无法及时执行。这在用 FreeRTOS 或者有定时器中断任务的工程里特别明显。比如你在主循环里频繁刷新整屏图片每次都调用巨大的HAL_I2C_Mem_Write发送 1024 字节如果 I2C 速率只有 100kHz一次刷屏就要几十毫秒主循环周期被拖得很长看起来就像别的任务卡住了。解决方案有几个方向一是把 I2C 速率提到 400kHz二是改用 DMA 或中断方式发送数据三是减少刷新频率只在内容变化时刷屏。我之前就踩过这个坑在做一个带菜单界面的小设备时所有按键检测都放在主循环里结果 OLED 刷屏太慢按键按下去半天没反应。后来我把整屏刷新改成了局部刷新只在光标移动时重绘那一小块区域问题立刻消失。还有一种比较隐蔽的原因OLED 的 I2C 和某个外设共用了同一个 I2C 总线而另一个外设的地址冲突或者时序冲突导致总线被拉死。最常见的就是板载 EEPROM 和 OLED 共用一个 I2C两边地址不同但总线的时钟延展或 ACK 冲突导致通信异常。排查时可以先把其他 I2C 外设摘掉单独测试 OLED再逐步加回。4.4 ESP32 下用 ESP-IDF 驱动 OLED 的差异很多热词都指向 ESP32 和 ESP-IDF 环境我再补一点 ESP32 平台的经验。ESP32 的 ESP-IDF 里操作 I2C 和 STM32 不完全一样。在较新的 IDF 版本5.x里I2C 驱动接口改成了新的i2c_master风格驱动函数老代码里常用的i2c_driver_install虽然还能用但官方推荐新接口。不管用哪种核心的取模逻辑和显示函数原理不变。ESP32 的 I2C 时钟频率可以直接配置到 400kHz 或更高只要 OLED 模块支持一般 400kHz 是稳定的。ESP-IDF 驱动 I2C 时要注意的是如果 OLED 挂了或者地址不对读取 ACK 失败会返回错误码不会像 STM32 HAL 的阻塞式接口那样一直死等。这是 ESP32 的一个优势排错相对友好。另外ESP32 的 Flash 空间比较大4MB 起步放全量 GB2312 字库都没问题。如果你在 ESP32 上做比较完整的中文菜单可以考虑直接把 16x16 的 GB2312 点阵字库放进 Flash运行时根据汉字的 GBK 编码计算字模在字库文件里的偏移这样做基本上想显示什么中文都可以不用预先在代码里放几百个数组。PCtoLCD2013 生成的单个字模数组可以用在小型工程里但大型项目还是要用字库文件方案这一点建议你提前规划好。4.5 关于 Linux 下 OLED 屏幕亮度调节的小插曲搜索热词里有“ubuntu oled screen brightness adjust”这其实和我们用 MCU 驱动 OLED 不太一样。在 Ubuntu 等桌面 Linux 系统上所谓的“OLED screen”通常指的是笔记本 OLED 屏幕亮度调节走的是/sys/class/backlight下的驱动接口或者桌面环境的亮度设置。这块和 SSD1306 这种模块无关。但如果你是在 Linux 上做嵌入式开发比如用树莓派或 BeagleBone 连接 OLED 模块那就需要考虑 Linux 的 I2C 设备文件/dev/i2c-x或者用 Python 的 smbus2 库来和 SSD1306 通信这时候字模数据同样是从 PCtoLCD2013 生成显示原理完全一致只是把 I2C 发送换成了 Linux 系统调用而已。写 Python 的时候注意i2c.write_i2c_block_data(addr, register, data)的参数顺序别把命令字节和显示数据搞混。5. 提高字模质量和效率的几个实操技巧5.1 字体选择与字号选择会影响显示效果同样的字在 PCtoLCD2013 里显示出来的效果和 Windows 系统字体选择有关系。PCtoLCD2013 内部虽然不直接调用系统字体库来做 TTF 渲染但它支持“字体”下拉框选择和 Windows 字体关联所以可以选择不同字体。OLED 上是像素风所以更适合选择笔画清晰、无衬线、尽量方正的中文字体。推荐优先用“黑体”、“宋体”或者“微软雅黑”来生成小字号字模。在 16x16 这个尺寸下宋体的笔画细节容易糊成一团黑体能保留更多结构信息。如果做 24x24 或者 32x32 的大字宋体的优势就出来了因为笔画衬线在大点阵下会更精致。如果你追求极致的显示效果还有一个办法先用位图编辑软件把字画成一个清晰的单色点阵图然后通过 PCtoLCD2013 的“打开图片”功能导入再生成字模。这样做的好处是你完全掌控每个像素的位置缺点是很费时间适合做特定 logo 或者特殊字符。5.2 字模数组在工程里的组织方式在工程里组织字模数组有两个流派。一个是每个汉字单独定义数组const unsigned char code char_[] {0x00,0x00,...};另一个是维护一个大数组和偏移表const unsigned char code F16x16[] { ... }; const unsigned short F16x16_Index[] { 0, 32, 64, ... };在单片机上第二种方式节省 Flash 更明显因为如果你定义了 100 个汉字数组光是数组名和符号信息就要占用不少开销做成大数组加索引查找时只需要知道汉字的序号。查找方法也很简单把你要显示的字符串里的每个汉字和你的字库表比对找到它在数组中的偏移再调用显示函数。缺点是如果你改变了字库顺序所有调用处的索引都要同步更新所以建议把字库和索引写在一个独立头文件里别散落在主程序中。5.3 字模显示出现重叠或乱码时的快速校准流程字模显示有问题不要慌先按照下面的顺序排查先确认单点测试在屏幕上画一个单点或一条直线确认横纵坐标方向和你预期一致。如果点斜了问题通常不在字模而在你的画点函数或者坐标映射。再显示一个 16x16 汉字看是否出现“上下颠倒”、“左右颠倒”或“镜像”。上下颠倒通常是“高位在前/低位在前”选反了左右镜像通常是“逆向”选项勾选问题旋转 90 度多半是取模走向设置成了逐行式而驱动按逐列式解释。看是否有“缺笔画”或“乱码”通常是数组长度和实际写入长度不一致。比如 16x16 汉字应该写入 32 字节你的循环只写了 16 字节自然缺下半部分。多字显示时位置错乱检查OLED_Set_Pos里的列地址设置是否正确特别是跨页时 x、y 是否自动进位。这套流程我处理了不下十几次基本每次都能马上定位问题。其实大多数问题都出在取模方向和坐标设置上而不是 OLED 硬件本身。6. 结合实际项目做一个带字模的 OLED 温湿度计前面讲了太多理论最后我拿一个实际项目把整套流程串起来。这个项目很小用 STM32 DHT11 温湿度传感器 0.96 寸 OLED实现温度湿度显示。OLED 上需要显示的汉字有“温度”、“湿度”、“℃”、“%”。我把所有要显示的汉字在 PCtoLCD2013 里一次生成然后粘贴进oled_font.h。生成后的字模数据大概是这样的示意非完整{0x04,0x04,0x04,0x04,0x04,0xFC,0x04,0x04, ...} // 温 前半段 {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, ...} // 温 后半段在主循环里我调用显示函数OLED_ShowChinese(0, 0, 0); // 显示“温度” OLED_ShowNum(32, 0, temp, 2); // 显示温度和数值这个工程验证过 PCtoLCD2013 取模方向和显示函数匹配之后我再把字模替换成批量字库把整个菜单需要的所有中文都放进去然后用查找函数动态显示。做这个项目时踩到最典型的一个坑是 DHT11 的时序要求比较严格而 OLED 显示又占时间导致 DHT11 的起始信号偶尔失败。解决办法很简单在 DHT11 读取完成后再刷屏而不是一边读一边刷或者把 DHT11 读取放到定时器中断里保证读取时序的连续性。这个经验在 OLED 驱动开发里很常见——很多“卡死”问题并不是 OLED 本身造成的而是外设之间的时序冲突被 OLED 的操作放大了。7. 最后再分享一点个人经验PCtoLCD2013 这个工具界面虽然老土但它是真正为嵌入式显示而生的。用熟之后你会发现它最值钱的不是那个“生成字模”按钮而是那些看起来繁琐的配置项。你花半小时理解逐列式、高位在前、阴码这些概念后面的所有 OLED 项目都会变得很顺。我至今还在用这个工具从最早的 51 单片机到现在的 STM32、ESP32字模流程几乎没有变过。如果你正在被 OLED 字模显示折腾我建议你先不要急着怀疑硬件。拿出 PCtoLCD2013重新检查一遍取模方向再对着驱动代码确认一下写入顺序大概率问题就出在这些细节上。做嵌入式显示就是这样原理不复杂但每一步都必须严谨一步错就会显示得莫名其妙。希望这篇内容能帮你少走一些弯路。
返回列表