《Arduino 手册(思路与案例)》栏目介绍:
在电子制作与智能控制的应用领域:广泛涉及了Arduino BLDC、Arduino CNC、Arduino ESP32 SPP、Arduino FreeRTOS、Arduino FOC、Arduino GRBL、Arduino HTTP、Arduino HUB75、Arduino IoT Cloud、Arduino JSON、Arduino LCD、Arduino OLED、Arduino LVGL、Arduino PID 及 Arduino TFT 等方面的相关拓展思路和众多参考案例。本专栏目前博客近2300篇。
https://blog.csdn.net/weixin_41659040/category_12422453.html
Arduino是一个开放源码的电子原型平台,它可以让你用简单的硬件和软件来创建各种互动的项目。Arduino的核心是一个微控制器板,它可以通过一系列的引脚来连接各种传感器、执行器、显示器等外部设备。Arduino的编程是基于C/C++语言的,你可以使用Arduino IDE(集成开发环境)来编写、编译和上传代码到Arduino板上。Arduino还有一个丰富的库和社区,你可以利用它们来扩展Arduino的功能和学习Arduino的知识。
Arduino的特点是:
1、开放源码:Arduino的硬件和软件都是开放源码的,你可以自由地修改、复制和分享它们。
2、易用:Arduino的硬件和软件都是为初学者和非专业人士设计的,你可以轻松地上手和使用它们。
3、便宜:Arduino的硬件和软件都是非常经济的,你可以用很低的成本来实现你的想法。
4、多样:Arduino有多种型号和版本,你可以根据你的需要和喜好来选择合适的Arduino板。
5、创新:Arduino可以让你用电子的方式来表达你的创意和想象,你可以用Arduino来制作各种有趣和有用的项目,如机器人、智能家居、艺术装置等。
概念概述
Arduino OLED 指的是将 Arduino 开发平台与 OLED(有机发光二极管)显示屏相结合的应用组合。Arduino 是开源电子原型平台,具备灵活的硬件扩展性和简单易上手的编程环境;OLED 显示屏则以其自发光、高对比度、宽视角、响应速度快等优势,为信息展示提供了优质的视觉体验。二者结合能实现各类数据显示、图形绘制及交互界面展示等功能,在电子制作、物联网、机器人等诸多领域广泛应用。
详细解释
Arduino 相关特性
硬件特性
开源设计:Arduino 的硬件设计方案完全公开,用户能够获取其原理图、PCB 版图等详细资料。这不仅降低了开发成本,还方便开发者根据自身需求对硬件进行修改和扩展,例如制作自定义外形或功能的开发板。
丰富接口资源:Arduino 开发板配备了多种类型的接口。数字输入输出引脚可用于连接开关、继电器、LED 等设备,实现数字信号的读取和输出控制;模拟输入引脚能够采集如温度传感器、光照传感器输出的连续模拟信号,经内部 ADC(模拟 - 数字转换器)转换为数字值供程序处理。
多种供电方式:支持 USB 供电、外接电源适配器供电以及电池供电等多种方式。使用 USB 供电时,可方便地与计算机连接进行程序上传和调试;外接电源适配器则能提供稳定的电源,适用于长时间运行的项目;电池供电赋予了 Arduino 设备便携性,可应用于移动监测等场景。
软件特性
简易编程环境:Arduino 使用基于 C/C++ 的编程语言,其语法简洁易懂。Arduino IDE 是专门为其开发的集成开发环境,具有跨平台性,可在 Windows、Mac OS、Linux 等操作系统上运行。IDE 提供了直观的代码编辑界面、便捷的编译和上传功能,还内置了大量示例代码,帮助初学者快速入门。
庞大的库资源:Arduino 社区拥有丰富的开源库,涵盖了传感器驱动、通信协议、图形绘制等各个领域。例如,Wire 库用于 I2C 通信,SPI 库用于 SPI 通信,开发者可以直接调用这些库,无需从头编写底层代码,大大提高了开发效率。
OLED 显示屏特性
显示原理
OLED 基于有机材料的电致发光特性工作。当在有机材料层两端施加电压时,电子从阴极注入,空穴从阳极注入,二者在有机材料中相遇并复合,释放出能量以光的形式呈现,从而实现发光显示。由于每个像素都能独立发光,OLED 显示屏无需背光源。
性能优势
自发光与高对比度:自发光特性使得 OLED 能够实现真正的黑色显示,因为不发光的像素完全不产生光线。这使得其对比度极高,图像的亮部更亮,暗部更暗,色彩表现更加生动逼真。
宽视角:OLED 的视角非常宽广,通常可达 170° 以上。从不同角度观看显示屏,画面的颜色和亮度变化极小,能为用户提供一致的视觉体验,适用于各种需要多角度观察的应用场景。
快速响应时间:OLED 的响应时间极短,一般在几微秒到几十微秒之间。相比传统的液晶显示屏,OLED 在显示动态画面时不会出现拖影现象,能够清晰、流畅地展示快速变化的图像,如动画、视频等。
轻薄与低功耗:由于无需背光源,OLED 显示屏的结构更加简单,厚度更薄,重量更轻。同时,其在显示黑色画面时几乎不消耗电能,只有发光的像素才会消耗功率,因此在显示深色画面较多的场景下,功耗显著降低。
Arduino 与 OLED 的连接和通信
通信接口类型
SPI(Serial Peripheral Interface):SPI 是一种高速的全双工串行通信协议,Arduino 通过 SPI 接口与 OLED 显示屏连接时,通常需要使用时钟线(SCK)、主输出从输入线(MOSI)、主输入从输出线(MISO)和片选线(SS)。SPI 通信速度快,适合需要快速传输大量数据的应用场景,如显示高分辨率的图像或视频流。
I2C(Inter - Integrated Circuit):I2C 是一种串行通信协议,使用两根线进行通信,即时钟线(SCL)和数据线(SDA)。I2C 接口简单,占用 Arduino 的引脚资源少,并且支持多个设备挂载在同一总线上,通过不同的设备地址进行区分。在一些对引脚资源要求较高的项目中,I2C 接口更为适用。
通信流程
初始化:在 Arduino 代码中,首先需要初始化所选的通信接口(SPI 或 I2C),并设置相关的通信参数,如时钟频率、设备地址等。
发送数据:Arduino 根据需要显示的内容,将数据按照 OLED 显示屏的通信协议进行编码,然后通过通信接口发送给 OLED 显示屏。数据可以是字符、数字、图形等信息。
显示更新:OLED 显示屏接收到数据后,对其进行解码和处理,将相应的内容显示在屏幕上。为了实现动态显示效果,Arduino 可以定期更新发送的数据,使 OLED 显示屏不断刷新显示内容。
应用场景
数据监测与显示:在环境监测系统中,Arduino 连接各种传感器(如温度传感器、湿度传感器、空气质量传感器等)采集环境数据,然后将数据通过通信接口传输到 OLED 显示屏上进行实时显示。用户可以直观地了解环境参数的变化情况。
智能家居控制:在智能家居系统中,Arduino 作为控制核心,连接各种家电设备和传感器。OLED 显示屏可以显示家电设备的状态(如开关状态、温度设置等),并提供操作菜单,用户可以通过触摸按键或其他输入设备在 OLED 显示屏上进行操作,实现对家电设备的远程控制。
机器人交互界面:在机器人项目中,OLED 显示屏可以作为机器人的交互界面,显示机器人的工作状态、任务进度、传感器数据等信息。同时,还可以显示一些动画或图标,增强机器人的人机交互体验。
手持设备与可穿戴设备:由于 OLED 显示屏的轻薄和低功耗特性,与 Arduino 结合可用于开发手持设备和可穿戴设备。例如,制作一个便携式的健康监测设备,通过 Arduino 连接心率传感器、计步器等,将监测数据显示在 OLED 显示屏上,方便用户随时查看自己的健康状况。
在Arduino项目中,OLED之表情动画显示(Facial Expression Animation Display on OLED) 是一种利用OLED屏幕展示动态表情的技术。它通过一系列预定义的图像帧来模拟面部表情的变化,从而增加人机交互的趣味性和直观性。这种技术广泛应用于各种嵌入式设备中,为用户提供更加丰富的互动体验。
一、主要特点
- 高度可定制化
开发者可以根据需求设计不同的面部表情和动画序列,如微笑、眨眼、惊讶等。
支持自定义分辨率和颜色深度,适应不同尺寸和类型的OLED屏幕。 - 轻量级实现
相比于复杂的图形库或高级处理器,使用Arduino与OLED屏可以实现低资源占用的表情动画显示。
多数OLED驱动库(如Adafruit_SSD1306、U8g2lib)提供了基本的绘图功能,便于快速开发。 - 灵活性强
动画帧可以通过数组存储在内存中,也可以从外部存储器(如SD卡)读取,支持动态加载和更新。
可以轻松集成其他传感器或输入设备,响应用户操作触发相应的表情变化。 - 视觉效果生动
表情动画能够有效吸引用户的注意力,并传达情感信息,增强用户体验。
配合声音或其他反馈机制,可以创建更具沉浸感的交互环境。 - 低功耗优势
OLED屏幕具有自发光特性,像素点亮时才消耗电能,相比传统LCD屏幕更节能。
动态显示内容可根据实际需要调整刷新频率,进一步优化能耗表现。
二、应用场景
- 智能穿戴设备
在智能手表或健身追踪器上显示简单的表情符号,作为通知提醒或情绪反馈。
示例:当收到朋友的消息时,屏幕上出现一个笑脸;如果检测到心率异常,则显示担忧的表情。 - 智能家居控制面板
在家庭自动化系统中,用于指示设备状态或提供用户反馈,使界面更加友好。
示例:当空调温度调节成功后,显示一个满意的笑脸;若设置失败,则显示困惑的表情。 - 教育与娱乐产品
制作基于Arduino的学习玩具或教育工具,通过表情动画帮助儿童学习情感认知或语言表达。
示例:电子宠物游戏,根据玩家的照顾情况展示开心、生气或生病的表情。 - 机器人与AI助手
作为机器人或虚拟助手的“脸”,展示实时的情感反应,提高人机交互的质量。
示例:社交机器人在与用户交谈时,根据对话内容变换表情,增进亲密度。 - 艺术装置与创意项目
结合传感器数据或其他输入源,创建具有互动性的艺术作品,展现动态表情变化。
示例:基于光线强度变化的艺术装置,随着光照条件改变而表现出不同的表情。
三、注意事项
- 帧间过渡平滑度
确保每帧之间的切换足够平滑,避免出现明显的跳动或闪烁现象。
调整合适的帧速率(FPS),通常建议保持在10-30 FPS之间,既能保证流畅性又不过分消耗资源。 - 内存管理
对于较大的动画序列或高分辨率图像,需注意Arduino内存限制,防止超出容量引发崩溃。
可采用压缩算法或减少色彩深度的方法降低单帧图片大小,或者分段加载动画帧。 - 兼容性测试
不同型号的OLED屏幕可能有不同的物理尺寸和分辨率,开发过程中应充分测试以确保显示效果一致。
使用标准库函数编写代码,以便更容易移植到其他硬件平台上。 - 电源稳定性
尤其是在电池供电的情况下,注意电源电压波动对OLED显示质量的影响。
若发现显示不稳定或出现残影现象,检查电源电路设计是否合理,
1、基础眨眼动画
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED显示屏幕的宽度,以像素计
#define SCREEN_HEIGHT 64 // OLED显示屏幕的高度,以像素计
#define OLED_RESET -1 // 不使用复位引脚
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void drawOpenEye() {
display.clearDisplay();
display.drawCircle(64, 32, 20, SSD1306_WHITE);
display.fillCircle(64, 32, 10, SSD1306_WHITE);
display.display();
}
void drawClosedEye() {
display.clearDisplay();
display.drawLine(44, 32, 84, 32, SSD1306_WHITE);
display.display();
}
void setup() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
}
void loop() {
drawOpenEye();
delay(1000);
drawClosedEye();
delay(200);
}
要点解读:
库的引入:引入了Wire.h用于I2C通信,Adafruit_GFX.h和Adafruit_SSD1306.h用于控制OLED屏幕和进行图形绘制。
初始化部分:在setup函数中,初始化OLED屏幕。若屏幕初始化失败,会在串口输出错误信息并进入无限循环。
动画函数:
drawOpenEye:绘制眼睛睁开的状态,先清空显示缓冲区,然后绘制一个大圆表示眼眶,再绘制一个填充的小圆表示眼球,最后刷新显示。
drawClosedEye:绘制眼睛闭合的状态,清空显示缓冲区后,绘制一条横线表示闭合的眼睛,然后刷新显示。
循环部分:在loop函数中,先调用drawOpenEye显示睁开的眼睛,延时1秒;再调用drawClosedEye显示闭合的眼睛,延时200毫秒,以此实现眨眼动画。
2、左右转动的眼睛动画
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED显示屏幕的宽度,以像素计
#define SCREEN_HEIGHT 64 // OLED显示屏幕的高度,以像素计
#define OLED_RESET -1 // 不使用复位引脚
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void drawEye(int pupilX) {
display.clearDisplay();
display.drawCircle(64, 32, 20, SSD1306_WHITE);
display.fillCircle(pupilX, 32, 10, SSD1306_WHITE);
display.display();
}
void setup() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
}
void loop() {
// 眼睛从左到右转动
for (int x = 44; x <= 84; x += 2) {
drawEye(x);
delay(50);
}
// 眼睛从右到左转动
for (int x = 84; x >= 44; x -= 2) {
drawEye(x);
delay(50);
}
}
要点解读:
库与初始化:同案例一,引入必要的库并完成初始化操作。
绘制函数:drawEye(int pupilX)函数用于绘制眼睛,通过传入不同的pupilX值来改变眼球的水平位置。先清空显示缓冲区,绘制眼眶和眼球,最后刷新显示。
循环部分:在loop函数中,通过两个for循环实现眼睛从左到右再从右到左的转动动画。
3、情绪化眼睛(含眨眼动画)
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED显示屏幕的宽度,以像素计
#define SCREEN_HEIGHT 64 // OLED显示屏幕的高度,以像素计
#define OLED_RESET -1 // 不使用复位引脚
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
enum Emotion { NEUTRAL, HAPPY, ANGRY };
Emotion currentEmotion = NEUTRAL;
void drawEmotionalEye(int x, int y, Emotion e) {
if (e == HAPPY) {
display.drawCircle(x, y, 15, SSD1306_WHITE);
display.drawLine(x - 10, y + 5, x + 10, y + 5, SSD1306_WHITE); // 微笑眼
} else if (e == ANGRY) {
display.drawTriangle(x - 15, y - 5, x + 15, y - 5, x, y + 15, SSD1306_WHITE); // 倒三角眼
} else {
display.fillCircle(x, y, 15, SSD1306_WHITE); // 标准圆眼
}
int pupilX = x + random(-8, 8);
int pupilY = y + random(-5, 5);
display.fillCircle(pupilX, pupilY, 5, SSD1306_BLACK);
}
void blinkAnimation() {
for (int i = 0; i <= 3; i++) {
display.clearDisplay();
int eyelidHeight = max(1, 15 - i * 5);
display.fillRoundRect(30, 32 - eyelidHeight / 2, 20, eyelidHeight, 3, SSD1306_WHITE);
display.fillRoundRect(78, 32 - eyelidHeight / 2, 20, eyelidHeight, 3, SSD1306_WHITE);
display.display();
delay(50);
}
delay(200);
for (int i = 3; i >= 0; i--) {
display.clearDisplay();
int eyelidHeight = max(1, 15 - i * 5);
display.fillRoundRect(30, 32 - eyelidHeight / 2, 20, eyelidHeight, 3, SSD1306_WHITE);
display.fillRoundRect(78, 32 - eyelidHeight / 2, 20, eyelidHeight, 3, SSD1306_WHITE);
display.display();
delay(50);
}
}
void setup() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
}
void loop() {
static unsigned long lastBlink = 0;
static unsigned long lastEmotionChange = 0;
if (millis() - lastBlink > random(3000, 5000)) {
blinkAnimation();
lastBlink = millis();
}
if (millis() - lastEmotionChange > 10000) {
currentEmotion = (Emotion)((currentEmotion + 1) % 3);
lastEmotionChange = millis();
}
display.clearDisplay();
drawEmotionalEye(40, 32, currentEmotion);
drawEmotionalEye(88, 32, currentEmotion);
display.display();
delay(100);
}
要点解读:
情绪状态机:使用enum定义三种眼部表情。
自然眨眼系统:随机间隔触发眨眼动画。
眼睑动画:通过fillRoundRect高度变化模拟。
非阻塞计时:millis()实现多时间轴管理。
4、基础表情切换(基于U8g2库)
#include <U8g2lib.h>
#include <Wire.h>
U8g2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8g2_R0, /* reset=*/ U8X8_PIN_NONE);
#define BUTTON_PIN 2
int currentEmotion = 0;
void setup() {
u8g2.begin();
u8g2.setContrast(200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
if (digitalRead(BUTTON_PIN) == LOW) {
currentEmotion = (currentEmotion + 1) % 3; // 循环切换表情
delay(300); // 防抖延迟
}
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_open_iconic_all_2x_t); // 使用内置图标字体
switch (currentEmotion) {
case 0: // 开心
u8g2.drawGlyph(32, 32, 0x0041); // 图标代码需根据实际字体调整
break;
case 1: // 中性
u8g2.drawGlyph(32, 32, 0x0042);
break;
case 2: // 生气
u8g2.drawGlyph(32, 32, 0x0043);
break;
}
} while (u8g2.nextPage());
}
要点解读:
图标字体:使用U8g2内置的open_iconic字体,通过drawGlyph绘制图标。
按钮交互:通过外部中断或轮询检测按钮状态,实现表情切换。
防抖处理:delay(300)避免按钮抖动导致多次触发。
5、动态表情动画(基于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 drawFace(bool isEyeOpen) {
display.clearDisplay();
display.drawCircle(64, 32, 30, SSD1306_WHITE); // 脸轮廓
// 绘制眼睛(动态开合)
display.fillCircle(50, 25, 5, isEyeOpen ? SSD1306_WHITE : SSD1306_BLACK);
display.fillCircle(78, 25, 5, isEyeOpen ? SSD1306_WHITE : SSD1306_BLACK);
display.drawCircle(64, 45, 10, SSD1306_WHITE); // 嘴巴
display.display();
}
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
}
void loop() {
static bool eyeState = true;
static unsigned long lastBlink = 0;
if (millis() - lastBlink > 2000) { // 每2秒眨眼一次
eyeState = !eyeState;
lastBlink = millis();
}
drawFace(eyeState);
delay(50);
}
要点解读:
动态绘制:通过isEyeOpen参数控制眼睛的填充状态,实现眨眼效果。
定时触发:使用millis()实现非阻塞定时,避免delay()阻塞主循环。
图形组合:结合圆形和填充函数构建简单表情。
6、交互式表情选择(基于U8g2库)
#include <U8g2lib.h>
#include <Wire.h>
U8g2_SSD1306_128X32_NONAME_F_HW_I2C u8g2(U8g2_R0, /* reset=*/ U8X8_PIN_NONE);
#define X_PIN A0
#define Y_PIN A1
int selectedEmotion = 0;
void setup() {
u8g2.begin();
u8g2.setContrast(200);
}
void loop() {
int xVal = analogRead(X_PIN);
// 摇杆左右控制表情选择
if (xVal < 300) selectedEmotion = (selectedEmotion - 1 + 2) % 2; // 左
else if (xVal > 700) selectedEmotion = (selectedEmotion + 1) % 2; // 右
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_open_iconic_all_2x_t);
switch (selectedEmotion) {
case 0: // 开心
u8g2.drawGlyph(16, 16, 0x0041);
u8g2.drawGlyph(48, 16, 0x0041);
u8g2.drawGlyph(32, 32, 0x0044); // 笑脸
break;
case 1: // 哭泣
u8g2.drawGlyph(16, 20, 0x0045); // 眼泪图标
u8g2.drawGlyph(48, 20, 0x0045);
u8g2.drawGlyph(32, 32, 0x0046); // 哭脸
break;
}
} while (u8g2.nextPage());
delay(100);
}
要点解读:
摇杆交互:通过模拟输入检测摇杆方向,动态更新selectedEmotion。
复合图标:组合多个图标(眼睛+嘴巴)构建复杂表情。
非阻塞延迟:delay(100)减少轮询频率,避免响应延迟。
注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。