
PCtoLCD2002 这个工具玩单片机的人应该都不陌生。早期做 12864、1602 中文显示离不开它后来做 0.96 寸 OLED 小屏它依然是绕不开的老伙计。很多新手第一次在 OLED 上显示汉字卡就卡在“取模”这一步——字是取出来了但显示出来全是花屏、乱码、倒着的甚至半个字半个字地跳。这篇东西我不讲虚的直接用手头的 0.96 寸 I2C OLEDSSD1306 主控走一遍完整流程从 PCtoLCD2002 参数设置到 HAL 库驱动代码全部落地照着抄就能用。先说清楚这篇文章适合谁正在做嵌入式课设、毕业设计或者刚接触 OLED 想显示中文的开发者。你会学到三件事第一PCtoLCD2002 每个参数到底什么意思为什么这么设第二怎么把取出来的字模组织成 C 语言数组配合驱动文件显示出来第三实际调试中最容易踩的坑比如花屏、方向反了、刷新慢怎么一步步排查。整个流程我尽量按“先理解原理再上手操作”的顺序来讲。1. 上手前的关键认知OLED 显示汉字的原理与工具选型1.1 0.96 寸 OLED 为什么要点阵显示0.96 寸 OLED 屏幕常见分辨率是 128x64也就是横向 128 个像素点纵向 64 个像素点。SSD1306 这颗驱动芯片做的事情很简单内部有一块 128x64 的显存GDDRAM每一位对应屏幕上的一个像素写 1 就点亮写 0 就熄灭。我们不断通过 I2C 或 SPI 往这块显存里填数据屏幕就能显示内容。汉字本质上是图形。一个 16x16 点阵的汉字就是 16 行、每行 16 个点用二进制表示就是 32 个字节16x16 / 8 32。PCtoLCD2002 干的事情就是把“你输入的汉字”变成“这 32 个字节的数据”。这个数据就是字模。显示汉字的过程等于把字模数组里的每一位“翻译”成屏幕上的点填充到 SSD1306 的显存里。理解了这一点你就知道取模工具不是随便点几下生成数据完事取模方式必须要和驱动代码里的“扫描方式”严格匹配。这一节后面所有的参数设置都是围绕“匹配”两个字展开的。1.2 为什么选 PCtoLCD2002 这个取模工具取模工具不少比如字模 III、Img2Lcd、LCD Assistant但 PCtoLCD2002 在汉字取模领域依然是首选原因有三个一是体积小、免安装绿色软件解压即用在 Windows 老机器上跑得飞快不挑环境。二是参数自由度很高点阵格式、取模走向、输出数制全部可以自定义能适配绝大多数屏幕驱动不只是 SSD1306ST7735、ST7789、UC1701 这些常见驱动都能用。三是操作直观左边输入文字右边立即预览生成的数据直接带 C 语言数组格式复制就能粘贴到工程里。有人会用 PCtoLCD2002 生成图片的 C 数组用来做 OLED 动画或开机 logo这也没问题后面我会单独讲动态图的取模思路。但首要任务还是把汉字显示搞定。注意网上流传的 PCtoLCD2002 版本很多有的版本“字模选项”里多了“自定义格式”有的版本界面按钮位置不同但核心参数名称基本一致。我下面用的版本是 2002 完美版界面是经典的左输入右预览布局。2. PCtoLCD2002 取模配置与操作全流程2.1 软件初始化设置打开软件后先不要急着输入汉字。第一步是把“选项”菜单里的“字模选项”设置好这一步直接决定生成的数据能不能用。字模选项对话框里需要关注这几项点阵格式选“阴码”取模走向选“逐行式”取模走向选“顺向”部分版本写的是“正向”输出数制选“十六进制”每行显示数选“16”或者“32”看你的代码风格这个只是格式化显示不影响数据内容自定义格式清空“索引格式”和“数据格式”只保留 C51 格式或直接留空这几项是配合 SSD1306 驱动最常见的选择。很多人在这里选成了“阳码”或者“逆向”结果就是花屏、镜像、旋转。下面我逐个解释为什么这么选。2.2 关键参数设置详解点阵格式为什么选阴码阴码表示“有笔画的地方写 1没笔画的地方写 0”。SSD1306 的显存规则是写入 1 点亮对应像素。用阴码生成的字模数据直接写入显存就是正常显示。如果选了阳码等于将颜色反转写进去就是“黑底白字”——在 OLED 上通常表现为笔画是暗的背景是亮的看起来像反色。取模走向为什么选逐行式逐行式指数据按行存放先取第 0 行的 16 个点用两个字节表示第 0 字节、第 1 字节再取第 1 行……直到第 15 行。SSD1306 的页寻址模式Page Addressing Mode恰好就是一页一页地写数据每页对应 8 行像素。16x16 的汉字正好占 2 页每页 2 个字节16 列 / 8 2 字节。逐行式取模和页寻址模式配合驱动代码可以写得非常简洁。取模走向为什么选顺向顺向表示每一行的数据从左往右排列。屏幕上的列地址本来就是从左往右递增的顺向取模可以直接把数据顺序写入显存。如果选了逆向字模数据左右镜像显示出来就是倒着的字只能通过修改驱动代码里的列地址参数来补救非常麻烦。输出数制为什么选十六进制因为 C 语言里十六进制字节数组写起来最直观0x00、0xFF 一眼能看清数据分布。当然选十进制也能用但十六进制的字模和取模预览图对照起来更舒服。2.3 实际操作输入汉字、生成字模、另存为 C 文件参数设置好之后操作流程就简单了在左侧“输入”框里输入你要显示的汉字比如“你好世界”。注意一次不要输入太多逐个汉字生成会更方便管理。在“取模宽度”和“取模高度”里分别填 16、16。这是最常用的汉字点阵规格。如果你想要更大更清晰的字体可以设 24x24 或 32x32但要注意屏幕高度只有 64 像素超过 64 的字体会超界。点击“生成字模”按钮右侧预览区会出现点阵预览下方信息框会生成对应的十六进制数据。点击“保存字模”按钮软件会生成一个 .c 或 .txt 文件里面是格式化好的数组。也可以直接复制信息框里的数据。生成的数据长这样示例/* ---------------- 文字: 你 ----------------- */ 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,注意这里的 32 字节是怎么分布的前 2 个字节是第 0 行16 个点2 字节接下来 2 个字节是第 1 行以此类推一共 16 行共 32 字节。这个顺序和驱动代码里的写屏函数高度相关。提示如果你发现生成的数组每一行是 4 个字节或 8 个字节不要慌这只是“每行显示数”设置不同导致的格式化差异。数据内容没变只是排版不同复制到代码里不影响使用。2.4 输出格式核对生成完字模先不要急着复制我建议花十秒钟对照一下预览点阵和数组内容确认数据确实对应你输入的汉字。常见的错误是输入的汉字没被识别成 GB2312/GBK 编码繁体字、生僻字可能超出字库显示为空白或者点阵预览方向异常。这一步核对好了后面能省很多调试时间。另外如果你需要显示英文和数字也用同样的方式取模只是高度可以设为 8x16 或 16x8更省显存。OLED 的字体显示完全可以混合英文用 6x8 的 ASCII 字库汉字用 16x16这样排版更紧凑。PCtoLCD2002 的字符模式下可以直接生成 ASCII 字模操作一样只需要切换输入模式。3. 完整显示代码从底层驱动到汉字调用3.1 底层 I2C 与 SSD1306 驱动基础0.96 寸 OLED 最常见的是 I2C 接口4 个引脚VCC、GND、SCL、SDA。在 STM32 上用 HAL 库驱动非常成熟。我先给出一个最小可用的底层驱动框架代码基于 STM32F103 系列 HAL 库但逻辑对所有使用 HAL I2C 的芯片通用。首先是 OLED 初始化相关的宏定义和底层写命令/写数据函数#include stm32f1xx_hal.h #define OLED_ADDR 0x78 // 7位地址0x3C左移一位 #define OLED_CMD 0x00 // 控制字节命令 #define OLED_DATA 0x40 // 控制字节数据 extern I2C_HandleTypeDef hi2c1; static void OLED_WriteCmd(uint8_t cmd) { uint8_t buf[2]; buf[0] OLED_CMD; buf[1] cmd; HAL_I2C_Master_Transmit(hi2c1, OLED_ADDR, buf, 2, 100); } static void OLED_WriteData(uint8_t data) { uint8_t buf[2]; buf[0] OLED_DATA; buf[1] data; HAL_I2C_Master_Transmit(hi2c1, OLED_ADDR, buf, 2, 100); }实际项目里建议对 HAL_I2C_Master_Transmit 做一层带超时和错误处理的封装但这里是示例代码保持精简就好。然后是 SSD1306 的初始化序列。这段序列是所有 SSD1306 驱动通用的直接抄即可不需要理解每一个命令的含义但核心命令的作用我会在下文说明void OLED_Init(void) { HAL_Delay(100); OLED_WriteCmd(0xAE); // 关闭显示 OLED_WriteCmd(0x20); // 设置内存寻址模式 OLED_WriteCmd(0x02); // 页寻址模式 OLED_WriteCmd(0xB0); // 设置页起始地址第0页 OLED_WriteCmd(0xC8); // 扫描方向从上到下 OLED_WriteCmd(0x00); // 设置列地址低4位 OLED_WriteCmd(0x10); // 设置列地址高4位 OLED_WriteCmd(0x40); // 设置起始行 OLED_WriteCmd(0x81); // 设置对比度 OLED_WriteCmd(0x7F); // 对比度值 OLED_WriteCmd(0xA1); // 段重映射左右反置 OLED_WriteCmd(0xA6); // 正常显示不是反色 OLED_WriteCmd(0xA8); // 设置多路复用比 OLED_WriteCmd(0x3F); // 64路 OLED_WriteCmd(0xA4); // 关闭整个显示保持RAM内容 OLED_WriteCmd(0xD3); // 设置显示偏移 OLED_WriteCmd(0x00); // 偏移0 OLED_WriteCmd(0xD5); // 设置时钟分频 OLED_WriteCmd(0x80); // 分频值 OLED_WriteCmd(0xD9); // 设置预充电周期 OLED_WriteCmd(0xF1); // 预充电值 OLED_WriteCmd(0xDA); // 设置COM引脚硬件配置 OLED_WriteCmd(0x12); // 配置值 OLED_WriteCmd(0xDB); // 设置VCOMH OLED_WriteCmd(0x40); // VCOMH值 OLED_WriteCmd(0x8D); // 设置电荷泵 OLED_WriteCmd(0x14); // 开启电荷泵 OLED_WriteCmd(0xAF); // 开启显示 OLED_Clear(); }这段命令里有一个非常关键的细节0xC8 是页扫描方向从上到下0xA1 是段重映射这两个命令决定了屏幕的左右、上下方向。如果你手上的屏显示方向不对通常就是这两个命令和你的硬件走线不匹配。我自己的做法是先默认用上面的配置如果出现镜像就换 0xC0扫描方向从下到上或 0xA0取消段重映射再试。3.2 页寻址模式下的显存写入函数SSD1306 在页寻址模式下显存被分成 8 页每页 8 行像素64 行 / 8 8 页。写数据时要先设置页地址0xB0~0xB7再设置列地址低 4 位 高 4 位然后连续写入数据列地址会自动递增。这意味着要写一个 16x16 的汉字需要分两页写入第 0 页PAGE0写入汉字的第 0~7 行数据共 2 字节第 1 页PAGE1写入汉字的第 8~15 行数据共 2 字节坐标到页的换算关系是页号 y / 8。比如要显示在 y16 的位置页号就是 2。列地址就是 x 坐标本身。下面给出一个直接显示 16x16 汉字的函数输入参数是页号和列号void OLED_ShowChinese(uint8_t page, uint8_t x, const uint8_t *data) { // 设置页地址 OLED_WriteCmd(0xB0 page); // 设置列地址 OLED_WriteCmd(((x) 0x0F)); OLED_WriteCmd(0x10 | (((x) 4) 0x0F)); // 写入上半部分第0~7行 for (uint8_t i 0; i 2; i) { OLED_WriteData(data[i]); } // 切换到下一页 OLED_WriteCmd(0xB0 page 1); OLED_WriteCmd(((x) 0x0F)); OLED_WriteCmd(0x10 | (((x) 4) 0x0F)); // 写入下半部分第8~15行 for (uint8_t i 2; i 4; i) { OLED_WriteData(data[i]); } }注意这里我用了“页 列”的定位方式而不是常见的 x/y 像素坐标。之所以这么写是因为 PCtoLCD2002 逐行式取模的数据天然就是按页组织的用页定位最直接代码也最简洁。你可以把它封装成带 x/y 坐标的版本但内部还是要转换成页。如果你需要同时显示多个汉字只需要按顺序遍历字模数组更新列地址即可。下面是显示字符串的示例void OLED_ShowChineseString(uint8_t page, uint8_t x, const uint8_t *data, uint8_t count) { for (uint8_t i 0; i count; i) { OLED_ShowChinese(page, x i * 16, data[i * 32]); } }这里的 32 字节对应一个 16x16 字模64 字节对应两个以此类推。字模数组的排列顺序必须和字符串顺序一致。3.3 字模数组与内码索引假设你要显示“你好世界”四个字可以把四个字的字模按顺序放在一个数组里const uint8_t Chn_Data[] { 0x00,0x00,... // “你”的32字节 0x00,0x00,... // “好”的32字节 0x00,0x00,... // “世”的32字节 0x00,0x00,... // “界”的32字节 };直接按顺序调用就能显示整句。但这样有一个问题如果你想做汉字库比如几千个常用汉字就不可能把每个字的字模都放在一个数组里得按照编码规则排列再写一个查表函数。最常用的方案是把字模文件按 GB2312 编码顺序排列汉字内码减去 0xA0 得到区位码再通过计算公式得到数组下标。驱动里可以根据汉字字符直接计算出它在字库数组里的偏移。简单说是这样GB2312 编码中一个汉字占两个字节第一字节是区码第二字节是位码。比如“啊”的 GB2312 编码是 0xB0A1区码是 0xB0位码是 0xA1。字库数组里如果按“区码从 0xA1 到 0xF7、位码从 0xA1 到 0xFE”的顺序存放 16x16 字模那么某个汉字的偏移计算公式就是offset ((区码 - 0xA1) * 94 (位码 - 0xA1)) * 3294 是因为一个区里最多 94 个位。这个方案的优点是省 Flash缺点是需要把整个字库刷进去2MB 的 Flash 都显得紧张。如果你的单片机内存足够大、又想灵活增删字模用我上面给的“按需取模、按顺序排列”的方案更实用。大部分项目显示的汉字数量非常有限完全没必要上整个字库。经验我做过一个温湿度计只需要显示“温度”“湿度”“当前”“正常”“异常”这五组词总共 11 个汉字按需取模总共才 352 字节一个 16K 的 Flash 芯片都绰绰有余。不要一开始就想着做全字库那是项目规模发展到一定程度才需要考虑的事。3.4 完整调用示例显示“你好世界”把上面所有代码组合起来main 函数里的调用逻辑就是这样int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); OLED_Init(); OLED_Clear(); // 在第0页、列0位置显示“你好世界” OLED_ShowChineseString(0, 0, Chn_Data, 4); while (1) { } }OLED_Clear 函数是把显存全部清 0实现方式很简单遍历 8 页每页写 128 个 0void OLED_Clear(void) { for (uint8_t page 0; page 8; page) { OLED_WriteCmd(0xB0 page); OLED_WriteCmd(0x00); OLED_WriteCmd(0x10); for (uint8_t i 0; i 128; i) { OLED_WriteData(0x00); } } }这段代码在每次刷新前调用避免残影。清屏后你的“你好世界”会在屏幕左上角显示字与字之间没有空隙每个字恰好占 16 列看起来是紧凑的。这里我给一个完整的显示效果对照四个 16x16 的汉字水平排列占满 64 列宽度垂直方向占 16 行高度位于屏幕顶部区域。这是最基础的用法也是后面所有复杂显示菜单、动画、波形的基础。4. 常见问题与排查技巧4.1 常见问题速查表OLED 显示汉字不成功绝大多数情况不是代码逻辑问题而是取模配置或物理连接问题。我把这几年积累的典型问题整理成一张表出现问题时先逐个对照排查现象可能原因解决方法花屏、满屏乱点取模点阵格式选错阳码/阴码反了回到 PCtoLCD2002把点阵格式改成阴码汉字上下颠倒扫描方向命令不对初始化命令里把 0xC8 改成 0xC0 试试汉字左右镜像段重映射命令不对初始化命令里把 0xA1 改成 0xA0 试试显示反色0xA6/0xA7 命令设置反了确认用的是 0xA6正常显示文字缺一半写屏时页地址没切换对检查 OLED_ShowChinese 里的页切换逻辑文字错位、乱序每行显示数设置不同导致数据排列错位确认复制数据时的排版格式重新生成屏幕不亮I2C 地址错误或接线问题用 I2C 扫描程序确认地址检查上拉电阻屏幕亮但无内容对比度太低初始化里 0x81 后跟的数值调大比如 0xFF刷新慢、闪烁每帧全屏刷新数据量太大改成局部刷新只更新变化区域这里我特别强调一下 I2C 地址的问题。0.96 寸 OLED 的 I2C 地址常见是 0x3C 或 0x3D取决于模块上地址选择电阻。很多模块的 7 位地址是 0x3C转换成 8 位写地址就是 0x78。如果你的驱动写 0x78 没反应先检查你的模块是不是 0x7A7 位地址 0x3D。最快的排查方式是用一个简单的 I2C 扫描程序把总线上所有设备的地址打印出来。4.2 花屏的底层原因与调试思路花屏是 OLED 新手遇到最多的问题而且千奇百怪。我见过最典型的一种取模设的是“逐列式”驱动里却按“逐行式”解析数据显示出来就像打乱的拼图完全看不出字形。解决办法只有一个回到 PCtoLCD2002重新设置取模走向为逐行式生成数据后再把数据的前两行和最后两行打印出来和预览图逐字节核对。还有一种花屏容易被忽略字模数组越界。比如你定义了一个 16x16 的数组但生成数据时取模宽度填成了 32数据长度变成了 64 字节你的数组只放了 32 个元素C 语言里读越界数据会读出随机值屏幕上就会出现乱码。这个错误在编译阶段不会报错运行时像随机花屏排查起来很费劲。所以一个非常值得养成的习惯是拿到任何一组字模数据先数一下字节数。16x16 必须是 32 字节8x16 是 16 字节32x32 是 128 字节如果按逐行式扫描行数 32 x 每行 4 字节 128 字节。这个简单的数字检查能避免很多低级别错误。此外代码层面的问题也可能表现为“显示一点就死机”。比如 HAL_I2C_Master_Transmit 的超时时间设置太短再加上 OLED 初始化时电容充电、电荷泵启动需要时间很容易在开机瞬间超时。遇到这种问题把超时时间从 10ms 加大到 100ms或者初始化前加 100ms 延时大概率能解决。4.3 关于刷新速率与动态显示OLED 虽然响应速度快但通过 I2C 刷新数据并不快。I2C 标准模式 100Kbps快速模式 400Kbps。16x16 汉字 32 字节一屏显示 8 个字也就 256 字节加上命令开销400Kbps 下刷新一屏大约 10ms 左右人眼感知不到。但如果整屏全刷新128x64 1KB快速模式下需要 20ms 以上刷新动画能明显感到卡顿同时 I2C 总线上其他设备也会被占用。所以做动态显示的时候尽量做局部刷新。比如一个时钟应用秒钟在变化你可以只更新秒钟对应的那一小段区域而不是整屏重画。局部刷新的核心是维护一个脏矩形dirty rect每次只更新变化的部分。这个思路在嵌入式 UI 开发里非常实用能在小内存单片机上做出流畅的动态效果。5. 进阶玩法图片取模、动态图与 GUI 框架思路5.1 用 PCtoLCD2002 给图片取模PCtoLCD2002 不只是能取汉字还能取图片。菜单栏里选择“文件 - 打开图片”导入一张 BMP 或 JPG 图片软件会自动转为单色位图。这时你要重点设置的是“取模走向”和“字节内排列方向”因为图片数据的扫描方式和汉字一样必须和驱动的显存组织匹配。对于 SSD1306 的页寻址模式推荐设置是点阵格式阴码黑底白图的图片用阴码白底黑图用阳码取模走向逐行式每行显示数按图片宽度设置宽度不是 8 的倍数时要补位图片取模生成的数据量直接取决于图片尺寸。一张 128x64 的满屏图片生成的数据是 1KB。这个大小对 STM32 的 Flash 来说完全可以接受因此很多产品的开机 logo 就是这么做的。但要注意图片取模之前要先把图片处理成单色位图而且原始图片的尺寸最好就是 128x64 或者 128 的约数否则缩放失真严重影响显示效果。我个人习惯用 Photoshop 或在线工具先把图片转成 1-bit BMP再导入 PCtoLCD2002这样可控性最高。5.2 动态图取模的思路很多人搜过“动态图取模软件”但实际做 OLED 动画的人都知道不是真的把 GIF 转成字模那么简单。OLED 动画的本质是一系列帧每帧是一张单色位图按顺序刷新显示。比如一个 8 帧的走路动画每帧 128x64 的位图就是 1KB总共 8KB还得外加帧率控制逻辑。PCtoLCD2002 本身不直接支持 GIF 分解成帧但你可以用视频处理工具把 GIF 拆成连续帧再批量导入取模。还有一个技巧如果动画只在小范围移动比如一个图标从左往右滑可以只取运动区域的帧其余部分保持不变这样每帧的数据量大幅下降。动态图取模要注意帧间隔。OLED 的余晖效应很弱帧率低于 15fps 会出现肉眼可见的闪烁。在 400Kbps 的 I2C 下一帧满屏 1KB 数据大约需要 20ms也就是极限帧率约 50fps看起来完全流畅。但要注意 I2C 总线不能被其他传感器比如 MPU6050长期占用否则刷新会卡顿。5.3 更进一步带缓冲的 GUI 绘制如果你觉得直接操作页地址和列地址太底层可以考虑在内存里开一个 1KB 的显存缓冲区128x64 / 8 1024 字节所有绘制操作先写缓冲区最后一次性把缓冲区刷到 SSD1306。这个方案的好处是简化了绘制逻辑支持像素级别的点、线、圆、矩形绘制还能结合局部刷新提高性能。开缓冲区的代价是 RAM 占用。STM32F103C8T6 有 20KB RAM1KB 缓冲区完全不是问题。但如果在资源更紧张的单片机上比如 2KB RAM 的芯片就要权衡了。带缓冲区之后字模的写入方式也变了——不再依赖页寻址模式而是按像素坐标直接修改缓冲区对应 bit 位void OLED_DrawPoint(uint8_t x, uint8_t y, uint8_t color) { if (x 128 || y 64) return; if (color) { OLED_Buffer[x (y / 8) * 128] | (1 (y % 8)); } else { OLED_Buffer[x (y / 8) * 128] ~(1 (y % 8)); } }显示汉字时把字模数据的每一位作为点阵坐标逐点写入缓冲区void OLED_ShowChineseBuf(uint8_t x, uint8_t y, const uint8_t *data) { for (uint8_t row 0; row 16; row) { for (uint8_t col 0; col 16; col) { uint8_t byte data[row * 2 col / 8]; uint8_t bit byte (0x80 (col % 8)); OLED_DrawPoint(x col, y row, bit ? 1 : 0); } } }这段代码里有一个细节值得注意PCtoLCD2002 生成的逐行式字模数据是“高位在前”也就是每字节的最高位对应最左边的像素。所以判断每一位时用 0x80 (col % 8) 逐位往右扫。如果你的驱动里用的是“低位在前”这里要改成 0x01 (col % 8)。这个方向问题经常被忽略一旦搞错汉字显示出来就是左右镜像。带缓冲区的架构还有一个好处屏幕闪烁明显减少。因为你是先把整个帧画在缓冲区里再一次刷屏中间状态不会外露。对于需要绘制动态波形的项目这种方式绝对是首选。6. 我的实操体会先固定取模参数再写驱动代码在 OLED 项目上我踩过的坑不算少但绝大多数都能归结到一个问题上取模参数和驱动代码不匹配。所以我的建议非常明确——先定取模参数再写驱动代码两者一一对应不要东改一点西改一点。PCtoLCD2002 里的每个选项都不是随意的阴码、逐行式、顺向、十六进制这四个参数就是 SSD1306 的标准组合。你可能会遇到有人推荐“逐列式 逆向”那一定是配了另一种驱动或者另一种寻址模式千万不要混搭。如果你的项目能顺利显示汉字后面的路就宽了显示传感器数据、做菜单逻辑、绘制波形曲线、做开机动画逻辑都是同一套——把字模或图像数据按照正确的格式写入显存。我目前在做的项目已经在上面的基础上扩展了一套带缓冲的小型 GUI字模、图片、动画统一管理效果很稳定。最后分享一个小技巧PCtoLCD2002 生成的数组文件顶部会有一行注释记录你当前使用的取模参数。把它连同字模数据一起保存到工程里的 .h 文件头部哪怕几个月后回头维护代码也能一眼看明白这个文件是用什么参数生成的。这行注释关键时刻能救你一命。