当前位置: 首页 > news >正文

OLED 显示屏——让 Arduino 拥有自己的“屏幕“

前面我们学了舵机、超声波、红外遥控,Arduino 已经能"动"、能"看"、能"遥控"了。但有个问题一直没解决——所有数据只能靠串口监视器看,你得连电脑才能知道 Arduino 在干什么。

今天这篇,我们要给 Arduino 装上一块OLED 显示屏,让它能独立显示文字、数字、图形,彻底摆脱电脑的束缚。

学完这篇,你会完成三个项目:

  • 文字显示:在 OLED 上显示自定义文字和实时数据
  • 图形绘制:画线、画圆、画矩形,制作简易仪表盘
  • 综合项目:智能测距仪:超声波测距 + OLED 实时显示,做成一个独立的小设备

一、OLED 显示屏是什么?

OLED(有机发光二极管)是一种自发光显示技术,和 LCD 不同,它不需要背光,每个像素自己发光。

OLED 的优势
  • 自发光:黑色区域完全不亮,对比度极高
  • 超薄:模块非常薄,适合嵌入各种项目
  • 低功耗:只点亮需要的像素,省电
  • 响应快:刷新速度快,适合动态显示
常见规格

Arduino 最常用的 OLED 模块是0.96 英寸 128×64 像素,有蓝色、白色、双色(上黄下蓝)等颜色可选。


二、通信方式:I2C

我们使用的 OLED 模块通过I2C 协议与 Arduino 通信,只需要 4 根线:

引脚接到作用
VCC5V(或 3.3V)供电
GNDGND接地
SCLA5I2C 时钟线
SDAA4I2C 数据线

I2C 是一种"总线"协议,多个设备可以共用 SCL 和 SDA 两根线。每个设备有自己的地址,Arduino 通过地址来区分它们。

查找 I2C 地址

OLED 模块的 I2C 地址通常是0x3C0x3D。如果不确定,可以用 I2C 扫描程序查找:

#include <Wire.h> void setup() { Serial.begin(9600); Wire.begin(); Serial.println("=== I2C 地址扫描 ==="); for (byte address = 1; address < 127; address++) { Wire.beginTransmission(address); if (Wire.endTransmission() == 0) { Serial.print("找到设备,地址: 0x"); Serial.println(address, HEX); } } Serial.println("扫描完成"); } void loop() {}

上传后打开串口监视器,它会列出所有连接在 I2C 总线上的设备地址。


三、安装必要的库

需要安装两个库:

  1. Adafruit SSD1306:OLED 驱动库
  2. Adafruit GFX Library:图形绘制库

安装步骤:

  1. 菜单工具 → 管理库
  2. 搜索Adafruit SSD1306,安装
  3. 搜索Adafruit GFX Library,安装

四、硬件清单

元件数量作用
Arduino Uno1块主控板
面包板1块搭建电路
0.96寸 OLED(I2C)1个显示屏
HC-SR04 超声波模块1个综合项目测距
杜邦线若干连接元件

五、电路接线

OLED 接线
  • VCC→ 接 5V
  • GND→ 接 GND
  • SCL→ 接 Arduino 的A5
  • SDA→ 接 Arduino 的A4
HC-SR04 接线(综合项目用)
  • VCC→ 接 5V
  • GND→ 接 GND
  • Trig→ 接 Arduino 的D9
  • Echo→ 接 Arduino 的D10

六、实验一:显示文字

在 OLED 上显示"Hello, Arduino!"和实时更新的计数器。

#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // 屏幕参数 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 // 没有复位引脚,设为 -1 // 创建显示对象 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); int counter = 0; void setup() { Serial.begin(9600); // 初始化 OLED if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("OLED 初始化失败!"); for (;;); // 初始化失败,停在这里 } Serial.println("OLED 初始化成功"); // 清屏 display.clearDisplay(); // 设置文字大小(1~5,数字越大字越大) display.setTextSize(1); // 设置文字颜色(SSD1306_WHITE 表示点亮像素) display.setTextColor(SSD1306_WHITE); // 设置光标位置(x, y) display.setCursor(0, 0); // 输出文字 display.println("Hello, Arduino!"); display.println("----------------"); display.println("OLED 显示测试"); // 将缓冲区内容刷新到屏幕 display.display(); } void loop() { // 清屏 display.clearDisplay(); display.setTextSize(2); display.setCursor(0, 10); display.println("Counter:"); display.setTextSize(3); display.setCursor(20, 35); display.println(counter); // 刷新显示 display.display(); counter++; delay(500); }
代码解读
  • display.begin(SSD1306_SWITCHCAPVCC, 0x3C):初始化 OLED,参数是 I2C 地址
  • display.clearDisplay():清空屏幕(只是清空缓冲区,还没显示)
  • display.setTextSize(n):设置文字大小,1 是最小,数字越大字越大
  • display.setCursor(x, y):设置下一个文字的起始位置
  • display.println():写入文字到缓冲区
  • display.display():把缓冲区的内容真正刷新到屏幕上

注意:所有display.println()只是写入缓冲区,必须调用display.display()才会在屏幕上显示。这样设计是为了提高刷新效率——你可以一次性准备好所有内容,再一次性刷新。


七、实验二:图形绘制

OLED 不仅能显示文字,还能画各种图形。我们用 Adafruit GFX 库提供的绘图函数来画。

#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); // 画矩形边框 display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // 画填充矩形 display.fillRect(5, 5, 40, 20, SSD1306_WHITE); // 画圆形 display.drawCircle(90, 32, 20, SSD1306_WHITE); // 画填充圆形 display.fillCircle(45, 45, 12, SSD1306_WHITE); // 画直线 display.drawLine(65, 45, 120, 45, SSD1306_WHITE); // 画三角形 display.drawTriangle(70, 55, 85, 45, 100, 55, SSD1306_WHITE); // 显示文字 display.setTextSize(1); display.setCursor(8, 8); display.setTextColor(SSD1306_BLACK); // 在白色背景上用黑色字 display.println("GFX"); display.setTextColor(SSD1306_WHITE); display.setCursor(70, 58); display.println("Shapes"); display.display(); } void loop() {}
常用绘图函数
函数作用
drawPixel(x, y, color)画一个点
drawLine(x1, y1, x2, y2, color)画直线
drawRect(x, y, w, h, color)画矩形边框
fillRect(x, y, w, h, color)画填充矩形
drawCircle(x, y, r, color)画圆形边框
fillCircle(x, y, r, color)画填充圆形
drawTriangle(x1,y1, x2,y2, x3,y3, color)画三角形
drawRoundRect(x, y, w, h, radius, color)画圆角矩形

坐标系:左上角是 (0, 0),x 向右增大,y 向下增大。屏幕右下角是 (127, 63)。


八、综合项目:智能测距仪

把超声波和 OLED 结合起来,做一个独立的测距仪——不需要连电脑,开机就能实时显示距离。

#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); const int trigPin = 9; const int echoPin = 10; void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); // 初始化 OLED display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); // 开机画面 display.setTextSize(2); display.setCursor(10, 10); display.println("Smart"); display.setCursor(10, 35); display.println("Ranger"); display.display(); delay(1500); } void loop() { // 测量距离 float distance = measureDistance(); // 清屏 display.clearDisplay(); // 画边框 display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // 标题 display.setTextSize(1); display.setCursor(30, 5); display.println("Distance Meter"); // 分隔线 display.drawLine(0, 16, 128, 16, SSD1306_WHITE); // 显示距离(大字体) display.setTextSize(3); display.setCursor(10, 25); display.print(distance, 1); // 保留1位小数 // 单位 display.setTextSize(2); display.setCursor(95, 30); display.print("cm"); // 状态指示 display.setTextSize(1); display.setCursor(5, 55); if (distance < 20) { display.println("[!!!] DANGER"); } else if (distance < 50) { display.println("[!!] WARNING"); } else if (distance < 100) { display.println("[!] CAUTION"); } else { display.println("[OK] SAFE"); } // 刷新显示 display.display(); delay(200); } float measureDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH, 30000); if (duration == 0) return 999.9; // 超时返回 999.9 return duration / 58.0; }
效果
  • 开机:显示 "Smart Ranger" 启动画面,1.5 秒后进入测距模式
  • 测距模式:实时显示距离数值(大字体),下方显示安全状态
  • 状态判断
    • < 20cm:显示DANGER
    • 20~50cm:显示WARNING
    • 50~100cm:显示CAUTION
    • > 100cm:显示SAFE

这就是一个完整的独立设备了——不需要电脑,不需要串口,开机即用。


九、OLED 显示技巧

自定义大数字

默认字体最大只有 5 号,如果想要更大的数字,可以手动绘制像素点阵,或者使用 U8g2 库(支持更多字体)。

显示中文

Adafruit SSD1306 默认不支持中文。要显示中文,需要:

  1. 准备中文字库(取模工具生成)
  2. 将字库数据存入 Arduino 的 Flash 存储
  3. display.drawBitmap()绘制

中文显示比较复杂,因为 Arduino Uno 的 Flash 空间有限(32KB),放不下完整的中文字库。如果需要中文显示,建议使用 U8g2 库,它内置了多种中文字体。

动态刷新技巧

如果整个屏幕都刷新,会有闪烁感。可以只刷新变化的部分:

// 只清除数字区域,不重绘边框和标题 display.fillRect(10, 25, 80, 25, SSD1306_BLACK); display.setTextSize(3); display.setCursor(10, 25); display.print(distance, 1); display.display();

十、常见问题排查

Q:OLED 什么都不显示?

  • 检查 I2C 地址是否正确(用扫描程序确认)
  • 检查 SCL 接 A5,SDA 接 A4
  • 确认display.begin()没有返回 false

Q:显示内容模糊或有残影?

  • 每次刷新前先调用display.clearDisplay()
  • 如果只更新部分内容,确保清除区域覆盖了旧内容

Q:屏幕亮度太低?

可以在setup()中调整对比度:

display.ssd1306_command(SSD1306_SETCONTRAST); display.ssd1306_command(255); // 0~255,255 最亮

Q:刷新速度太慢?

减少display.display()的调用频率,或者只刷新变化的区域。


十一、本篇小结

回顾一下今天学到的核心知识:

  • OLED 原理:自发光显示,高对比度,低功耗
  • I2C 通信:只需 SCL + SDA 两根线,通过地址区分设备
  • Adafruit SSD1306 库:初始化、清屏、设置光标、输出文字、刷新显示
  • Adafruit GFX 库:画点、线、矩形、圆形、三角形等图形
  • 缓冲区机制:先写入缓冲区,再一次性刷新到屏幕
  • 综合项目:超声波 + OLED = 独立测距仪

OLED 显示屏让 Arduino 项目从"只能看串口"升级为"自带屏幕的独立设备"。下一篇,我们学习温湿度传感器 DHT11——让 Arduino 能够感知环境温度和湿度,做一个气象站。

http://www.cnnetsun.cn/news/4315755.html

相关文章:

  • 自动售货机NFC支付模块集成实战:从硬件选型到交易流程的工程实践
  • ROS2 Humble机器人小车开发骨架:工程级可部署最小可行框架
  • LangGraph 节点触发机制通俗解读
  • 工厂自动化现场调试实战:从串口到总线,通信链路排查全攻略
  • 怕AIGC标红踩坑?2026年亲测15款免费降AI工具,附白嫖指南
  • 三款AI写作辅助软件横评:从选题到答辩怎么选才不踩坑?
  • PDF 转 draw.io:把 PDF 图表恢复成可编辑图形
  • OpenAI重仓医疗AI:技术拆解、落地路径与开发者实战指南
  • AI原型工具免费版靠谱吗?新手入门首选与商业项目避坑完整指南
  • Rust实现零分配预测性遥测引擎:核心设计与最小实现
  • 模型上线当天 OOM:我排查一晚才发现是模型加载方式埋的坑
  • STM32CubeMX生成CMSIS-DSP失败:M33内核手动集成指南
  • 拓扑差值论时间
  • 中国人寿半年狂赚1345亿,蔡希良把“一哥”坐实了
  • 二本逆袭阿里Java后端实习:五轮面试全流程复盘与避坑指南
  • AI-Native创业课程平台:从架构设计到代码实战
  • STM32 L452上USB外设覆盖PA11/PA12 GPIO设置的解决指南
  • ESP32上运行微型LLM:用Brainscope实时可视化Transformer推理
  • code-graph-rag实战:用代码图谱增强RAG实现仓库深度问答
  • ASP聊天室源码解析:老旧Windows服务器上的轻量级Web通信方案
  • 免费开源的 Paperwork:多系统可用,高效整理文档,强大搜索功能超便捷!
  • 从全局构建器到隔离管道:辅助工具重构实战
  • 基于机器学习与流批一体的治安案件预警系统实战解析
  • 集成ADC的宽范围电源监测器:选型、电路与实战解析
  • Qx效率启动器技术拆解:从架构设计到二次开发实践
  • macOS原生OCR:用Swift Vision实现命令行文字识别工具
  • Swarm-forge:轻量级多AI智能体协调工具解析与部署指南
  • 美团2017秋招测试开发笔试题全解析:考点、思路与复习路径
  • SDN实战入门:从Mininet+Ryu环境搭建到防火墙与负载均衡实验
  • STSPIN32G4实战:从硬件到FOC的无刷电机驱动方案解析