1. 从点亮第一块OLED屏幕开始:认识我们的主角SSD1306
如果你玩过ESP32或者Arduino,大概率会对一块小小的、能自发光的黑色屏幕感兴趣,那就是我们今天要深入聊的SSD1306 OLED显示屏。我刚开始接触嵌入式开发时,总觉得屏幕驱动是件麻烦事,直到用上了这块屏幕,才发现原来让硬件“开口说话”可以这么简单直接。SSD1306之所以在创客和物联网项目中如此流行,不是没有道理的。它通常有128x64的分辨率,这个尺寸不大不小,刚好能显示几行文字、画个简单的图标或者波形图,对于显示传感器数据、设备状态或者作为微型人机交互界面来说,简直是量身定做。
从硬件上看,你拿到手的模块通常只有四个引脚:GND、VCC、SCL和SDA。这清晰的结构意味着它使用的是I2C通信协议,一种只需要两根数据线就能搞定数据传输的简洁方式。更棒的是,它支持3.3V到5V的宽电压供电,这意味着无论是用5V的Arduino Uno,还是我们主角3.3V的ESP32,都可以直接连接,完全不用担心烧坏芯片。我实测下来,用ESP32的3.3V引脚供电非常稳定。这里有个新手容易踩的坑:虽然模块标称支持5V,但如果你用ESP32的5V引脚(比如USB提供的5V)直接给VCC供电,有时会因为电源噪声导致显示闪烁,所以我个人习惯是统一使用3.3V,图个心安。
那么,具体怎么连呢?记住ESP32上I2C的默认引脚:GPIO 21对应SDA(数据线),GPIO 22对应SCL(时钟线)。用四根母对母杜邦线,按照GND接GND,VCC接3.3V,SDA接21,SCL接22的方式连接即可。接好后,你可能会想,我怎么知道屏幕的I2C地址对不对?这时候就需要一个“侦探工具”——I2C扫描代码。在初始化任何I2C设备前,先运行一段扫描程序,它能帮你找出总线上所有设备的地址。SSD1306的常见地址是0x3C,偶尔也可能是0x3D。我遇到过一块屏幕死活不亮,折腾半天才发现地址是0x3D,而代码里写死了0x3C。所以,先扫描确认地址,是避免无谓排查的第一步。
2. 图形库双雄:Adafruit_GFX与u8g2究竟是何方神圣?
当我们谈驱动SSD1306时,其实是在谈如何通过代码指挥这块屏幕显示内容。直接操作屏幕的底层寄存器非常复杂,好在有图形库为我们做了封装。这就好比你想建房子,不需要从烧砖开始,直接用预制好的砖块(图形库)来砌墙就行。Adafruit_GFX和u8g2就是嵌入式图形界最著名的两套“预制砖块库”。但它们的哲学和实现方式颇有不同,选对了,开发事半功倍;选错了,可能就得像我一样踩坑半天。
先说说Adafruit_GFX。它来自知名的Adafruit公司,是一个纯粹的、硬件抽象的图形核心库。你可以把它理解为一个“绘画引擎”,它定义了drawLine(画线)、drawCircle(画圆)、print(打印文字)等一系列标准接口,但它本身并不知道怎么跟具体的屏幕硬件说话。这就需要针对具体屏幕的“驱动层”。对于SSD1306,这个驱动层就是Adafruit_SSD1306库。Adafruit_SSD1306继承自Adafruit_GFX,实现了将那些抽象的绘图命令翻译成SSD1306能听懂的I2C或SPI指令。这种架构很清晰,核心功能与硬件驱动分离,理论上你可以用同一套Adafruit_GFX的绘图代码,通过更换不同的驱动库(比如SSD1306、ST7735)来驱动不同的屏幕。
而u8g2(全称μ8g2)则走了另一条路。它是一个“全栈式”的图形库,把从底层硬件驱动到上层图形绘制的所有功能都打包在了一个库里。它内置了海量屏幕的驱动,SSD1306只是其中非常普通的一员。当你使用U8G2_SSD1306_128X64_NONAME_F_SW_I2C这样的类时,你已经同时获得了驱动和绘图能力。u8g2的设计哲学是提供一套统一的API,无论你用什么屏幕,代码写法都高度一致。它的功能极其丰富,从基本图形、文字到图标、动画支持都很全面,而且对多语言字体(包括中文)的支持是其一大强项。
我个人的体会是,如果你做一个快速原型验证,或者项目只涉及SSD1306且需要显示中文,u8g2的“开箱即用”体验非常棒。但如果你未来考虑切换屏幕类型,或者项目架构上希望严格区分硬件抽象层和图形层,那么Adafruit_GFX的模块化设计可能更合适。不过,这里我必须提一个我踩过的大坑:如果你计划在ESP32上使用流行的LVGL(一个更高级的嵌入式GUI库)来构建酷炫的界面,那么请注意,Adafruit_SSD1306驱动目前无法直接用于LVGL。原因在于LVGL的“显示刷新”机制需要驱动实现setAddrWindow和pushCo


5248

被折叠的 条评论
为什么被折叠?



