【花雕学编程】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 能够快速响应代码指令,在 OLED 显示屏上实时绘制线条。当有新的线条绘制请求时,能够迅速更新显示内容,适用于需要动态展示线条变化的场景。
占用资源少:绘制线条的操作相对简单,对 Arduino 的硬件资源消耗较少,不会过多占用内存和处理能力,使得 Arduino 可以同时处理其他任务,提高系统的整体性能。

应用场景
图形界面设计:在一些小型电子设备的图形用户界面(GUI)设计中,绘制线条可以用于构建界面的边框、分割线、菜单选项的下划线等元素,帮助提升界面的美观度和可读性,为用户提供更好的交互体验。
数据可视化:当需要将数据以图形化的方式展示时,线条可以用来绘制折线图、柱状图的边框或坐标轴等。例如,在环境监测系统中,用线条绘制出温度、湿度等数据随时间变化的折线图,直观地呈现数据的变化趋势。
简单图形绘制:对于一些简单的图形绘制需求,如绘制箭头、三角形、多边形等,线条是基本的构建元素。在教育领域的图形编程教学中,通过让学生学习用 Arduino 在 OLED 上绘制线条来构建简单图形,有助于培养学生的编程逻辑和图形设计能力。
指示标识:在工业控制、智能家居等场景中,线条可以用于绘制指示标识,如在设备状态显示屏上,用线条绘制出箭头指向设备的运行状态指示灯,或者绘制线条组成的图形来表示不同的设备功能区域,方便用户快速识别和操作。

需要注意的事项
坐标系统:Arduino OLED 的坐标系统有其特定的规则,通常原点(0, 0)位于屏幕的左上角。在绘制线条时,需要准确计算线条起点和终点的坐标,确保线条绘制在正确的位置上。不同的 OLED 显示屏尺寸和分辨率会导致坐标范围不同,要根据实际情况进行调整。
颜色与亮度:虽然 OLED 显示屏支持多种颜色,但在绘制线条时要考虑颜色的搭配和亮度设置。避免使用过于鲜艳或刺眼的颜色组合,以免影响视觉效果。同时,要根据环境光线条件合理调整显示屏的亮度,以节省能源并延长 OLED 的使用寿命。
线条质量:为了获得更好的线条质量,要注意线条的平滑度和连贯性。在绘制较长或复杂的线条时,可能需要采用一些算法来优化线条的绘制,如抗锯齿算法,以减少线条边缘的锯齿状现象,使线条看起来更加自然流畅。
内存管理:如果需要频繁地绘制大量线条或者动态更新线条内容,可能会占用较多的内存。要注意合理管理内存,避免因内存耗尽导致程序崩溃。可以采用一些优化措施,如及时释放不再使用的内存空间,或者对线条数据进行压缩存储。
显示屏寿命:OLED 显示屏存在烧屏的风险,特别是当长时间显示固定的线条图案时。为了延长显示屏的使用寿命,应避免长时间显示相同的线条内容,尽量使显示内容具有一定的动态性,或者定期更换显示的线条图案。

在这里插入图片描述

1、绘制静态直线

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
#define OLED_RESET 4
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
 
void setup() {
    
    
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
 
  // 绘制一条从(10, 10)到(110, 50)的直线
  display.drawLine(10, 10, 110, 50, SSD1306_WHITE);
  display.display();
}
 
void loop() {
    
    
  // 静态程序,无需循环操作
}

要点解读
drawLine()函数
语法:drawLine(x0, y0, x1, y1, color)
参数说明:(x0, y0)为起点坐标,(x1, y1)为终点坐标,color为颜色(SSD1306_WHITE或SSD1306_BLACK)。
示例中绘制了一条从(10, 10)到(110, 50)的白色直线。
OLED屏幕初始化
使用display.begin()初始化OLED屏幕,地址通常为0x3C。
调用display.clearDisplay()清屏,避免残留图像。
优化建议
可结合按钮输入,动态调整线条的起点和终点坐标。
使用drawFastVLine()或drawFastHLine()优化垂直/水平线条的绘制速度。

2、动态轨迹跟踪(模拟加速度传感器)

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <MPU6050.h>
 
#define OLED_RESET 4
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);
MPU6050 mpu;
 
int lastX = 64, lastY = 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);
 
  // 将加速度映射到屏幕坐标
  int newX = 64 + map(ax, -16000, 16000, -30, 30);
  int newY = 32 + map(ay, -16000, 16000, -30, 30);
 
  // 限制坐标范围,防止越界
  newX = constrain(newX, 0, 127);
  newY = constrain(newY, 0, 63);
 
  // 绘制线条
  display.drawLine(lastX, lastY, newX, newY, SSD1306_WHITE);
  display.display();
 
  // 更新上一个点的坐标
  lastX = newX;
  lastY = newY;
 
  // 清除旧轨迹(可选)
  // display.clearDisplay(); // 如果需要清除轨迹,取消注释
}

要点解读
加速度数据映射
使用MPU6050读取加速度数据,通过map()函数将ax和ay映射到屏幕坐标范围。
示例中ax映射到x轴范围[34, 94],ay映射到y轴范围[2, 62]。
轨迹绘制
使用drawLine()连接上一个点和当前点,形成动态轨迹。
通过constrain()函数限制坐标范围,防止线条超出屏幕边界。
轨迹清除
如果需要清除旧轨迹,可调用display.clearDisplay(),但会导致轨迹不连续。
另一种方法是使用drawPixel()覆盖旧点,或实现轨迹长度限制。
优化建议
增加滤波算法(如滑动平均),减少加速度噪声。
使用display.drawFastVLine()或drawFastHLine()优化特定方向的线条绘制。

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 angle = 0;
 
void setup() {
    
    
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
}
 
void loop() {
    
    
  display.clearDisplay();
 
  // 绘制波浪线
  for (int x = 0; x < 128; x++) {
    
    
    int y = 32 + 15 * sin(angle + x * 0.1); // 波浪公式
    if (x > 0) display.drawLine(x - 1, lastY, x, y, SSD1306_WHITE);
    lastY = y; // 记录上一个点的y坐标
  }
 
  display.display();
  angle += 0.1; // 调整波浪速度
  delay(50);
}

要点解读
波浪线公式
使用sin()函数生成波浪线,公式为y = 32 + 15 * sin(angle + x * 0.1)。
32为垂直中心点,15为振幅,x * 0.1控制波浪周期。
动态绘制
通过for循环遍历屏幕宽度,逐点计算y坐标。
使用drawLine()连接相邻点,形成连续的波浪线。
动画效果
通过angle变量控制波浪的相位,实现动态移动效果。
delay(50)控制波浪移动速度。
优化建议
增加颜色渐变效果(如使用display.drawPixel()设置不同灰度值)。
使用双缓冲技术,避免闪烁问题。

在这里插入图片描述

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);

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

    // 绘制静态线条
    display.drawLine(10, 10, 118, 54, SSD1306_WHITE); // (x0, y0, x1, y1)
    display.drawLine(118, 10, 10, 54, SSD1306_WHITE); // 对角线交叉

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

void loop() {
    
    
    // 无需循环操作
}

要点解读
drawLine()函数
drawLine(x0, y0, x1, y1, color)用于在屏幕上绘制从(x0, y0)到(x1, y1)的直线。
对角交叉线条
通过绘制两条对角线,形成一个交叉图案,展示简单的几何设计。
静态显示
线条在setup()中绘制后保持不变,适合静态UI设计。
清屏初始化
使用clearDisplay()清除屏幕内容,确保画面干净。
硬件兼容性
适用于任何支持SSD1306驱动的OLED屏幕,兼容性广泛。

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);

int line_length = 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("Growing Line");
    display.display();
}

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

    // 动态绘制线条
    display.drawLine(10, 32, 10 + line_length, 32, SSD1306_WHITE); // 水平线条

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

    // 增加线条长度
    line_length += 2;

    // 边界检查
    if (line_length > 118) {
    
    
        line_length = 0;
    }

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

要点解读
动态线条增长
通过增加line_length变量,使线条从左向右逐渐延长。
边界重置
当线条长度超过屏幕宽度时,重置为初始值,形成循环动画。
水平线条绘制
固定起点(10, 32),动态调整终点(10 + line_length, 32)。
清屏与重绘优化
每次更新前清屏,避免线条叠加导致画面混乱。
延时控制
使用delay(50)平衡动画流畅性和系统性能。

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; // 角度变量

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("Radar Scan");
    display.display();
}

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

    // 计算扫描线终点
    int x_end = 64 + 50 * cos(angle);
    int y_end = 32 + 50 * sin(angle);

    // 绘制扫描线
    display.drawLine(64, 32, x_end, y_end, SSD1306_WHITE); // 从中心向外辐射

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

    // 增加角度
    angle += 0.1;

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

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

要点解读
雷达扫描效果
使用极坐标公式计算扫描线的终点位置,模拟雷达扫描效果。
角度递增与循环
角度angle以固定步长递增,超出2π时重置,形成连续的扫描动画。
中心辐射线条
扫描线从屏幕中心(64, 32)向外辐射,形成动态变化的效果。
视觉增强
结合动态角度变化和清屏操作,提升视觉效果。
延时与帧率平衡
使用delay(50)控制刷新频率,确保动画流畅且不占用过多资源。

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

在这里插入图片描述