尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

ESP8266/ESP32 SSD1306 OLED 驱动库实战指南:ThingPulse esp8266-oled-ssd1306 4.1 的完整使用与源码剖析

ESP8266/ESP32 SSD1306 OLED 驱动库实战指南:ThingPulse esp8266-oled-ssd1306 4.1 的完整使用与源码剖析 嵌入式物联网网络安全渗透测试【免费下载链接】esp8266_deautherAffordable WiFi hacking platform for testing and learning项目地址https://gitcode.com/gh_mirrors/es/esp8266_deauther点击查看免费下载本指南围绕随仓库内置的 esp8266-oled-ssd1306-4.1.0 库官方 README 展开系统讲解 ThingPulse 出品的 SSD1306/SH1106 OLED 驱动库在 ESP8266、ESP32 与 mbed-os 平台上的安装、接线、绘制 API 与 UI 框架用法并结合当前仓库esp8266_deauther中该库的源码与集成代码剖析双缓冲刷新、增量渲染、字体跳表等底层实现。读完本文你将能够独立完成一块 128×64 / 128×32 OLED 屏幕的驱动初始化、基础绘图、文本排版以及基于 Frame/Overlay 的轮播式菜单界面开发。一、库的定位与适用场景ThingPulse OLED SSD1306 是一个面向SSD1306 128×64 与 128×32单色 OLED 显示屏的驱动库运行于 Arduino/ESP8266、ESP32 以及 mbed-os 平台同时支持I2C 与 SPI两种接口版本的显示屏。它的典型应用场景包括传感器数据展示屏温湿度、天气站、时钟交互式菜单与状态机界面如本仓库 esp8266_deauther 的 OLED 菜单基于 Frame 轮播的仪表盘自动翻页 指示器。库的初始作者是 Daniel Eichhornsquix78。二、安装方式README 提供了三种主流安装途径1. Arduino IDE 库管理器在 Arduino IDE 的「库管理器」中搜索ESP8266 and ESP32 Oled Driver for SSD1306 display即可一键安装。2. 手动解压安装将库以 zip 形式下载后解压到 Arduino 的libraries目录。3. PlatformIOplatformio lib install 5624. mbed-os该库已适配 ARM mbed-os 环境mbed-os 中以OLED_SSD1306名称提供副本。也可将以下文件复制进 mbed-os 工程OLEDDisplay.cpp OLEDDisplay.h OLEDDisplayFonts.h OLEDDisplayUi.cpp OLEDDisplayUi.h SSD1306I2C.h在 OLEDDisplay.h 中可以看到平台抽象ARDUINO环境下OLEDDisplay继承自Print__MBED__环境下继承自Stream并内置一个轻量String模拟类若两者均未定义则直接报错Unkown operating system。三、硬件抽象I2C 与 SPI 两种连接方式库通过不同的头文件封装了四种硬件通路全部继承自统一的OLEDDisplay基类接口SSD1306SH1106依赖I2CWire.hSSD1306Wire.hSH1106Wire.hWire.hI2Cbrzo_i2c汇编加速SSD1306Brzo.hSH1106Brzo.hbrzo_i2c.hSPISSD1306Spi.hSH1106Spi.hSPI.hI2C Wire.h#include Wire.h #include SSD1306Wire.h // 128x64 屏幕 SSD1306Wire display(0x3c, SDA, SCL); // ADDRESS, SDA, SCL // 128x32 屏幕需显式传入几何参数 // SSD1306Wire display(0x3c, SDA, SCL, GEOMETRY_128_32);SH1106 的用法完全一致仅替换头文件与类名#include Wire.h #include SH1106Wire.h SH1106Wire display(0x3c, SDA, SCL); // ADDRESS, SDA, SCL在源码层面SSD1306Wire 的 connect() 会调用Wire.begin(sda, scl)并执行Wire.setClock(700000)即 ESP8266 运行在 160MHz 模式下 I2C 时钟被拉高到约 700kHz而 80MHz 模式下会被限制到约 400kHz——这是官方刻意为之的提速手段也是读屏帧率的重要影响因素。另外它还提供了setI2cAutoInit(bool)用于在Wire.begin尚未被调用时就先行发送指令的场景下自动补初始化。I2C brzo_i2c更快#include brzo_i2c.h #include SSD1306Brzo.h SSD1306Brzo display(0x3c, SDA, SCL); // ADDRESS, SDA, SCL对应 SH1106#include brzo_i2c.h #include SH1106Brzo.h SH1106Brzo display(0x3c, SDA, SCL); // ADDRESS, SDA, SCLbrzo_i2c 是用汇编编写的高速 I2C 库适合对刷新率有要求的场景。SPI#include SPI.h #include SSD1306Spi.h SSD1306Spi display(D0, D2, D8); // RES, DC, CSSH1106 SPI 版只需 RES 与 DC 两个引脚#include SPI.h #include SH1106Spi.h SH1106Spi display(D0, D2); // RES, DC从 SSD1306Spi 的 connect() 可以看到 SPI 通路的关键细节将 DC、CS、RES 设为输出SPI.begin()后使用SPI.setClockDivider(SPI_CLOCK_DIV2)取最高分频并通过「RES 拉高 → 拉低 10ms → 拉高」的脉冲序列完成硬件复位。几何分辨率参数几何类型定义在 OLEDDisplay.h 中enum OLEDDISPLAY_GEOMETRY { GEOMETRY_128_64 0, GEOMETRY_128_32, GEOMETRY_RAWMODE, };所有构造函数的最后一个参数默认是GEOMETRY_128_64使用 128×32 屏幕时务必传入GEOMETRY_128_32否则取景偏移与页地址page address会不匹配。四、在 esp8266_deauther 项目中的真实集成该库正是 esp8266_deauther 项目的 OLED 显示底层。项目通过 DisplayUI.h 按编译宏选择具体驱动类#if defined(SSD1306_I2C) SSD1306Wire display SSD1306Wire(I2C_ADDR, I2C_SDA, I2C_SCL); #elif defined(SSD1306_SPI) SSD1306Spi display SSD1306Spi(SPI_RES, SPI_DC, SPI_CS); #elif defined(SH1106_I2C) SH1106Wire display SH1106Wire(I2C_ADDR, I2C_SDA, I2C_SCL); #elif defined(SH1106_SPI) SH1106Spi display SH1106Spi(SPI_RES, SPI_DC, SPI_CS); #endif而引脚、地址、屏幕方向等参数集中在 A_config.h 的板级预设中例如#define SSD1306_I2C #define I2C_ADDR 0x3C #define I2C_SDA 4 // D2 #define I2C_SCL 5 // D1以及 SPI 方案#define SH1106_SPI #define SPI_RES 5 #define SPI_DC 4 #define SPI_CS 15FLIP_DIPLAY注意原文拼写与DISPLAY_TEXT均有默认值兜底false与空串见 A_config.h#L534-L540。显示初始化在 DisplayUI.cpp 的 configInit() 中完成void DisplayUI::configInit() { display.init(); display.setFont(DejaVu_Sans_Mono_12); display.setContrast(255); if (FLIP_DIPLAY) display.flipScreenVertically(); display.clear(); display.display(); }这段代码正好覆盖了库的四个关键 APIinit()、setFont()、setContrast()、flipScreenVertically()。项目还定义了screenWidth 128、sreenHeight 64、lineHeight 12、drawInterval 10010 FPS等 UI 常量说明它实际运行在 128×64 的 I2C 屏幕上DisplayUI.h#L104-L111。注意代码注释中特别提醒遇到 char/uint8_t 类型转换编译错误时需确认安装的是 4.0 及以上版本的驱动库——这印证了 README 中「4.0 版本内部大量改动」的说法。五、核心绘制 API 全解析5.1 显示控制// 初始化显示屏会复位屏幕 void init(); // 释放显示内存 void end(); // 重新走一遍初始化流程循环复位 void resetDisplay(void); // 通过 I2C 重新连接屏幕 void reconnect(void); // 开屏 / 关屏 void displayOn(void); void displayOff(void); // 清空本地像素缓冲区 void clear(void); // 将缓冲区写入屏幕显存 void display(void); // 反色显示 / 正常显示 void invertDisplay(void); void normalDisplay(void); // 设置对比度详细说明见下 void setContrast(uint8_t contrast, uint8_t precharge 241, uint8_t comdetect 64); // 便捷调节亮度 void setBrightness(uint8_t); // 屏幕上下翻转 void flipScreenVertically(); // 屏幕镜像显示可用于镜子/投影场景 void mirrorScreen();对比度参数有非常实用的经验值README 原话极低亮度与低对比度contrast 10, precharge 5, comdetect 0正常亮度与对比度contrast 100。setContrast的后两个参数带默认值precharge 241、comdetect 64其默认值定义可见 OLEDDisplay.h#L273-L276。deauther 项目中直接用了display.setContrast(255)将对比度拉满。另外allocateBuffer()用于深度睡眠唤醒后不复位屏幕直接恢复显示它只分配缓冲区并重建连接返回是否成功而init()会同时执行驱动与屏幕初始化并复位屏幕。颜色枚举OLEDDISPLAY_COLOR含BLACK / WHITE / INVERSE三值OLEDDisplay.h#L124-L128。5.2 像素与图形绘制// 设置后续所有像素操作的颜色 void setColor(OLEDDISPLAY_COLOR color); // 在指定位置画一个像素 void setPixel(int16_t x, int16_t y); // 从 (x0,y0) 到 (x1,y1) 画一条线 void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1); // 画矩形边框 / 填充矩形 void drawRect(int16_t x, int16_t y, int16_t width, int16_t height); void fillRect(int16_t x, int16_t y, int16_t width, int16_t height); // 画圆边框 / 填充圆 void drawCircle(int16_t x, int16_t y, int16_t radius); void fillCircle(int16_t x, int16_t y, int16_t radius); // 水平 / 垂直直线 void drawHorizontalLine(int16_t x, int16_t y, int16_t length); void drawVerticalLine(int16_t x, int16_t y, int16_t length); // 圆角进度条progress 为 0~100 的无符号字节 void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress); // 绘制库内部图像格式的位图 void drawFastImage(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *image); // 绘制 XBM 位图 void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const uint8_t *xbm); // 绘制 16x16 的 XBM 图标可反色 void drawIco16x16(int16_t x, int16_t y, const char *ico, bool inverse false);其中drawProgressBar的实际实现见 OLEDDisplay.cpp#L411。所有图形最终都会经由内部统一的drawInternal写入像素缓冲区OLEDDisplay.h#L366因此绘制的顺序决定了遮挡关系且clear()只清缓冲、display()才真正上屏。5.3 文本操作// 在 (x, y) 处绘制字符串 void drawString(int16_t x, int16_t y, String text); // 带最大行宽的绘制文本超过 maxLineWidth 时 // 会在空格或短横线处自动换行 void drawStringMaxWidth(int16_t x, int16_t y, int16_t maxLineWidth, String text); // 获取当前字体下字符串的像素宽度两个重载char* 带长度 / String uint16_t getStringWidth(const char* text, uint16_t length); uint16_t getStringWidth(String text); // 设置文本对齐锚点 // TEXT_ALIGN_LEFT / TEXT_ALIGN_RIGHT / TEXT_ALIGN_CENTER / TEXT_ALIGN_CENTER_BOTH void setTextAlignment(OLEDDISPLAY_TEXT_ALIGNMENT textAlignment); // 设置字体内置 // ArialMT_Plain_10、ArialMT_Plain_16、ArialMT_Plain_24 // 或用字体工具自行生成 void setFont(const uint8_t* fontData);对齐枚举定义在 OLEDDisplay.h#L130-L135。文本渲染的内部实现是drawStringInternalOLEDDisplay.cpp#L470它按字体跳表逐个字形绘制。两个值得注意的进阶能力UTF-8 支持drawString系列在绘制前会调用utf8ascii()OLEDDisplay.cpp#L970将 UTF-8 字符转换为扩展 ASCII 再查字形表你也可以通过setFontTableLookupFunction()注册自定义的 UTF-8→字形索引映射函数OLEDDisplay.h#L256-L257。deauther 项目中就使用了replaceUtf8(str, String(QUESTIONMARK))配合中文字符集做兜底替换DisplayUI.cpp#L43-L45。日志缓冲setLogBuffer(uint16_t lines, uint16_t chars)会开辟一块行×字符的环形文本区之后可通过继承自Print的write()直接print日志再用drawLogBuffer(x, y)整块上屏非常适合滚动日志场景。5.4 字体体系字体采用一种专有但开放的二进制格式存储源码中以JUMPTABLE_BYTES/LSB/SIZE/WIDTH/START等宏描述字形的跳表头结构见 OLEDDisplay.h#L78-L90。README 提供了在线字体生成工具http://oleddisplay.squix.ch在该网站选择字体族、风格与字号预览满意后点击 Create 即可生成字体数组复制粘贴到新的或已有的头文件中即可使用。库内置三种 ArialMT 字号10/16/24所有字形数据统一存放在 OLEDDisplayFonts.h 中。除了内置字体deauther 项目还额外使用了DejaVu_Sans_Mono_12等宽字体用于菜单排版。六、UI 框架OLEDDisplayUi当界面元素增多时建议使用库自带的 UI 框架。它提供两种 UI 元素Frame帧默认行为是每帧显示固定时长后自动切到下一帧配套一个自动更新的 Indicator指示器。Overlay覆盖层始终绘制在同一位置的固定信息例如常驻时钟不受翻页动画影响。6.1 基础配置OLEDDisplayUi ui(display); // 与显示对象绑定 // 初始化显示 ui.init(); // 设置内部目标帧率 ui.setTargetFPS(30); // 自动轮播控制 ui.enableAutoTransition(); // 开启自动翻页 ui.disableAutoTransition(); // 关闭自动翻页 ui.setAutoTransitionForwards(); // 正向轮播 ui.setAutoTransitionBackwards(); // 反向轮播 // 时长配置近似值实际以 tick 计 ui.setTimePerFrame(5000); // 每帧停留约 5000ms ui.setTimePerTransition(500); // 每次过渡约 500ms // 指示器控制 ui.enableIndicator(); // 显示指示器可滑入滑出 ui.disableIndicator(); ui.enableAllIndicators(); ui.disableAllIndicators(); ui.setIndicatorPosition(BOTTOM); // TOP / RIGHT / BOTTOM / LEFT ui.setIndicatorDirection(LEFT_RIGHT); // 或 RIGHT_LEFT ui.setActiveSymbol(activeSymbol); // 自定义激活态符号 ui.setInactiveSymbol(inactiveSymbol); // 自定义非激活态符号 // 帧间动画方向 ui.setFrameAnimation(SLIDE_LEFT); // SLIDE_UP / SLIDE_DOWN / SLIDE_LEFT / SLIDE_RIGHT // 注册帧与覆盖层的绘制回调 ui.setFrames(frames, frameCount); ui.setOverlays(overlays, overlayCount); // 加载动画 ui.setLoadingDrawFunction(loadingDrawFunction); ui.runLoadingProcess(stages, stagesCount);注意ui.update()必须放在主循环loop()中持续调用它返回剩余可绘制时间ms以便你控制每帧的绘制预算。6.2 回调与状态的数据结构回调签名定义在 OLEDDisplayUi.h#L109-L111typedef void (*FrameCallback)(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); typedef void (*OverlayCallback)(OLEDDisplay *display, OLEDDisplayUiState* state); typedef void (*LoadingDrawFunction)(OLEDDisplay *display, LoadingStage* stage, uint8_t progress);OLEDDisplayUiState结构体OLEDDisplayUi.h#L86-L102包含上次更新时间戳、距上次状态切换的 tick 数、当前帧号、帧状态IN_TRANSITION / FIXED、指示器是否已绘制、过渡方向1 正向 / -1 反向、是否手动控制以及一个可存放自定义数据的userData指针。LoadingStage结构体则由process阶段名与callback阶段回调组成用于开机加载进度屏。6.3 一个完整的 Frame/Overlay 示例// 帧 1画文本 void drawFrame1(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { display-setTextAlignment(TEXT_ALIGN_LEFT); display-setFont(ArialMT_Plain_16); display-drawString(x 2, y 2, Frame 1); } // 帧 2画进度条 void drawFrame2(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) { display-drawProgressBar(x 10, y 20, 108, 10, 50); } // 覆盖层右上角常驻时钟 void drawOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) { display-setTextAlignment(TEXT_ALIGN_RIGHT); display-setFont(ArialMT_Plain_10); display-drawString(128, 0, 12:00); } FrameCallback frames[] { drawFrame1, drawFrame2 }; int frameCount 2; OverlayCallback overlays[] { drawOverlay }; int overlaysCount 1; void setup() { display.init(); ui.setTargetFPS(30); ui.setFrames(frames, frameCount); ui.setOverlays(overlays, overlaysCount); ui.setTimePerFrame(5000); ui.setTimePerTransition(500); ui.init(); } void loop() { ui.update(); }七、双缓冲与增量刷新流畅动画的底层保障README 功能清单提到「自动侧滑轮播」能力其流畅度依赖库的**双缓冲double buffering**设计。默认情况下库会定义OLEDDISPLAY_DOUBLE_BUFFER除非显式定义OLEDDISPLAY_REDUCE_MEMORY见 OLEDDisplay.h#L73-L76即维护buffer与buffer_back两个缓冲区。以 SSD1306Wire 的 display() 为例每次刷新会逐页对比buffer与buffer_back计算发生变化的包围盒minBoundX/maxBoundX、minBoundY/maxBoundY若没有任何变化minBoundY 仍为 UINT8_MAX直接返回不做任何 I2C 传输否则通过COLUMNADDR0x21与PAGEADDR0x22指令只把变化区域重新发送给屏幕数据按 16 字节一包通过 I2C 批量写出并穿插yield()保证系统任务不被饿死。x_offset (128 - width) / 2则解释了为什么 128×32 屏幕在 128 列宽的驱动下也能居中显示。SPI 版 SSD1306Spi 的 display() 采用同样策略只是将 I2C 写包替换为SPI.transfer。这套「脏矩形 增量刷新」机制让 128×64 全屏动画在 ESP8266 的有限带宽下依然可达较高帧率。八、屏幕方向与对比度调优display.flipScreenVertically(); // 上下翻转用于倒装安装的屏幕 display.mirrorScreen(); // 水平镜像镜子或投影应用 display.resetOrientation(); // 复位旋转/镜像状态flipScreenVertically在 deauther 项目里由FLIP_DIPLAY编译宏控制。低亮度场景可组合setContrast三个参数实现省电显示参考 5.1 节的经验值。setBrightness()是便捷方法内部同样走对比度寄存器。九、版本升级注意事项README 明确提示3.0 版本起 API 有较大变化4.0 版本则更换了大量内部实现并增加了更多屏幕兼容性原文分别指向UPGRADE-3.0.md与UPGRADE-4.0.md升级指南这两个指南文件未随本仓库附带需从上游 ThingPulse 仓库获取。当前仓库内置的是4.1.0版本主要面向 v4 API。一个已知的坑README 之外、deauther 代码注释也提到若在 v4 以下版本编译char与uint8_t之间的类型转换会产生编译错误遇到时应先升级到 4.0 及以上版本。十、官方 Demo 的四个经典帧README 中的 SSD1306Demo 示例展示了四个代表性帧可作为学习素材Frame 1XBM 图片绘制、不被翻页动画移动的静态文本、激活/非激活帧指示器Frame 2内置字体展示Arial 10/16/24 三档字号Frame 3文本对齐演示坐标标注了各种对齐锚点的渲染位置Frame 4drawStringMaxWidth自动换行效果适合较长文本。SPI 版 Demo 则验证了同一套 API 在 SPI 屏幕上的工作引脚见 demo 代码。README 还列举了若干基于该库的知名项目如 ThingPulse Weather Station、ESP8266 QRCode 等需要更多实战参考的读者可直接研读本仓库 DisplayUI.cpp 中基于该库实现的完整菜单、时钟、扫描动画等界面代码这是该库在真实产品级固件中最好的使用范本。参考文件索引库官方文档esp8266_deauther/src/esp8266-oled-ssd1306-4.1.0/README.md显示基类与命令定义esp8266_deauther/src/esp8266-oled-ssd1306-4.1.0/OLEDDisplay.hUI 框架头文件esp8266_deauther/src/esp8266-oled-ssd1306-4.1.0/OLEDDisplayUi.hI2C/Wire 实现esp8266_deauther/src/esp8266-oled-ssd1306-4.1.0/SSD1306Wire.hSPI 实现esp8266_deauther/src/esp8266-oled-ssd1306-4.1.0/SSD1306Spi.h库在项目中的集成esp8266_deauther/DisplayUI.h 与 esp8266_deauther/DisplayUI.cpp板级屏幕配置esp8266_deauther/A_config.h赞分享嵌入式物联网网络安全渗透测试【免费下载链接】esp8266_deautherAffordable WiFi hacking platform for testing and learning项目地址https://gitcode.com/gh_mirrors/es/esp8266_deauther点击查看免费下载相关推荐ESP8266 OLED SSD1306驱动库3.0版本升级指南ESP8266 OLED SSD1306驱动库3.0版本升级指南 前言 ESP8266 OLED SSD1306驱动库3.0版本带来了一系列重要的架构改进和新功嵌入式物联网ESP32 OLED显示实战SSD1306驱动完全指南想要在ESP32项目中添加OLED显示屏却不知从何入手SSD1306作为物联网设备中最常用的OLED显示方案能够为你的项目提供清晰直观的视觉反馈。本文将带你嵌入式驱动开发物联网嵌入式GUISSD1306 OLED显示屏驱动库完整使用指南SSD1306 OLED显示屏驱动库完整使用指南 SSD1306是一款专为有机/聚合物发光二极管点阵图形显示系统设计的单芯片CMOS OLED/PLED驱动控制驱动开发嵌入式硬件开发上一篇Ebook2Audiobook终极指南一键将电子书转换为专业有声书的完整教程下一篇10分钟掌握CEmu调试技巧提升TI-84 Plus CE程序开发效率创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表