常用库介绍
Arduino 的强大之处在于丰富的库支持。库是预先编写好的代码,让你无需从头实现复杂的功能。本章将介绍 Arduino 开发中最常用的库,包括内置库和常用的第三方库。
库的概念与管理
什么是库
库是一组预定义的函数和类的集合,用于实现特定功能。使用库可以大大简化开发过程,避免重复造轮子。比如,要控制舵机,你不需要自己写 PWM 信号生成代码,只需使用 Servo 库的 write() 方法即可。
库的安装方式
方式一:库管理器安装(推荐)
- 打开 Arduino IDE
- 点击
项目→加载库→管理库 - 在搜索框中输入库名称
- 选择版本并点击安装
方式二:手动安装
- 从 GitHub 或其他来源下载库的 ZIP 文件
- 点击
项目→加载库→添加 .ZIP 库 - 选择下载的 ZIP 文件
方式三:直接复制
将库文件夹复制到 Arduino 的库目录:
- Windows:
文档\Arduino\libraries\ - macOS:
~/Documents/Arduino/libraries/ - Linux:
~/Arduino/libraries/
库的使用方法
安装库后,需要在代码中包含库的头文件:
#include <库名.h> // 系统库使用尖括号
// 或
#include "myLibrary.h" // 自定义库使用双引号
包含头文件后,就可以使用库提供的函数和类了。
内置库详解
Arduino IDE 自带了一系列内置库,无需额外安装。
EEPROM 库
EEPROM 是一种断电后数据不会丢失的存储器。Arduino Uno 有 1024 字节的 EEPROM,适合存储配置参数、校准值等小量数据。
基本特性
| 开发板 | EEPROM 容量 |
|---|---|
| Uno, Nano | 1024 字节 |
| Mega 2560 | 4096 字节 |
| Leonardo | 1024 字节 |
EEPROM 的写入寿命约为 10 万次,请避免频繁写入同一个地址。使用 update() 代替 write() 可以延长寿命。
常用函数
#include <EEPROM.h>
// 读取单个字节
byte value = EEPROM.read(address);
// 写入单个字节(直接写入,即使值相同)
EEPROM.write(address, value);
// 更新单个字节(只在值不同时才写入)
EEPROM.update(address, value);
// 读取任意类型数据
EEPROM.get(address, variable);
// 写入任意类型数据
EEPROM.put(address, variable);
// 获取 EEPROM 大小
unsigned int size = EEPROM.length();
// 使用数组语法访问
EEPROM[0] = 100; // 写入
byte val = EEPROM[0]; // 读取
存储结构体示例
#include <EEPROM.h>
// 定义配置结构体
struct Config {
int deviceId;
float calibration;
char name[20];
bool enabled;
};
const int CONFIG_ADDR = 0;
Config config;
void setup() {
Serial.begin(9600);
// 读取配置
EEPROM.get(CONFIG_ADDR, config);
// 检查是否是有效配置
if (config.deviceId == 0xFFFF) {
// 无效配置,使用默认值
config.deviceId = 1;
config.calibration = 1.0;
strcpy(config.name, "Default");
config.enabled = true;
// 保存默认配置
EEPROM.put(CONFIG_ADDR, config);
Serial.println("已保存默认配置");
}
// 打印当前配置
Serial.print("设备 ID: ");
Serial.println(config.deviceId);
Serial.print("校准值: ");
Serial.println(config.calibration);
Serial.print("名称: ");
Serial.println(config.name);
}
void loop() {}
Servo 库
Servo 库用于控制舵机,支持标准舵机(0-180度)和连续旋转舵机。
基本限制
| 开发板 | 最大舵机数量 |
|---|---|
| Uno, Nano, Mini | 12 个 |
| Mega | 48 个 |
使用 Servo 库时,D9 和 D10 的 PWM 功能会被禁用(Uno 上)。
常用函数
#include <Servo.h>
Servo myServo;
// 关联引脚
myServo.attach(pin);
myServo.attach(pin, min, max); // 指定脉冲宽度范围
// 设置角度(0-180度)
myServo.write(angle);
// 设置脉冲宽度(微秒)
myServo.writeMicroseconds(us);
// 读取当前角度
int angle = myServo.read();
// 读取当前脉冲宽度
int us = myServo.readMicroseconds();
// 断开连接
myServo.detach();
多舵机控制示例
#include <Servo.h>
// 创建舵机对象数组
Servo servos[4];
const int servoPins[] = {9, 10, 11, 12};
void setup() {
// 初始化所有舵机
for (int i = 0; i < 4; i++) {
servos[i].attach(servoPins[i]);
}
Serial.begin(9600);
Serial.println("多舵机控制系统");
}
void loop() {
// 同时控制多个舵机
for (int angle = 0; angle <= 180; angle += 10) {
for (int i = 0; i < 4; i++) {
servos[i].write(angle);
}
delay(50);
}
// 独立控制
servos[0].write(90); // 舵机 1: 90度
servos[1].write(45); // 舵机 2: 45度
servos[2].write(135); // 舵机 3: 135度
servos[3].write(180); // 舵机 4: 180度
delay(1000);
}
Wire 库(I2C 通信)
Wire 库用于 I2C 总线通信,可以连接各种 I2C 设备,如 OLED 显示屏、温湿度传感器、实时时钟等。
引脚定义
| 开发板 | SDA | SCL |
|---|---|---|
| Uno, Nano | A4 | A5 |
| Mega | 20 | 21 |
| Leonardo | D2 | D3 |
| MKR 系列 | D11 | D12 |
主设备常用函数
#include <Wire.h>
// 初始化为主设备
Wire.begin();
// 开始传输
Wire.beginTransmission(address);
// 写入数据
Wire.write(data);
Wire.write(buffer, length);
// 结束传输
Wire.endTransmission();
Wire.endTransmission(false); // 发送重启条件而非停止
// 请求从设备数据
Wire.requestFrom(address, quantity);
// 检查可用字节数
int available = Wire.available();
// 读取数据
int data = Wire.read();
I2C 设备读写示例
#include <Wire.h>
// BMP280 I2C 地址
const int BMP280_ADDR = 0x76;
void setup() {
Serial.begin(9600);
Wire.begin();
// 读取设备 ID 寄存器
byte id = readRegister(0xD0);
Serial.print("设备 ID: 0x");
Serial.println(id, HEX);
}
void loop() {}
// 读取单个寄存器
byte readRegister(byte reg) {
Wire.beginTransmission(BMP280_ADDR);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(BMP280_ADDR, 1);
return Wire.read();
}
// 写入单个寄存器
void writeRegister(byte reg, byte value) {
Wire.beginTransmission(BMP280_ADDR);
Wire.write(reg);
Wire.write(value);
Wire.endTransmission();
}
从设备模式
#include <Wire.h>
const int SLAVE_ADDRESS = 0x08;
void setup() {
Wire.begin(SLAVE_ADDRESS); // 作为从设备
Wire.onReceive(receiveEvent); // 接收事件回调
Wire.onRequest(requestEvent); // 请求事件回调
Serial.begin(9600);
}
void loop() {}
// 接收数据回调
void receiveEvent(int howMany) {
while (Wire.available()) {
char c = Wire.read();
Serial.print(c);
}
}
// 被请求发送数据回调
void requestEvent() {
Wire.write("Hello");
}
SPI 库
SPI 是一种高速同步串行通信协议,常用于 SD 卡、TFT 显示屏、传感器等设备。
引脚定义(Arduino Uno)
| 信号 | 引脚 | 说明 |
|---|---|---|
| SS | D10 | 从机选择 |
| MOSI | D11 | 主机输出从机输入 |
| MISO | D12 | 主机输入从机输出 |
| SCK | D13 | 时钟 |
常用函数
#include <SPI.h>
// 初始化 SPI
SPI.begin();
// 配置 SPI 参数
SPI.beginTransaction(SPISettings(speed, dataOrder, dataMode));
// 传输数据
byte received = SPI.transfer(data);
SPI.transfer(buffer, length);
// 结束传输
SPI.endTransaction();
// 禁用 SPI
SPI.end();
SPI 设备通信示例
#include <SPI.h>
const int SS_PIN = 10;
void setup() {
Serial.begin(9600);
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH);
SPI.begin();
}
void loop() {
// 读取数据
byte data = readSPI(0x00);
Serial.println(data);
delay(1000);
}
byte readSPI(byte address) {
digitalWrite(SS_PIN, LOW);
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
SPI.transfer(address | 0x80); // 读命令
byte data = SPI.transfer(0x00);
SPI.endTransaction();
digitalWrite(SS_PIN, HIGH);
return data;
}
SoftwareSerial 库
SoftwareSerial 库可以在任意数字引脚上模拟串口通信,当硬件串口不够用时非常有用。
限制与注意事项
- 不能同时接收和发送数据
- 最高波特率约 115200
- 某些引脚可能不支持(仅部分引脚支持引脚变化中断)
- 会占用更多 CPU 资源
常用函数
#include <SoftwareSerial.h>
// 创建软串口,RX, TX
SoftwareSerial mySerial(10, 11);
// 初始化
mySerial.begin(baudrate);
// 发送数据
mySerial.print(data);
mySerial.println(data);
mySerial.write(data);
// 接收数据
if (mySerial.available()) {
char c = mySerial.read();
}
// 设置监听(多个软串口时)
mySerial.listen();
多串口通信示例
#include <SoftwareSerial.h>
// 硬件串口连接电脑
// 软串口连接 ESP8266
SoftwareSerial espSerial(10, 11);
void setup() {
Serial.begin(9600); // 电脑
espSerial.begin(115200); // ESP8266
Serial.println("双串口桥接器");
}
void loop() {
// 从电脑转发到 ESP8266
if (Serial.available()) {
espSerial.write(Serial.read());
}
// 从 ESP8266 转发到电脑
if (espSerial.available()) {
Serial.write(espSerial.read());
}
}
常用第三方库
ArduinoJson
ArduinoJson 是处理 JSON 数据的标准库,广泛用于物联网项目。
安装
在库管理器中搜索 "ArduinoJson" 并安装。
基本用法
#include <ArduinoJson.h>
void setup() {
Serial.begin(9600);
// 创建 JSON 文档
StaticJsonDocument<256> doc;
// 添加数据
doc["sensor"] = "DHT22";
doc["temperature"] = 23.5;
doc["humidity"] = 65.0;
doc["timestamp"] = 1234567890;
// 序列化为字符串
String output;
serializeJson(doc, output);
Serial.println(output);
// 解析 JSON 字符串
const char* json = "{\"name\":\"Arduino\",\"version\":1}";
StaticJsonDocument<128> doc2;
deserializeJson(doc2, json);
const char* name = doc2["name"];
int version = doc2["version"];
Serial.print("Name: ");
Serial.println(name);
Serial.print("Version: ");
Serial.println(version);
}
void loop() {}
Adafruit_Sensor + DHT
这是读取 DHT 系列温湿度传感器的常用库组合。
安装
- 安装 "Adafruit Unified Sensor"
- 安装 "DHT sensor library"
使用示例
#include <DHT.h>
#define DHT_PIN 2
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
delay(2000); // DHT22 需要至少 2 秒间隔
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("读取失败!");
return;
}
// 计算体感温度
float heatIndex = dht.computeHeatIndex(temperature, humidity, false);
Serial.print("温度: ");
Serial.print(temperature);
Serial.print(" °C | 湿度: ");
Serial.print(humidity);
Serial.print(" % | 体感: ");
Serial.print(heatIndex);
Serial.println(" °C");
}
LiquidCrystal_I2C
简化 I2C 接口 LCD1602 显示屏的使用。
安装
在库管理器中搜索 "LiquidCrystal I2C"。
使用示例
#include <LiquidCrystal_I2C.h>
// 地址通常是 0x27 或 0x3F
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Hello, World!");
lcd.setCursor(0, 1);
lcd.print("Arduino LCD");
}
void loop() {
// 闪烁背光
lcd.noBacklight();
delay(500);
lcd.backlight();
delay(500);
}
FastLED
控制 WS2812 等可编程 LED 灯带的强大库。
安装
在库管理器中搜索 "FastLED"。
使用示例
#include <FastLED.h>
#define LED_PIN 6
#define NUM_LEDS 30
#define BRIGHTNESS 50
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
void setup() {
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
}
void loop() {
// 彩虹效果
static uint8_t hue = 0;
fill_rainbow(leds, NUM_LEDS, hue, 7);
FastLED.show();
hue++;
delay(10);
}
Adafruit_SSD1306
控制 SSD1306 驱动的 OLED 显示屏。
安装
- 安装 "Adafruit GFX Library"
- 安装 "Adafruit SSD1306"
使用示例
#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 setup() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for (;;); // 初始化失败,停止
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 25);
display.println("OLED Test");
display.display();
}
void loop() {}
创建自定义库
当你的代码需要在多个项目中复用时,可以创建自己的库。
库的基本结构
MyLibrary/
├── MyLibrary.h // 头文件
├── MyLibrary.cpp // 实现文件
├── keywords.txt // 关键字高亮(可选)
└── README.md // 说明文档(可选)
头文件示例
// MyLibrary.h
#ifndef MYLIBRARY_H
#define MYLIBRARY_H
#include <Arduino.h>
class MyLED {
private:
int pin;
bool state;
public:
MyLED(int pin);
void begin();
void on();
void off();
void toggle();
bool getState();
};
#endif
实现文件示例
// MyLibrary.cpp
#include "MyLibrary.h"
MyLED::MyLED(int pin) {
this->pin = pin;
this->state = false;
}
void MyLED::begin() {
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
void MyLED::on() {
digitalWrite(pin, HIGH);
state = true;
}
void MyLED::off() {
digitalWrite(pin, LOW);
state = false;
}
void MyLED::toggle() {
state ? off() : on();
}
bool MyLED::getState() {
return state;
}
使用自定义库
#include <MyLibrary.h>
MyLED led(13);
void setup() {
led.begin();
}
void loop() {
led.toggle();
delay(1000);
}
库的最佳实践
选择库的建议
- 优先选择官方库:官方库通常更稳定、维护更好
- 查看更新日期:长时间未更新的库可能有问题
- 阅读文档:好的库应该有清晰的使用文档
- 检查示例代码:示例代码可以帮助快速上手
- 关注社区反馈:查看 GitHub stars 和 issues
使用库的注意事项
- 内存占用:大型库可能占用大量内存,注意监控
- 引脚冲突:不同库可能使用相同的引脚或定时器
- 兼容性:某些库可能不支持所有 Arduino 开发板
- 版本问题:更新库时注意 API 是否有变化
库冲突排查
当多个库冲突时,检查以下方面:
- 是否使用了相同的引脚
- 是否使用了相同的定时器
- 是否有内存不足的问题
- 是否有命名冲突
常见问题
库安装后找不到
- 确认安装路径正确
- 重启 Arduino IDE
- 检查库文件夹名称是否正确
编译错误:未定义的引用
- 确认正确包含了头文件
- 检查库名称拼写是否正确
- 确认库已正确安装
程序太大或内存不足
- 移除未使用的库
- 使用更轻量的替代库
- 优化代码减少内存使用
下一步
掌握常用库后,你已经具备了开发复杂 Arduino 项目的能力。接下来可以通过实战项目来综合运用所学知识。