【花雕学编程】Arduino OLED 之椭圆轨迹示波器

在这里插入图片描述

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 显示屏上,方便用户随时查看自己的健康状况。

在这里插入图片描述

主要特点
• 高分辨率显示:OLED 显示屏具有高分辨率和高对比度,能够清晰地显示椭圆轨迹的细节,有助于准确观察和分析信号的特征。
• 实时动态显示:可以实时地根据输入信号的变化绘制椭圆轨迹,能够快速响应信号的动态变化,让用户及时了解信号的实时状态。
• 可定制性强:通过编写 Arduino 代码,可以方便地对椭圆轨迹示波器进行定制,例如调整椭圆的大小、形状、颜色,以及添加各种辅助标识和刻度等,以满足不同用户的需求。
• 体积小、便携性好:Arduino 开发板和 OLED 显示屏的体积相对较小,便于携带和安装,可在不同的场合使用,如实验室、现场测试等。
• 低功耗:OLED 显示屏本身具有低功耗的特点,结合 Arduino 的节能设计,使得整个椭圆轨迹示波器在运行时消耗的功率较低,适合长时间使用。

应用场景
• 电子电路实验教学:在电子电路实验中,常用于展示交流信号的相位关系和 Lissajous 图形。学生可以通过观察椭圆轨迹的变化,直观地理解信号的频率、相位等参数对图形的影响,有助于加深对相关理论知识的理解。
• 信号分析与调试:在电子设备的研发和调试过程中,工程师可以利用椭圆轨迹示波器来分析和调试各种周期性信号,如音频信号、视频信号等。通过观察椭圆轨迹的形状和变化,判断信号的质量、稳定性以及是否存在失真等问题,从而进行相应的调整和优化。
• 通信工程领域:在通信系统的测试和分析中,可用于观察调制信号的星座图。星座图可以直观地反映出调制信号的相位和幅度信息,帮助工程师评估通信系统的性能,如误码率、信噪比等,进而对系统进行优化和改进。

需要注意的事项
• 信号输入范围:要确保输入到 Arduino 的信号幅度在其可接受的范围内,避免信号过大导致 Arduino 的模拟输入引脚损坏,或者信号过小导致无法准确检测到信号。通常需要根据 Arduino 的参考电压和模拟输入引脚的特性来合理调整输入信号的幅度。
• 采样频率与刷新率:椭圆轨迹的绘制效果与采样频率和 OLED 显示屏的刷新率有关。如果采样频率过低,可能会导致椭圆轨迹不连续或失真;而刷新率过低则会使显示的图形出现闪烁或卡顿现象。因此,需要根据实际情况合理设置采样频率和刷新率,以获得稳定、清晰的椭圆轨迹显示效果。
• 内存使用:在绘制椭圆轨迹时,可能需要存储一些中间数据和计算结果,这会占用 Arduino 的内存。如果处理的信号数据量较大,可能会导致内存不足。因此,要注意优化代码,合理分配内存,避免出现内存溢出的情况。
• OLED 显示屏寿命:OLED 显示屏虽然具有很多优点,但长时间显示固定的图像可能会导致屏幕烧屏,影响显示屏的使用寿命。因此,在使用椭圆轨迹示波器时,应避免长时间显示相同的椭圆轨迹或静态图像,尽量采用动态显示或定期更换显示内容的方式来保护 OLED 显示屏。
• 电磁干扰:Arduino 和 OLED 显示屏在工作时可能会受到周围环境中的电磁干扰,影响信号的传输和显示效果。因此,在安装和使用时,应尽量避免将其放置在强电磁场附近,如大型电机、变压器等设备旁边。同时,可以采取一些抗干扰措施,如使用屏蔽线、合理接地等,以提高系统的稳定性和可靠性。

在这里插入图片描述

1、基于正弦波生成椭圆轨迹

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
 
#define OLED_RESET 4
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
 
float angle = 0;
const float a = 30; // 椭圆长轴半径
const float b = 20; // 椭圆短轴半径
 
void setup() {
    
    
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}
 
void loop() {
    
    
  int x = 64 + a * cos(angle); // 椭圆中心为(64, 32)
  int y = 32 + b * sin(angle);
  angle += 0.1; // 角度增量
  if (angle > 2 * PI) angle = 0;
 
  display.clearDisplay();
  display.drawCircle(64, 32, 2, 1); // 绘制椭圆中心点
  display.fillCircle(x, y, 2, 1);   // 绘制动态点
  display.display();
  delay(50);
}

要点解读
椭圆公式
椭圆参数方程:x = cx + acos(θ),y = cy + bsin(θ),其中(cx, cy)为椭圆中心,a和b分别为长轴和短轴半径。
代码中a=30,b=20,中心点为(64, 32)。
动态绘制
使用cos()和sin()函数生成动态点,通过调整angle实现椭圆轨迹运动。
fillCircle()绘制动态点,drawCircle()绘制中心点以增强视觉效果。
优化建议
增加轨迹擦除功能(如使用drawPixel()清除旧点),避免残留轨迹。
调整angle增量控制椭圆运动速度。

2、MPU6050加速度数据生成动态椭圆轨迹

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <MPU6050.h>
#include <math.h>
 
#define OLED_RESET 4
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
MPU6050 mpu;
 
float a = 30, b = 20; // 椭圆半径
int centerX = 64, centerY = 32;
 
void setup() {
    
    
  Wire.begin();
  mpu.initialize();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}
 
void loop() {
    
    
  int16_t ax, ay;
  mpu.getMotion6(&ax, &ay, NULL, NULL, NULL, NULL);
  a = 30 + map(ax, -16000, 16000, -10, 10); // 动态调整长轴
  b = 20 + map(ay, -16000, 16000, -10, 10); // 动态调整短轴
 
  float angle = millis() * 0.01; // 时间驱动角度
  int x = centerX + a * cos(angle);
  int y = centerY + b * sin(angle);
 
  display.clearDisplay();
  display.drawCircle(centerX, centerY, 2, 1);
  display.fillCircle(x, y, 2, 1);
  display.display();
}

要点解读
加速度控制椭圆变形
通过MPU6050读取加速度数据,动态调整椭圆长轴a和短轴b。
map()函数将加速度值映射到半径变化范围(-10到10)。
时间驱动椭圆运动
使用millis()生成时间驱动的角度angle,实现连续运动。
避免使用delay(),保证MPU6050数据读取的实时性。
优化建议
增加加速度数据滤波,减少噪声干扰。
限制a和b的最小值,防止椭圆退化为点。

3、双椭圆轨迹示波器(李萨如图形)

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
 
#define OLED_RESET 4
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
 
float angleX = 0, angleY = 0;
const float a = 30, b = 20;
 
void setup() {
    
    
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}
 
void loop() {
    
    
  int x = 64 + a * cos(angleX);
  int y = 32 + b * sin(angleY);
  angleX += 0.1;
  angleY += 0.15; // 不同频率产生李萨如图形
 
  display.clearDisplay();
  display.drawCircle(64, 32, 2, 1);
  display.fillCircle(x, y, 2, 1);
  display.display();
  delay(50);
}

要点解读
李萨如图形原理
两个正弦波分别控制x和y坐标,频率比不同产生不同图形。
代码中angleX和angleY增量不同(0.1和0.15),形成李萨如图形。
动态绘制
使用cos()和sin()生成动态点,通过调整频率比实现不同图形。
适合展示振动信号的相位关系。
优化建议
增加频率比和幅值调整功能(如通过串口输入)。
增加图形清屏逻辑,避免残留轨迹。

在这里插入图片描述

4、基本椭圆轨迹示波器

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

// 创建OLED对象
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float angle = 0; // 角度变量

void setup() {
    
    
    // 初始化OLED
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    
     // 使用默认I2C地址0x3C
        Serial.println(F("SSD1306 allocation failed"));
        for (;;);
    }
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println("Ellipse Trajectory");
    display.display();
}

void loop() {
    
    
    // 清屏
    display.clearDisplay();

    // 计算椭圆轨迹上的点 (x, y)
    float x = 64 + 50 * cos(angle); // 水平半轴为50,中心在64
    float y = 32 + 30 * sin(angle); // 垂直半轴为30,中心在32

    // 绘制点
    display.drawPixel(x, y, SSD1306_WHITE);

    // 更新显示
    display.display();

    // 增加角度
    angle += 0.1;

    // 边界检查
    if (angle > 2 * PI) {
    
    
        angle -= 2 * PI;
    }

    delay(50); // 控制刷新频率
}

要点解读
椭圆公式
使用参数方程x = a * cos(angle)和y = b * sin(angle)生成椭圆轨迹上的点。
动态绘制点
drawPixel()函数用于在椭圆轨迹上逐点绘制。
角度递增与循环
角度angle以固定步长递增,超出2π时重置,形成连续的轨迹。
延时控制
使用delay(50)控制刷新频率,确保动画流畅且不占用过多资源。
清屏与重绘
每次循环调用clearDisplay()清除屏幕内容,避免图形叠加。

5、多轨迹叠加示波器

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

// 创建OLED对象
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float angle1 = 0, angle2 = 0; // 两个角度变量

void setup() {
    
    
    // 初始化OLED
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    
    
        Serial.println(F("SSD1306 allocation failed"));
        for (;;);
    }
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println("Multi Ellipse Trajectories");
    display.display();
}

void loop() {
    
    
    // 清屏
    display.clearDisplay();

    // 第一条轨迹
    float x1 = 64 + 50 * cos(angle1);
    float y1 = 32 + 30 * sin(angle1);
    display.drawPixel(x1, y1, SSD1306_WHITE);

    // 第二条轨迹
    float x2 = 64 + 40 * cos(angle2);
    float y2 = 32 + 20 * sin(angle2);
    display.drawPixel(x2, y2, SSD1306_WHITE);

    // 更新显示
    display.display();

    // 增加角度
    angle1 += 0.1;
    angle2 += 0.15;

    // 边界检查
    if (angle1 > 2 * PI) angle1 -= 2 * PI;
    if (angle2 > 2 * PI) angle2 -= 2 * PI;

    delay(50); // 控制刷新频率
}

要点解读
多轨迹叠加
使用两组不同的参数(如半轴长度和角度增量)生成两条独立的椭圆轨迹。
不同速度轨迹
通过调整角度增量(如0.1和0.15),使两条轨迹的速度不同,形成交错效果。
点绘制与叠加
使用drawPixel()分别绘制两条轨迹上的点,展示叠加效果。
边界处理
对每个角度变量进行范围限制,确保其始终在[0, 2π]范围内。
视觉效果优化
多轨迹叠加增强了视觉复杂性,适用于模拟多信号源的示波器。

6、动态变化的椭圆轨迹

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

// 创建OLED对象
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float angle = 0; // 角度变量
int radius_x = 50, radius_y = 30; // 初始半轴长度

void setup() {
    
    
    // 初始化OLED
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    
    
        Serial.println(F("SSD1306 allocation failed"));
        for (;;);
    }
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println("Dynamic Ellipse");
    display.display();
}

void loop() {
    
    
    // 清屏
    display.clearDisplay();

    // 动态计算椭圆轨迹上的点
    float x = 64 + radius_x * cos(angle);
    float y = 32 + radius_y * sin(angle);

    // 绘制点
    display.drawPixel(x, y, SSD1306_WHITE);

    // 更新显示
    display.display();

    // 增加角度
    angle += 0.1;

    // 动态调整半轴长度
    radius_x += 0.2;
    radius_y -= 0.1;

    // 边界检查
    if (radius_x > 60 || radius_y < 10) {
    
    
        radius_x = 50;
        radius_y = 30;
    }

    delay(50); // 控制刷新频率
}

要点解读
动态半轴变化
椭圆的水平半轴radius_x和垂直半轴radius_y随时间动态变化,形成形状变化的轨迹。
边界重置
当半轴长度超出设定范围时,重置为初始值,形成周期性变化。
视觉效果增强
动态调整椭圆形状,使轨迹呈现出渐变和收缩的效果。
清屏与重绘优化
每次更新前清屏,确保轨迹清晰无残留。
延时与帧率平衡
使用delay(50)控制刷新频率,确保动画流畅且不占用过多资源。

注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。

在这里插入图片描述