Arduino

技术栈
嵌入式 SDK
arduino嵌入式MCU开源硬件AVRC++

概览

Arduino 技术栈概览

Arduino 是全球最流行的开源硬件原型平台,由 Massimo Banzi 等人于 2005 年在意大利 Ivrea 创建。它包含简易的硬件开发板(基于 AVR/ARM 等 MCU)和Arduino IDE + 编程框架,将底层寄存器操作封装为 digitalWrite()analogRead() 等易用 API。

解决什么问题

  • 降低嵌入式门槛:无需深入理解 MCU 寄存器,几行代码即可点亮 LED、读取传感器
  • 快速原型验证:从想法到实物原型仅需几十分钟,极大加速创客、IoT 产品迭代
  • 跨平台统一:同一套代码可在 Uno、Mega、Nano、Due 等不同板子上运行
  • 庞大生态:数万个第三方库,覆盖显示屏、电机、WiFi、蓝牙等几乎所有常见外设

关键特性

  • 简易 C/C++ API:setup()/loop() 结构,引脚操作函数化
  • 跨平台 IDE:支持 Windows/macOS/Linux,也支持 Web Editor
  • 丰富的开发板矩阵:Uno R3/R4、Nano、Mega 2560、MKR 系列(IoT)、Portenta(工业级)
  • Shield 扩展系统:标准化引脚排列,即插即用扩展板
  • 活跃社区:全球数百万用户,海量教程、示例和开源项目

安装

Arduino 安装指南

1. 环境准备

平台 要求
Windows Windows 10/11(64 位),USB 端口
macOS macOS 10.14 Mojave 及以上,Intel/Apple Silicon
Linux Ubuntu 20.04+ / Fedora 36+ / Debian 11+,需配置 udev 规则

硬件:Arduino 开发板(Uno / Nano / Mega 等)+ USB 数据线。

2. 安装步骤

Windows / macOS(图形化安装)

  1. 访问 https://www.arduino.cc/en/software
  2. 下载对应系统的 Arduino IDE 2.x 安装包
  3. Windows:运行 .exe,按向导完成安装
  4. macOS:将 Arduino.app 拖入 Applications
  5. 首次启动会提示安装驱动,请同意

Linux(命令行安装)

# Ubuntu / Debian
sudo apt update
sudo apt install arduino

# Fedora
sudo dnf install arduino

# 或下载 AppImage(推荐,版本最新)
wget https://downloads.arduino.cc/arduino-ide/arduino-ide_latest_Linux_64bit.AppImage
chmod +x arduino-ide_*.AppImage
./arduino-ide_*.AppImage

配置 udev 规则(Linux 必需)

# 添加当前用户到 dialout 组
sudo usermod -a -G dialout $USER
# 注销重新登录后生效

板卡管理器(安装额外平台)

  1. 打开 Arduino IDE → 工具开发板开发板管理器
  2. 搜索 ESP32STM32 等安装对应平台包

3. 常见安装问题

问题 解决方案
端口不识别 (Windows) 安装 CH340/CP2102 驱动;尝试换 USB 线
权限拒绝 (Linux) 执行 sudo usermod -a -G dialout $USER注销
IDE 启动白屏 (macOS) 删除 ~/Library/Arduino15/ 配置文件夹重新启动
下载板卡包慢 设置代理或在 preferences.txt 中配置镜像 URL
编译上传失败 avrdude 检查板型和端口选择是否正确;按住 Reset 再上传

示例

Arduino 外设综合:温湿度传感器 DHT22 + OLED 显示

目标

使用 DHT22 采集温湿度,在 SSD1306 OLED 上实时显示,并实现按键切换显示模式。

硬件清单

元件 引脚
Arduino Uno -
DHT22 温湿度传感器 DATA → D2
SSD1306 OLED (128×64 I²C) SDA → A4, SCL → A5
按键 D3(内部上拉)

完整代码

/*
 * 温湿度监测仪 — DHT22 + SSD1306 OLED
 * 库依赖:DHT sensor library by Adafruit (>=1.4.4)
 *         Adafruit SSD1306 (>=2.5.7)
 *         Adafruit GFX Library (>=1.11.9)
 */

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

// ── 引脚定义 ──
#define DHTPIN      2
#define DHTTYPE     DHT22
#define BTN_PIN     3
#define OLED_ADDR   0x3C
#define SCREEN_W    128
#define SCREEN_H    64

// ── 对象 ──
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_W, SCREEN_H, &Wire);

// ── 状态 ──
enum DisplayMode { MODE_NORMAL, MODE_LARGE_TEMP, MODE_LARGE_HUM, MODE_COUNT };
DisplayMode mode = MODE_NORMAL;

float temperature = 0.0;
float humidity = 0.0;
unsigned long lastRead = 0, lastBtnCheck = 0;
const unsigned long READ_INTERVAL = 2000;

// ── 初始化 ──
void setup() {
  Serial.begin(9600);
  pinMode(BTN_PIN, INPUT_PULLUP);

  dht.begin();

  // OLED 初始化
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println(F("SSD1306 初始化失败!"));
    while (1) delay(10);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 25);
  display.println(F("DHT22 Monitor"));
  display.display();
  delay(1500);
}

// ── 读取传感器 ──
bool readSensor() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();

  if (isnan(t) || isnan(h)) {
    Serial.println(F("DHT22 读取失败!"));
    return false;
  }
  temperature = t;
  humidity = h;
  return true;
}

// ── 按键处理 ──
void checkButton() {
  static bool lastState = HIGH;
  bool now = digitalRead(BTN_PIN);

  if (lastState == HIGH && now == LOW) {  // 下降沿
    delay(30);  // 消抖
    if (digitalRead(BTN_PIN) == LOW) {
      mode = (DisplayMode)((mode + 1) % MODE_COUNT);
      Serial.print(F("切换模式: "));
      Serial.println(mode);
    }
  }
  lastState = now;
}

// ── OLED 渲染 ──
void renderDisplay() {
  display.clearDisplay();

  switch (mode) {
    case MODE_NORMAL:
      renderNormal();
      break;
    case MODE_LARGE_TEMP:
      renderLarge(0, "TEMPERATURE", temperature, "C");
      break;
    case MODE_LARGE_HUM:
      renderLarge(1, "HUMIDITY", humidity, "%");
      break;
  }

  display.display();
}

void renderNormal() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println(F("--- DHT22 Monitor ---"));

  display.drawLine(0, 12, 128, 12, SSD1306_WHITE);

  display.setTextSize(2);
  display.setCursor(5, 20);
  display.print(temperature, 1);
  display.print((char)247);  // °
  display.print(F("C"));

  display.setTextSize(2);
  display.setCursor(5, 42);
  display.print(humidity, 1);
  display.print(F("%"));

  // 模式指示
  display.setTextSize(1);
  display.setCursor(100, 56);
  display.print(mode + 1);
  display.print(F("/"));
  display.print(MODE_COUNT);
}

void renderLarge(int icon, const char* title, float value, const char* unit) {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(title);

  // 大字号数值
  display.setTextSize(4);
  int x = (value < 10) ? 30 : (value < 100) ? 18 : 5;
  display.setCursor(x, 18);
  display.print(value, 1);

  display.setTextSize(2);
  display.setCursor(x + 60, 38);
  display.print(unit);

  display.setTextSize(1);
  display.setCursor(0, 56);
  display.print(F("按键切换 ["));
  display.print(mode + 1);
  display.print(F("/"));
  display.print(MODE_COUNT);
  display.print(F("]"));
}

// ── 主循环 ──
void loop() {
  unsigned long now = millis();

  // 定时读取传感器(非阻塞)
  if (now - lastRead >= READ_INTERVAL) {
    lastRead = now;
    if (readSensor()) {
      Serial.print(F("温度: "));
      Serial.print(temperature);
      Serial.print(F("°C  湿度: "));
      Serial.print(humidity);
      Serial.println(F("%"));
    }
    renderDisplay();
  }

  // 按键扫描
  if (now - lastBtnCheck >= 50) {
    lastBtnCheck = now;
    checkButton();
  }
}

运行步骤

  1. 在 Arduino IDE 库管理器安装:DHT sensor libraryAdafruit SSD1306Adafruit GFX
  2. 按硬件表接线
  3. 编译上传,打开串口监视器(9600 波特率)
  4. 按按键切换显示模式

预期输出

  • OLED 实时显示温湿度(2 秒刷新)
  • 串口同步输出读数
  • 按键切换 4 种模式:双排紧凑 → 大字温度 → 大字湿度 → 循环

关键点

  • isnan() 检测 DHT22 读取失败(常见于刚上电)并优雅处理
  • 显示刷新放在定时器中避免频繁重绘导致闪烁
  • 按键用 INPUT_PULLUP 省外部上拉电阻

Arduino Hello World:LED 闪烁与串口输出

目标

掌握 Arduino 最基础的开发流程:编译 → 上传 → 观察 LED 闪烁和串口监视器输出。

完整代码

/*
 * Arduino Hello World - 板载 LED 闪烁 + 串口打印
 * 适用于 Arduino Uno / Nano / Mega 等大多数开发板
 * 板载 LED 通常连接到 D13(Uno/Nano/Mega)
 */

const int LED_PIN = LED_BUILTIN;  // 板载 LED(大多数板子为 13)
unsigned long lastBlinkTime = 0;
const unsigned long BLINK_INTERVAL = 500;  // 毫秒
int blinkCount = 0;

void setup() {
  // 初始化 LED 引脚为输出模式
  pinMode(LED_PIN, OUTPUT);

  // 初始化串口通信,波特率 9600
  Serial.begin(9600);

  // 等待串口就绪(部分板子需要)
  while (!Serial) {
    delay(10);
  }

  Serial.println("=== Arduino Hello World ===");
  Serial.println("板载 LED 开始闪烁,每 500ms 翻转一次");
  Serial.print  ("LED 引脚:");
  Serial.println(LED_PIN);
}

void loop() {
  unsigned long now = millis();

  // 非阻塞延时实现 LED 闪烁
  if (now - lastBlinkTime >= BLINK_INTERVAL) {
    lastBlinkTime = now;

    // 翻转 LED 状态
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));

    // 串口输出计数
    blinkCount++;
    Serial.print("闪烁次数: ");
    Serial.print(blinkCount);
    Serial.print(" | LED 状态: ");
    Serial.println(digitalRead(LED_PIN) ? "亮" : "灭");
  }

  // 这里可以放其他非阻塞任务
}

运行步骤

  1. 用 USB 线连接 Arduino 到电脑
  2. 打开 Arduino IDE → 工具开发板 → 选择你的板子(如 Arduino Uno)
  3. 工具端口 → 选择对应 COM 端口
  4. 粘贴代码 → 点击 上传(→ 箭头)
  5. 打开 工具串口监视器(Ctrl+Shift+M),波特率选 9600

预期输出

  • 板载 LED 每 0.5 秒闪烁一次
  • 串口监视器持续输出:
=== Arduino Hello World ===
板载 LED 开始闪烁,每 500ms 翻转一次
LED 引脚:13
闪烁次数: 1 | LED 状态: 亮
闪烁次数: 2 | LED 状态: 灭
闪烁次数: 3 | LED 状态: 亮
...

关键点

  • setup() 只执行一次,loop() 无限循环
  • millis() 实现非阻塞延时,优于 delay() 阻塞方案
  • LED_BUILTIN 是跨板通用宏,自动适配不同板子的板载 LED 引脚

教程

Arduino 开发从入门到点亮世界

本章目标

理解 Arduino 平台的核心概念,完成第一个项目,掌握数字 I/O 与串口通信基础。


1. 什么是 Arduino?

Arduino 不是一块板子,而是一个 生态系统

  • 硬件:以 ATmega328P (Uno) 为代表的开源开发板
  • 软件:Arduino IDE + Arduino 编程框架
  • 社区:数以万计的开源库和教程

为什么选择 Arduino?

对比维度 裸机 AVR (寄存器) Arduino
点亮 LED 配置 DDRB/PORTB 寄存器 pinMode(13,OUTPUT); digitalWrite(13,HIGH);
学习周期 1-2 周 10 分钟
代码复用 需重写驱动 数以万计的现成库

2. 第一个程序:Blink

硬件

任意 Arduino 板 + USB 线。板载 LED(Uno 为 D13)即可。

代码

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);  // 配置引脚为输出
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // 点亮
  delay(1000);                       // 等待 1 秒
  digitalWrite(LED_BUILTIN, LOW);   // 熄灭
  delay(1000);
}

编译与上传

  1. 连接 USB → 选择板卡型号 + 端口
  2. 点击 上传 按钮
  3. 观察 LED 开始闪烁

3. 理解 setup() 与 loop()

Arduino 的独特之处在于 隐式 main()

// Arduino 内部实际上是这样的:
int main(void) {
    init();           // 初始化硬件
    setup();          // 用户初始化(只执行一次)

    while (1) {
        loop();       // 用户主循环(无限重复)
    }
    return 0;
}

最佳实践

  • setup() 中放初始化代码:pinMode、Serial.begin、传感器初始化
  • loop() 中放业务逻辑,避免 在 loop 内使用长 delay()

4. 数字 I/O

基本操作

pinMode(pin, INPUT);        // 输入(高阻态)
pinMode(pin, INPUT_PULLUP); // 输入(内部上拉 ~30kΩ)
pinMode(pin, OUTPUT);       // 输出

int val = digitalRead(pin);  // 读引脚
digitalWrite(pin, HIGH);     // 写高/低

按键读取(带消抖)

const int BTN = 3;
int lastState = HIGH;
unsigned long lastDebounce = 0;

void loop() {
  int reading = digitalRead(BTN);

  if (reading != lastState) {
    lastDebounce = millis();  // 复位消抖计时器
  }

  if ((millis() - lastDebounce) > 50) {  // 50ms 消抖
    // 确认状态改变
    if (reading == LOW) {
      Serial.println("按键按下!");
    }
  }
  lastState = reading;
}

5. 串口通信

void setup() {
  Serial.begin(9600);  // 波特率
}

void loop() {
  Serial.print("millis: ");
  Serial.println(millis());

  // 格式化输出
  float voltage = analogRead(A0) * 5.0 / 1023.0;
  Serial.print("Voltage: ");
  Serial.print(voltage, 2);  // 2 位小数
  Serial.println("V");

  delay(1000);
}

6. 模拟输入

Arduino Uno 的 ADC 为 10 位(0-1023),基准电压默认 5V。

int raw = analogRead(A0);
float voltage = raw * (5.0 / 1023.0);

思考题

  1. 为什么 delay() 不适合复杂项目?用什么替代?
  2. INPUT_PULLUP 相比外部上拉电阻有什么优缺点?
  3. 如果用 50Hz PWM 控制 LED 亮度,人眼能看到闪烁吗?

参考资料

  1. [1] Arduino Team. Arduino Official Documentation. 2024. https://docs.arduino.cc/
  2. [2] Arduino Team. Arduino Language Reference. 2024. https://www.arduino.cc/reference/en/
  3. [3] Massimo Banzi, Michael Shiloh. Getting Started with Arduino. 2022.
  4. [4] Michael Margolis, Brian Jepson, Nicholas Robert Weldin. Arduino Cookbook. 2020.