U8g2库入门:零基础点亮OLED,兼容SSD1306/SH1106等多芯片
简介Arduino_u8g2库是面向嵌入式初学者与IoT开发者的高性能图形显示解决方案专为Arduino平台优化解决OLED、LCD及ePaper等多类显示屏在资源受限MCU上的驱动与图形渲染难题广泛适用于智能硬件原型、交互装置、物联网终端等项目。资源包共160个文件含96个C源码实现底层驱动与字体渲染、53个INO示例覆盖ST75256、SSD1327、UC1611等主流屏的初始化与绘图、4个头文件定义核心API与设备结构以及License、README等辅助文档整体7.44MB结构完整、即装即用。已有2379人学习下载说明其在实践社区中具备高参考价值。用户可直接复用数百个跨屏兼容的驱动模块、调用成熟封装的drawString/drawRect/display等API快速实现文本多语言显示、矢量图形绘制与页面刷新还可深入研究u8g2_fonts.c等关键源码理解位图压缩与内存分页机制是掌握嵌入式GUI开发不可多得的实战型代码基座。1. 这不是“又一个Arduino库”U8g2 是 OLED 屏幕的「通用遥控器」零基础也能点亮第一行字你刚拆开一块 OLED 屏幕模块插上 Arduino打开 IDE却卡在第一步屏幕不亮、乱码、或者干脆黑着——不是板子坏了也不是接线错了而是你手里的这块屏可能用的是 SSD1306 芯片隔壁同学那块是 SH1106还有一块是 ST7735虽然它其实是彩屏……每种芯片都像一台不同品牌的空调遥控器互不通用。而 U8g2就是那个能兼容几十种“空调型号”的万能遥控器它不绑定某一块屏、不依赖某一种接线方式I²C 或 SPI 都行也不挑 Arduino 型号Uno、Nano、ESP32、甚至树莓派 Pico 都能跑。它把底层芯片差异全藏起来只留给你一组简单命令drawStr()写字、drawBox()画框、sendBuffer()刷屏。对新手来说这意味着——你不用先啃完三页芯片手册就能让屏幕显示“Hello, World!”。适合谁就是那个连 I²C 和 SPI 都分不清、但想明天就做出带显示的温湿度计、电子时钟或小游戏的人。它不教你怎么造遥控器而是直接把遥控器塞进你手里还附赠说明书而且是中文注释版。2. 为什么非得是 U8g2不是 U8g也不是 Adafruit_SSD13062.1 先搞清一个事实U8g 和 U8g2 不是“升级版”而是“重写版”很多新手第一次搜“Arduino OLED”会撞见两个名字U8g 和 U8g2。看起来像 1.0 和 2.0但真相是U8g2 是从头写的全新库和 U8g 没有代码继承关系。U8g 是十多年前的老将稳定但功能封顶U8g2 是为现代需求重构的——比如支持更多新屏幕像常见的 128x64、128x32、甚至 64x48 小尺寸、更省内存这对 Uno 这类只有 2KB RAM 的板子至关重要、原生支持多种字体包括中文字体、还有关键一点它把“字体”和“图形”彻底解耦。什么意思以前你想显示中文得自己做点阵图、存进 Flash一不小心就爆内存U8g2 允许你只加载需要的字符比如只载“温”“度”“”“25”而不是整套 GB2312 字库。这就像你装 AppU8g 是打包好的整套 OfficeWordExcelPPT 全占内存U8g2 是按需下载——要写文档才下 Word要算数才下 Excel。2.2 对比 Adafruit_SSD1306专精 vs 通用选哪个取决于你“下一步想干啥”Adafruit_SSD1306 是官方出品、针对 SSD1306 芯片优化的库画圆、画线、显示图片非常顺滑文档也漂亮。但它有个硬伤只认 SSD1306。如果你换一块 SH1106 屏外观一模一样价格便宜一半代码编译通过屏幕却只闪一下就黑——因为寄存器地址不同它根本没发对指令。U8g2 则像一位老司机你告诉它“我要开一辆车”它不问品牌自动匹配钥匙、调座椅、设导航。你换屏只需改一行初始化代码里的设备名比如U8G2_SSD1306_128X64_NONAME_F_SW_I2C→U8G2_SH1106_128X64_NONAME_F_SW_I2C其余所有drawStr()、drawLine()全部照用。这不是偷懒而是把“适配硬件”的精力腾出来做真正有意思的事设计界面、加交互逻辑、连传感器。我第一次做电子秤项目中途换了三块不同来源的 OLEDU8g2 只改了三行初始化其他代码一行没动——这种确定性对新手就是最大的安全感。2.3 它到底支持哪些屏幕别背列表记住三个“锚点”就够了网上常列几十种支持型号新手一看就晕。其实你只需要盯住三个真实存在的“锚点”就能覆盖 90% 场景锚点 1128x64 分辨率—— 最常见淘宝搜“OLED 0.96 寸”基本都是它芯片多为 SSD1306 或 SH1106锚点 2128x32 分辨率—— 短条形屏常用于仪器状态栏、小型信息提示芯片多为 SSD1306锚点 364x48 分辨率—— 超迷你屏适合可穿戴或嵌入式小设备芯片多为 PCF8812。U8g2 的命名规则很直白U8G2_[芯片型号]_[分辨率]_[屏型号标识]_[模式]_[接口]。例如U8G2_SSD1306_128X64_NONAME_F_SW_I2C拆解就是SSD1306驱动芯片128X64分辨率NONAME通用无品牌屏不是某家定制FFull buffer 模式推荐新手用图像最稳SW_I2C软件模拟 I²C不用硬件 I²C 引脚接线更自由提示新手第一次用直接选NONAME开头的型号它不挑屏兼容性最强等你熟悉了再研究MINI12864或UC1701_ELECTRONIC_CUBES这类定制型号。2.4 内存友好为什么 Uno 能跑而有些库一编译就报“全局变量溢出”Arduino Uno 只有 2KB RAM但很多图形库默认建一个 128×648192 字节的帧缓冲区8KB直接超载。U8g2 的解法很务实它提供三种缓冲模式新手只需知道两个FFull buffer建完整 8KB 缓冲区画图快、刷新稳适合 Uno 以外的板子如 Mega、ESP32LPage buffer只建 128 字节一页缓冲128×1 像素内存省到极致但画复杂图形要多次刷屏稍慢U8G2_R0无缓冲不建缓冲直接发指令内存零占用但无法画任意位置像素仅限简单文本。对 Uno 新手我们不硬扛F模式而是用U8G2_SSD1306_128X64_NONAME_1_SW_I2C注意末尾是1代表单页缓冲。它只占约 130 字节 RAM足够显示多行文字简单图标且代码和F模式几乎一样以后换大板子只需改型号名不用重写逻辑。3. 第一步下载、安装、接线三分钟点亮你的 OLED3.1 下载哪里找别去 GitHub 翻源码用 Arduino IDE 内置库管理器最稳U8g2 官方维护的 Arduino 版本已收录进 Arduino IDE 的官方库索引。你不需要手动下载 ZIP、解压、放进 libraries 文件夹——那种方式容易路径错、版本混新手三天内必翻车。正确姿势打开 Arduino IDE建议 1.8.19 或 2.x 版本点顶部菜单工具 → 管理库…快捷键 CtrlShiftI在搜索框输入u8g2注意是小写 u8g2不是 U8G2找到作者为olikraus的U8g2库最新版通常是 2.39.x点右侧「安装」按钮等待进度条走完。提示安装完成后重启 IDE。别信“已安装”就完事——重启后你才能在示例菜单里看到它。这是血泪经验我第一次教 A 同学他跳过重启死活找不到示例折腾两小时才发现 IDE 没刷新库缓存。3.2 接线I²C 是新手首选四根线搞定不用纠结 MOSI/MISOOLED 模块通常有 47 个引脚。新手请只接 4 根线用 I²C 模式最省事、干扰最小OLED 引脚Arduino Uno 引脚说明VCC5V供电注意部分 OLED 标 3.3V但多数 0.96 寸兼容 5VGNDGND公共地SCLA5或SCLI²C 时钟线Uno 的硬件 I²C SCL 是 A5SDAA4或SDAI²C 数据线Uno 的硬件 I²C SDA 是 A4注意如果模块标着3.3V而你只有 5V 电源别慌——绝大多数国产 OLED 模块内部有稳压接 5V 也能正常工作。实在不放心可用 Uno 的3.3V引脚供电但亮度略低。3.3 第一个程序复制粘贴就能跑重点看懂这 5 行核心代码打开 IDE菜单文件 → 示例 → U8g2 → hello world你会看到一个叫u8g2_hello_world的例子。别急着上传我们先精读关键段落已删减无关注释保留最简结构#include Arduino.h #include U8g2lib.h // ① 必须包含这个头文件 // ② 创建 U8g2 对象指定芯片、分辨率、屏型号、缓冲模式、接口 U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* rotation: 0° */ U8X8_PIN_NONE, /* reset pin: not used */ /* I²C address: 0x3C (default for most OLEDs) */ U8X8_PIN_NONE /* clock: not used (hardware I²C) */ ); void setup() { u8g2.begin(); // ③ 初始化屏幕必须放在 setup() 里 } void loop() { u8g2.clearBuffer(); // ④ 清空画布像擦黑板 u8g2.setFont(u8g2_font_ncenB08_tr); // ⑤ 选字体8号粗宋体带中文支持 u8g2.drawStr(0, 10, Hello World!); // ⑥ 在坐标(0,10)写字 u8g2.sendBuffer(); // ⑦ 把画好的内容刷到屏幕像按“确认”键 delay(1000); }逐行解释①U8g2lib.h是总入口所有 U8g2 功能都从这里导出②这行定义了u8g2对象括号里U8G2_R0表示屏幕不旋转0°后面U8X8_PIN_NONE是占位符因为我们用硬件 I²C不需软件模拟所以 reset、clock 引脚设为“不用”③u8g2.begin()是启动命令没有它屏幕永远黑着④clearBuffer()很关键每次画新内容前必须清屏否则旧字会残留像没擦干净的黑板⑤setFont()指定字体。u8g2_font_ncenB08_tr是 U8g2 自带的中英双语字体tr terminal raster终端点阵8 号大小清晰不糊。新手别碰_cn结尾的字体那是纯中文体积大易爆内存⑥drawStr(x, y, text)x 是横向像素位置0 最左y 是纵向基线位置不是左上角y10 表示文字底部离顶边 10 像素所以实际显示在第 2 行⑦sendBuffer()是最后一步把内存里画好的图真正发给屏幕显示。漏掉这句屏幕永远不更新。3.4 上传与验证如果屏幕没亮先查这三处物理信号上传成功不代表屏幕一定亮。新手常见“编译绿、上传蓝、屏幕黑”。按顺序排查看串口监视器有没有报错IDE 底部黑色窗口如果出现U8G2: init failed或I2C: no device found说明通信失败用万用表测 SDA/SCL 是否有电压正常 I²C 空闲时SDA/SCL 都应为高电平约 5V 或 3.3V。如果量出来是 0V检查 VCC/GND 是否接反反接会烧模块用 Arduino 自带 I²C 扫描器确认地址新建草稿粘贴 Arduino 官方 I²C Scanner 代码上传后打开串口监视器115200 波特率如果看到Found address: 0x3C或0x3D说明屏在线如果什么都没检查接线是否松动尤其 GND90% 的“找不到设备”是 GND 没接牢。4. 常见问题排查新手踩坑TOP5现象、原因、解法全说透4.1 现象屏幕全白/全黑/闪一下就灭原因I²C 地址错配。多数 OLED 默认地址是0x3C但部分模块尤其山寨版出厂设为0x3D。U8g2 初始化时用错地址发指令无响应屏幕保持上电状态白或黑。解决修改初始化对象中的地址参数。原代码U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, U8X8_PIN_NONE);改为显式指定地址U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, U8X8_PIN_NONE, /* I2C address */ 0x3D);提示地址只改这一处0x3C和0x3D二选一试一次就知道。4.2 现象文字显示为方块、乱码、或只显示 ASCII原因字体未正确加载或用了不支持中文的字体。U8g2 默认字体如u8g2_font_helvB08_tf是纯英文遇到中文字符自动显示为方块。解决换用带trterminal raster或cnchinese后缀的字体并确保drawStr()中文字符串用 UTF-8 编码Arduino IDE 默认保存为 UTF-8无需额外设置u8g2.setFont(u8g2_font_wqy12_t_chinese2); // 更粗的中文但体积大慎用 // 或更轻量的 u8g2.setFont(u8g2_font_ncenB08_tr); // 推荐中英混排清晰体积小 u8g2.drawStr(0, 20, 温度25℃); // 直接写中文IDE 会自动转 UTF-84.3 现象编译报错 “U8G2_SSD1306_128X64_NONAME_F_SW_I2C does not name a type”原因库未正确安装或 IDE 未重启导致头文件未索引。也可能复制代码时把U8G2_开头的型号名拼错了比如少个2写成U8G_。解决关闭 IDE重新打开菜单草稿 → 包含库 → U8g2确认能点开复制型号名时不要手打从示例代码里 CtrlC / CtrlV检查#include U8g2lib.h是否在第一行且没有拼成U8g2.h或u8g2lib.h大小写敏感。4.4 现象屏幕显示错位、文字被截断、Y 坐标不准原因U8g2 的 Y 坐标是“文字基线”位置不是左上角。例如drawStr(0, 10)中的10是指文字底部离屏幕顶边 10 像素而字母“p”、“g”有下降部会超出。新手常误以为y0是顶边结果字全挤在顶上被切掉。解决用u8g2.getStrWidth(测试)测宽用u8g2.getAscent()获取字体上升高度即基线到顶边距离来精确定位int baseline_y 20; // 设定基线位置 u8g2.drawStr(0, baseline_y, Hello); // 若想让文字整体居中可用 int ascent u8g2.getAscent(); // 通常为 8~12 int descent u8g2.getDescent(); // 通常为 -2~-4 int text_height ascent - descent; // 总高度 int y_center 32 (text_height / 2); // 128x64 屏垂直居中 y≈32 u8g2.drawStr(0, y_center, 居中);4.5 现象用 ESP32 板子编译报错 “Wire was not declared in this scope”原因ESP32 的 I²C 库名不是Wire而是TwoWire且需手动创建实例。U8g2 默认用Wire在 ESP32 上不识别。解决为 ESP32 显式声明 I²C 实例并传入构造函数#include Wire.h TwoWire I2Cone TwoWire(0); // 创建 I²C 实例0 表示默认 I²C U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2( U8G2_R0, U8X8_PIN_NONE, U8X8_PIN_NONE, I2Cone // 关键把自定义 I²C 实例传进去 ); void setup() { I2Cone.begin(21, 22); // SDA21, SCL22ESP32 默认引脚 u8g2.begin(); }5. 从“点亮”到“做出东西”三个可立即上手的进阶技巧5.1 技巧一用drawBox()和drawFrame()快速搭界面框架告别“裸字”纯文字堆砌看着廉价加个边框、分个区域立刻专业感拉满。U8g2 的drawBox()实心矩形和drawFrame()空心边框是零成本美化神器void loop() { u8g2.clearBuffer(); // ① 画一个 120x50 的主内容框留边 u8g2.drawFrame(4, 4, 120, 50); // x4,y4,w120,h50 // ② 在框内写标题用大号字体 u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(10, 20, 温湿度监测); // ③ 画分割线分上下区 u8g2.drawLine(4, 32, 124, 32); // 横线 y32 // ④ 下半区显示数据用小号字体右对齐更清爽 u8g2.setFont(u8g2_font_ncenB08_tr); u8g2.drawStr(10, 45, 温度); u8g2.drawStr(70, 45, 25.3℃); // 右对齐70 124 - 文字宽可预估 u8g2.sendBuffer(); delay(2000); }提示drawFrame()比drawBox()更省资源只画四条线适合做边框drawBox()适合做背景色块如警告红底。所有坐标单位都是像素128x64 屏X 范围 0~127Y 范围 0~63。5.2 技巧二用u8g2_uint_t u8g2_GetStrWidth(const char *s)实现动态右对齐传感器数值长度会变“25℃” vs “102℃”固定 X 坐标会导致数字跑出屏幕。U8g2 提供getStrWidth()精确测宽实现真·右对齐String temp_str 25.3℃; u8g2.setFont(u8g2_font_ncenB08_tr); uint8_t width u8g2.getStrWidth(temp_str.c_str()); // 返回像素宽度 int x_right 128 - width - 4; // 128屏宽-4 是右留边 u8g2.drawStr(x_right, 45, temp_str.c_str());血泪经验我第一次做时钟时间从 12:05 变成 12:55数字突然右移一格还以为代码错了。后来发现是getStrWidth()没用硬编码 X 坐标导致的。5.3 技巧三用u8g2.setFontDirection(1)让文字竖排做极简状态栏某些场景如电池电量、信号强度用竖排图标更省空间。U8g2 支持字体旋转setFontDirection(0)水平默认1顺时针转 90°竖排从上到下2180°3270°u8g2.setFont(u8g2_font_unifont_t_symbols); // 符号字体 u8g2.setFontDirection(1); // 设为竖排 u8g2.drawStr(120, 10, ); // 信号图标从 (120,10) 开始向下写 u8g2.setFontDirection(0); // 记得切回水平否则后续文字全竖着注意竖排时drawStr(x,y)的y变成起始行位置文字向下延伸。务必在画完竖排内容后用setFontDirection(0)切回否则整个界面崩溃。6. 下一步学什么一条不绕弯的实战学习路径从点亮第一行字到做出能用的小项目中间不是靠“学完所有函数”而是靠“在具体任务里精准调用 35 个函数”。我给自己和学员规划的路径就是围绕三个真实需求展开每个需求只深挖最相关的 U8g2 能力绝不贪多6.1 需求一做一个实时温湿度显示器传感器 OLED这是新手第一个闭环项目读数据 → 处理 → 显示。U8g2 在这里只需掌握drawStr()显示数值已会drawFrame()画边框分区域已会clearBuffer()sendBuffer()控制刷新节奏已会新增重点drawXBM()显示小图标如温度计、水滴图标。XBMX BitMap是 U8g2 原生支持的极简位图格式一张 16x16 图标仅占 32 字节内存。你不用学图像处理直接用在线工具如 xbm.io 把 PNG 转成 C 数组粘贴进代码// 生成的温度计图标数组16x16 static const unsigned char thermometer_xbm[] U8G2_PROGMEM { 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, 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, 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, 0x00,0x00,0x00,0x00,0x00,...... // 实际 32 字节 }; // 在 loop() 中调用 u8g2.drawXBM(5, 15, 16, 16, thermometer_xbm); // x5,y15,宽16,高16,数据提示XBM 图标必须是黑白1bit尺寸建议 16x16 或 24x24太大内存吃不消。先做温度计、湿度滴、电池框三个图标界面立刻有灵魂。6.2 需求二做一个可交互的菜单系统按钮 OLED加一个按键就能切换显示“温度”、“湿度”、“时间”这才是真正的产品感。U8g2 本身不处理按键但和digitalRead()结合极简单const int buttonPin 2; int menuIndex 0; // 0温度,1湿度,2时间 void loop() { u8g2.clearBuffer(); if (digitalRead(buttonPin) LOW) { // 按下按钮低电平触发 delay(20); // 消抖 if (digitalRead(buttonPin) LOW) { menuIndex (menuIndex 1) % 3; // 循环切换 while (digitalRead(buttonPin) LOW) delay(10); // 等松手 } } switch(menuIndex) { case 0: u8g2.drawStr(0,20,温度25.3℃); break; case 1: u8g2.drawStr(0,20,湿度65%RH); break; case 2: u8g2.drawStr(0,20,时间14:30); break; } u8g2.sendBuffer(); delay(100); }关键点delay(20)消抖是后悔药没它你会按一次跳三页while (digitalRead(...) LOW)是防长按误触发确保只算一次点击。6.3 需求三做一个带动画的小游戏如贪吃蛇雏形用 U8g2 做动画核心就两个函数drawBox()画蛇身方块、clearBuffer()清上一帧。不需要多线程用millis()控制节奏即可unsigned long lastMove 0; const unsigned long moveInterval 300; // 300ms 移动一次 void loop() { unsigned long now millis(); if (now - lastMove moveInterval) { lastMove now; // ① 清屏擦掉旧蛇 u8g2.clearBuffer(); // ② 画新蛇简化版只画一个移动的方块 static int x 10, y 30; x 2; // 向右移动 if (x 120) x 0; // 到边回绕 u8g2.drawBox(x, y, 4, 4); // 4x4 的蛇头 } u8g2.sendBuffer(); }这就是贪吃蛇最简内核清屏 → 计算新位置 → 画新图形 → 刷屏。后续加食物、碰撞检测、长度增长全是这个循环的扩展。记住动画不是“画得快”而是“逻辑更新画面刷新”的节奏一致。从那以后我每次教新人都强制走一遍这三步先用drawStr显示传感器值再加drawFrame搭框架最后用drawXBM加图标——三小时一个能拿出去展示的温湿度仪就出来了。没有玄学没有黑匣子只有清晰的输入传感器读数、确定的处理U8g2 函数调用、可见的输出屏幕变化。希望帮到你。本文还有配套的精品资源点击获取