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

别再只用串口打印了!用Arduino UNO和0.96寸OLED做个桌面小动画(附完整代码)

用Arduino UNO和0.96寸OLED打造桌面动态艺术装置

你是否已经厌倦了单调的串口打印输出?Arduino UNO搭配0.96寸OLED屏幕可以变身为一个迷你的数字画布,为你的工作台增添一抹动态的科技艺术。本文将带你超越基础的数据显示,探索如何利用这块小小的屏幕创造生动的动画效果,从随机弹跳的球体到简约的数字时钟,让你的硬件项目更具观赏性和趣味性。

1. 硬件准备与环境搭建

1.1 所需组件清单

要开始这个创意项目,你需要准备以下硬件:

  • Arduino UNO开发板:作为整个系统的控制核心
  • 0.96寸OLED显示屏(I2C接口):推荐使用SSD1306驱动的版本
  • 杜邦线若干:用于连接各组件
  • USB数据线:为Arduino供电并上传程序

硬件连接非常简单,只需将OLED的四个引脚与Arduino对应连接:

OLED引脚Arduino引脚
GNDGND
VCC3.3V或5V
SCLA5
SDAA4

1.2 软件环境配置

在开始编程前,需要安装必要的库文件:

  1. 打开Arduino IDE,点击"工具"->"管理库"
  2. 搜索并安装以下两个关键库:
    • Adafruit_GFX_Library:提供基础的图形绘制功能
    • Adafruit_SSD1306:针对SSD1306显示屏的专用驱动

提示:安装库时,建议选择最新稳定版本以确保兼容性

安装完成后,可以通过以下测试代码验证硬件连接是否正常:

#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(10, 20); display.println("OLED Test Success!"); display.display(); } void loop() {}

2. 掌握Adafruit_GFX核心绘图功能

2.1 基础图形绘制

Adafruit_GFX库提供了一系列图形绘制函数,以下是几个最常用的:

  • drawPixel(x, y, color):在指定位置绘制单个像素点
  • drawLine(x0, y0, x1, y1, color):绘制直线
  • drawRect(x, y, w, h, color):绘制空心矩形
  • fillRect(x, y, w, h, color):绘制实心矩形
  • drawCircle(x, y, r, color):绘制空心圆形
  • fillCircle(x, y, r, color):绘制实心圆形
  • drawTriangle(x0,y0,x1,y1,x2,y2,color):绘制空心三角形

2.2 文本显示技巧

除了图形,文本显示也是OLED的重要功能。关键文本函数包括:

display.setTextSize(1); // 设置字体大小(1-8) display.setTextColor(SSD1306_WHITE); // 设置文本颜色 display.setCursor(0, 0); // 设置文本起始位置 display.println("Hello World!"); // 输出文本

注意:OLED屏幕的坐标系原点(0,0)位于左上角,x轴向右增加,y轴向下增加

2.3 屏幕刷新优化

频繁刷新整个屏幕可能导致闪烁,可以采用以下优化策略:

  1. 局部刷新:只更新需要改变的部分
  2. 双缓冲技术:在内存中完成绘制后再一次性显示
  3. 合理设置刷新率:根据动画需求调整delay时间

3. 创建弹跳球动画

3.1 基础弹跳球实现

让我们从经典的弹跳球动画开始。以下代码实现了一个在屏幕边界反弹的球体:

#include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire); int ballX = SCREEN_WIDTH/2; int ballY = SCREEN_HEIGHT/2; int ballRadius = 5; int ballSpeedX = 2; int ballSpeedY = 3; void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); } void loop() { display.clearDisplay(); // 更新球的位置 ballX += ballSpeedX; ballY += ballSpeedY; // 边界检测与反弹 if(ballX <= ballRadius || ballX >= SCREEN_WIDTH-ballRadius) { ballSpeedX = -ballSpeedX; } if(ballY <= ballRadius || ballY >= SCREEN_HEIGHT-ballRadius) { ballSpeedY = -ballSpeedY; } // 绘制球体 display.fillCircle(ballX, ballY, ballRadius, SSD1306_WHITE); display.display(); delay(20); // 控制动画速度 }

3.2 添加物理效果

为了让动画更真实,可以引入简单的物理模拟:

  1. 重力加速度:让球体下落时加速
  2. 能量损失:每次碰撞后速度略微减小
  3. 随机扰动:增加运动的不确定性

改进后的物理模型代码片段:

float gravity = 0.1; float damping = 0.95; // 能量损失系数 void loop() { display.clearDisplay(); // 应用重力 ballSpeedY += gravity; // 更新位置 ballX += ballSpeedX; ballY += ballSpeedY; // 边界碰撞处理 if(ballY >= SCREEN_HEIGHT-ballRadius) { ballY = SCREEN_HEIGHT-ballRadius; ballSpeedY = -ballSpeedY * damping; // 添加随机水平扰动 ballSpeedX += random(-2, 3); } if(ballX <= ballRadius || ballX >= SCREEN_WIDTH-ballRadius) { ballSpeedX = -ballSpeedX * damping; } display.fillCircle(ballX, ballY, ballRadius, SSD1306_WHITE); display.display(); delay(20); }

4. 构建迷你数字时钟动画

4.1 基础时钟实现

结合时间功能和简单动画,可以创建一个更实用的桌面时钟:

#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include "RTClib.h" RTC_DS3231 rtc; Adafruit_SSD1306 display(128, 64, &Wire); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); if (!rtc.begin()) { while (1); } if (rtc.lostPower()) { rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } } void loop() { DateTime now = rtc.now(); display.clearDisplay(); // 绘制时钟背景 display.drawRect(10, 10, 108, 44, SSD1306_WHITE); // 显示时间 display.setTextSize(2); display.setCursor(20, 20); if(now.hour() < 10) display.print("0"); display.print(now.hour()); display.print(":"); if(now.minute() < 10) display.print("0"); display.print(now.minute()); display.print(":"); if(now.second() < 10) display.print("0"); display.print(now.second()); // 显示日期 display.setTextSize(1); display.setCursor(20, 45); display.print(now.year()); display.print("/"); display.print(now.month()); display.print("/"); display.print(now.day()); display.display(); delay(200); }

4.2 添加动画元素

让静态的时钟变得生动起来:

  1. 秒针动画:用动态弧线表示秒针移动
  2. 时间数字变化效果:数字变化时添加过渡动画
  3. 背景元素:随时间的天气图标或装饰元素

改进后的动画时钟代码片段:

void loop() { DateTime now = rtc.now(); static uint8_t lastSecond = 61; display.clearDisplay(); // 绘制动态秒针 float angle = map(now.second(), 0, 60, 0, 360) - 90; int centerX = 64, centerY = 32, radius = 20; int endX = centerX + radius * cos(angle * DEG_TO_RAD); int endY = centerY + radius * sin(angle * DEG_TO_RAD); display.drawCircle(centerX, centerY, radius, SSD1306_WHITE); display.drawLine(centerX, centerY, endX, endY, SSD1306_WHITE); // 数字变化动画 if(now.second() != lastSecond) { // 添加数字变化效果 display.fillRect(40, 10, 48, 20, SSD1306_BLACK); lastSecond = now.second(); } // 显示数字时间 display.setTextSize(2); display.setCursor(40, 10); if(now.hour() < 10) display.print("0"); display.print(now.hour()); display.print(":"); if(now.minute() < 10) display.print("0"); display.print(now.minute()); display.display(); delay(50); }

5. 进阶创意项目:交互式粒子系统

5.1 粒子系统基础

粒子系统可以创造出更复杂的视觉效果。每个粒子都有位置、速度和生命周期等属性:

struct Particle { float x, y; // 位置 float vx, vy; // 速度 uint8_t life; // 生命周期 uint8_t radius; // 大小 }; #define MAX_PARTICLES 50 Particle particles[MAX_PARTICLES];

5.2 粒子系统实现

完整的粒子系统实现代码:

#include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define MAX_PARTICLES 30 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire); struct Particle { float x, y; float vx, vy; uint8_t life; uint8_t radius; }; Particle particles[MAX_PARTICLES]; void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 初始化粒子 for(int i=0; i<MAX_PARTICLES; i++) { resetParticle(i); } } void resetParticle(int index) { particles[index].x = random(SCREEN_WIDTH); particles[index].y = random(SCREEN_HEIGHT); particles[index].vx = random(-2.0, 2.0); particles[index].vy = random(-2.0, 2.0); particles[index].life = random(50, 200); particles[index].radius = random(1, 4); } void loop() { display.clearDisplay(); // 更新并绘制所有粒子 for(int i=0; i<MAX_PARTICLES; i++) { if(--particles[i].life <= 0) { resetParticle(i); } particles[i].x += particles[i].vx; particles[i].y += particles[i].vy; // 边界检查 if(particles[i].x < 0 || particles[i].x >= SCREEN_WIDTH) { particles[i].vx = -particles[i].vx; } if(particles[i].y < 0 || particles[i].y >= SCREEN_HEIGHT) { particles[i].vy = -particles[i].vy; } // 绘制粒子 display.fillCircle(particles[i].x, particles[i].y, particles[i].radius, SSD1306_WHITE); } display.display(); delay(30); }

5.3 添加交互功能

通过添加传感器,可以让粒子系统响应外部输入。例如,使用加速度计控制重力方向:

// 假设使用MPU6050加速度计 #include "MPU6050.h" MPU6050 mpu; void setup() { // ...其他初始化代码... mpu.initialize(); } void loop() { // 获取加速度数据 int16_t ax, ay, az; mpu.getAcceleration(&ax, &ay, &az); // 应用加速度到粒子 for(int i=0; i<MAX_PARTICLES; i++) { particles[i].vx += ax * 0.0001; particles[i].vy += ay * 0.0001; // ...其余粒子更新代码... } // ...其余绘制代码... }

在实际项目中,我发现粒子系统的性能优化至关重要。当粒子数量较多时,可以尝试以下优化:减少粒子半径变化范围、简化碰撞检测、或者降低刷新频率。经过测试,在Arduino UNO上,30-50个粒子能够保持流畅的动画效果。

http://www.jsqmd.com/news/770471/

相关文章:

  • 昆山裕振鑫机械设备:金山正规的大型挖机出租有哪些 - LYL仔仔
  • AI应用平台进入实战期 迈富时以本体驱动突破落地困境 - 资讯焦点
  • 用AMD 4650G+ESXI 6.7打造家庭全能服务器:兼顾Win10轻办公与黑群晖NAS的配置心得
  • 别只盯着参数!手把手教你用ZU19EG评估板搭建一个边缘AI视频分析原型(附FMC扩展实战)
  • 工业视觉异常检测:深度学习在制药BFS产线的应用
  • 麒麟V10 SP3 2303桌面版防火墙白名单配置全攻略:从图形化到命令行,再到开机自启的完整避坑指南
  • 2026年五金配件定制与顺德金属制品厂家深度评测指南 - 精选优质企业推荐官
  • 2026乌鲁木齐平开窗与系统门窗深度选购指南:本地源头工厂直供方案对比 - 年度推荐企业名录
  • 91%生产级AI Agent存在致命漏洞:2026年智能体安全危机全景报告与防御指南
  • 工业矿物与沙石图像识别数据集 沙石大小尺寸识别 物料图像识别 沙石尺寸自动化识别 yolo数据集第10686期
  • 龙芯3A5000开发环境搭建记:从apt绝望到aptitude救场的Qt5安装全流程
  • TAPPA框架:优化注意力机制的时间连续性分析
  • Go语言构建系统监控与情绪可视化桌面应用:VibeGo项目全解析
  • 2026年高光谱国内外品牌与厂家全梳理:哪些值得推荐,哪个性价比更高更靠谱 - 品牌推荐大师1
  • 2025年5月 | 双关双断阀TOP8厂商推荐 - 资讯焦点
  • 【限时解密】AISMM-OKR融合评估工具包(含6大诊断量表+自动打分引擎):仅开放72小时,测完即生成组织能力缺口热力图
  • 构建个人技能库:从零散知识到结构化知识体系的工程实践
  • AI 测试面试经验大纲
  • 告别手动配置!用VectorCAST RSP包5分钟搞定IAR/Keil嵌入式单元测试环境
  • 深入HDMI带宽与协议:从杜比视界标准模式的8bit限制,看懂HDR兼容性问题的根源
  • 服务网格与 Java 微服务的集成:构建智能服务网络
  • 红米AC2100刷Hiboy Padavan后,子网设备死活拿不到IPv6?试试这几条关键命令
  • 在 Node.js 后端服务中集成 Taotoken 调用多模型完成内容生成
  • 033、陷波滤波器与谐振抑制
  • Python性能优化:AST解析与进程隔离实战
  • Acepe:下一代智能体开发环境的设计理念与实战指南
  • 2026年4月手套箱厂商推荐,单工位手套箱/厌氧手套箱/注液手套箱/亚克力手套箱/真空手套箱,手套箱生产厂家哪家专业 - 品牌推荐师
  • ConvNeXt 系列改进:引入 InceptionNeXt 的大核分解思想,将 7×7 卷积拆解为多分支条带卷积
  • 从一次产线停机说起:深度复盘刹车电阻烧毁背后的‘温升陷阱’与选型误区
  • 2026年喀什智能卫浴镜与岩板定制一站式工厂深度评测:喀什本地交付如何消除采购痛点 - 年度推荐企业名录