本文详细整理了 Arduino 中常用外设(GPIO、中断、时钟、定时器等)和通信模块(UART、I2C、SPI、蓝牙、WiFi 等)的语法、用法,并附带可直接运行的实例代码,覆盖从基础 IO 到进阶通信的全场景需求。
1、GPIO(数字输入输出)
核心函数
| 函数 | 作用 |
|---|---|
pinMode(pin,mode) | 配置引脚模式:OUTPUT(输出)/INPUT(输入)/INPUT_PULLUP(上拉输入) |
digitalWrite(pin, value) | 输出高低电平:HIGH(高)/LOW(低) |
digitalRead(pin) | 读取引脚电平,返回HIGH/LOW |
实例代码:LED 闪烁 + 按键控制
const int ledPin = 13; // LED引脚
const int keyPin = 2; // 按键引脚
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(keyPin, INPUT_PULLUP); // 上拉输入,按键未按下时为HIGH
}
void loop() {
int keyState = digitalRead(keyPin); // 读取按键状态
if (keyState == LOW) { // 按键按下(接地)
digitalWrite(ledPin, HIGH); // LED亮
} else {
digitalWrite(ledPin, LOW); // LED灭
}
delay(100); // 消抖
}
2. 串口通信(UART)
核心函数
| 函数 | 作用 |
|---|---|
Serial.begin(baud) | 初始化串口,设置波特率(9600/115200 等) |
Serial.print(data) | 发送数据(不换行) |
Serial.println(data) | 发送数据 + 换行 |
Serial.available() | 返回串口缓冲区未读取字节数 |
Serial.read() | 读取 1 个字节数据 |
实例代码:串口收发指令控制 LED
const int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600); // 初始化串口,波特率9600
while (!Serial); // 等待串口连接(仅带USB的主板有效)
}
void loop() {
// 接收串口数据
if (Serial.available() > 0) {
char cmd = Serial.read();
if (cmd == '1') {
digitalWrite(ledPin, HIGH);
Serial.println("LED已打开");
} else if (cmd == '0') {
digitalWrite(ledPin, LOW);
Serial.println("LED已关闭");
} else {
Serial.println("未知指令,请发送1/0");
}
}
// 发送传感器模拟数据
int sensorVal = analogRead(A0);
Serial.print("模拟值:");
Serial.println(sensorVal);
delay(500);
}
3. 中断系统(INT)
核心函数
| 函数 | 作用 |
|---|---|
attachInterrupt(pin, ISR, mode) |
绑定外部中断:
|
detachInterrupt(pin) | 解除中断绑定 |
触发模式
RISING:上升沿触发(低→高)FALLING:下降沿触发(高→低)CHANGE:电平变化触发LOW:低电平触发(仅部分主板支持)
实例代码:中断触发 LED 翻转
const int ledPin = 13;
const int intPin = 2; // Uno中断引脚2
volatile int ledState = LOW; // 易失性变量,中断中修改
// 中断处理函数(无参数、无返回值)
void toggleLED() {
ledState = !ledState;
}
void setup() {
pinMode(ledPin, OUTPUT);
// 绑定中断:引脚2,下降沿触发(按键按下)
attachInterrupt(digitalPinToInterrupt(intPin), toggleLED, FALLING);
}
void loop() {
digitalWrite(ledPin, ledState); // 刷新LED状态
}
4. 系统时钟
Arduino 默认系统时钟由晶振决定(Uno 为 16MHz,ESP32 为 80MHz/160MHz),无需手动配置,核心影响:
delay(ms):毫秒级延时,基于系统时钟;micros():返回开机以来微秒数(16MHz 下精度 4μs);millis():返回开机以来毫秒数(溢出周期约 50 天)。
实例代码:精准计时(替代 delay)
const int ledPin = 13;
unsigned long previousMillis = 0; // 上一次切换时间
const long interval = 1000; // 间隔1秒
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
// 非阻塞延时,避免delay占用CPU
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
digitalWrite(ledPin, !digitalRead(ledPin)); // 翻转LED
}
}
5. 定时器
Arduino 定时器分为硬件定时器(Timer0/Timer1/Timer2)和软件定时器,以下为常用的Timer1定时器示例(Uno)。
实例代码:Timer1 定时中断(1 秒触发一次)
#include <TimerOne.h> // 需安装TimerOne库
const int ledPin = 13;
int count = 0;
// 定时器中断处理函数
void timerIsr() {
count++;
if (count >= 100) { // 100*10ms=1秒
count = 0;
digitalWrite(ledPin, !digitalRead(ledPin));
}
}
void setup() {
pinMode(ledPin, OUTPUT);
Timer1.initialize(10000); // 初始化定时器,定时10ms(10000μs)
Timer1.attachInterrupt(timerIsr); // 绑定中断函数
}
void loop() {
// 主循环可执行其他任务,不阻塞
}
6. PWM(脉冲宽度调制)
核心函数
| 函数 | 作用 |
|---|---|
analogWrite(pin, value) |
输出 PWM 波:
|
实例代码:呼吸灯
const int ledPin = 9; // Uno PWM引脚9
int brightness = 0; // 亮度0~255
int fadeStep = 1; // 亮度步长
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
analogWrite(ledPin, brightness); // 输出PWM
brightness += fadeStep;
// 到达边界反转步长
if (brightness <= 0 || brightness >= 255) {
fadeStep = -fadeStep;
}
delay(10); // 渐变速度
}
7. ADC(模拟数字转换)
Arduino Uno 内置 10 位 ADC(0~1023),参考电压默认 5V(可通过analogReference()修改)。
核心函数
| 函数 | 作用 |
|---|---|
analogRead(pin) | 读取模拟引脚值,返回 0~1023 |
analogReference(type) |
设置参考电压:
|
实例代码:读取电位器值控制 PWM
const int potPin = A0; // 电位器引脚
const int ledPin = 9; // PWM引脚
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
int potVal = analogRead(potPin); // 读取电位器值(0~1023)
int pwmVal = map(potVal, 0, 1023, 0, 255); // 映射到0~255
analogWrite(ledPin, pwmVal); // 控制LED亮度
Serial.print("电位器值:");
Serial.print(potVal);
Serial.print(" → PWM值:");
Serial.println(pwmVal);
delay(100);
}
8. RTC 时钟
需外接 RTC 模块(如 DS3231),通过 I2C 通信,精度高于系统时钟。
实例代码:DS3231 RTC 读取时间
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc; // 创建RTC对象
void setup() {
Serial.begin(9600);
if (!rtc.begin()) { // 初始化RTC
Serial.println("RTC模块未找到!");
while (1);
}
// 首次使用设置时间(注释掉已设置的行)
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // 使用编译时间
// rtc.adjust(DateTime(2025, 12, 9, 10, 30, 0)); // 手动设置:年/月/日/时/分/秒
}
void loop() {
DateTime now = rtc.now(); // 获取当前时间
// 打印时间
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.println(now.second(), DEC);
delay(1000);
}
9. I2C 总线
I2C 是双线串行总线(SDA/SCL),Arduino Uno SDA=A4、SCL=A5,ESP32 SDA=21、SCL=22。
核心函数(Wire 库)
| 函数 | 作用 |
|---|---|
Wire.begin() | 初始化 I2C 总线(主设备) |
Wire.begin(address) | 初始化 I2C 总线(从设备,指定地址) |
Wire.beginTransmission(address) | 开始向从设备发送数据 |
Wire.write(data) | 发送字节 / 字符串 / 数组 |
Wire.endTransmission() | 结束传输,返回 0 = 成功 |
Wire.requestFrom(address, len) | 从从设备读取指定长度数据 |
Wire.available() | 返回可读取的字节数 |
Wire.read() | 读取 1 个字节数据 |
实例代码:I2C 主从通信(主设备发送数据)
主设备代码
#include <Wire.h>
void setup() {
Wire.begin(); // 初始化I2C主设备
Serial.begin(9600);
}
void loop() {
Wire.beginTransmission(8); // 向地址8的从设备发送数据
Wire.write("Hello I2C"); // 发送字符串
Wire.endTransmission(); // 结束传输
Serial.println("数据已发送");
delay(1000);
}
从设备代码
#include <Wire.h>
void setup() {
Wire.begin(8); // 初始化I2C从设备,地址8
Wire.onReceive(receiveEvent); // 注册接收数据回调函数
Serial.begin(9600);
}
void loop() {
delay(100);
}
// 接收数据回调函数
void receiveEvent(int howMany) {
while (Wire.available()) { // 读取所有数据
char c = Wire.read();
Serial.print(c);
}
Serial.println();
}
10. 外部中断(EXTI)
外部中断与「中断系统」原理一致,以下为 ESP32 多中断示例(支持任意引脚)。
实例代码:ESP32 外部中断(双按键控制 LED)
const int led1Pin = 2;
const int led2Pin = 4;
const int key1Pin = 18; // 中断引脚18
const int key2Pin = 19; // 中断引脚19
volatile bool led1State = LOW;
volatile bool led2State = LOW;
// 中断处理函数1
void IRAM_ATTR key1ISR() { // IRAM_ATTR:ESP32中断函数需放入RAM
led1State = !led1State;
}
// 中断处理函数2
void IRAM_ATTR key2ISR() {
led2State = !led2State;
}
void setup() {
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(key1Pin, INPUT_PULLUP);
pinMode(key2Pin, INPUT_PULLUP);
// 绑定中断:下降沿触发
attachInterrupt(digitalPinToInterrupt(key1Pin), key1ISR, FALLING);
attachInterrupt(digitalPinToInterrupt(key2Pin), key2ISR, FALLING);
}
void loop() {
digitalWrite(led1Pin, led1State);
digitalWrite(led2Pin, led2State);
}
11. OLED 显示器(I2C)
常用 0.96 寸 I2C OLED(SSD1306 驱动),需安装Adafruit SSD1306和Adafruit GFX库。
硬件接线
| OLED 引脚 | Arduino Uno 引脚 |
|---|---|
| VCC | 3.3V(勿接 5V) |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
实例代码:I2C OLED 显示文字 / 图形
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// 屏幕分辨率:128x64
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C // OLED I2C地址(0x3C/0x3D)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
// 初始化OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("OLED初始化失败"));
while(1);
}
delay(2000);
display.clearDisplay(); // 清屏
// 显示文字
display.setTextSize(1); // 字体大小1
display.setTextColor(SSD1306_WHITE); // 白色字体
display.setCursor(0, 0); // 设置光标位置
display.println(F("Arduino OLED I2C"));
// 显示数字
display.setTextSize(2);
display.setCursor(0, 20);
display.println(12345);
// 绘制矩形
display.drawRect(0, 40, 60, 20, SSD1306_WHITE); // 空心矩形
display.fillRect(70, 40, 50, 20, SSD1306_WHITE); // 实心矩形
display.display(); // 刷新显示
}
void loop() {
// 动态显示秒数
static int sec = 0;
display.setCursor(0, 50);
display.setTextSize(1);
display.print("Sec: ");
display.println(sec++);
display.display();
display.fillRect(0, 50, 128, 10, SSD1306_BLACK); // 清除旧数据
delay(1000);
}
12. OLED 显示器(SPI)
SPI OLED 速度更快,接线更多,驱动库与 I2C 通用。
硬件接线(0.96 寸 SPI OLED)
| OLED 引脚 | Arduino Uno 引脚 |
|---|---|
| VCC | 3.3V |
| GND | GND |
| SCL | 13(SCK) |
| SDA | 11(MOSI) |
| RES | 8 |
| DC | 9 |
| CS | 10 |
实例代码:SPI OLED 显示
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_DC 9
#define OLED_CS 10
#define OLED_RESET 8
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
&SPI, OLED_DC, OLED_RESET, OLED_CS);
void setup() {
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("OLED初始化失败"));
while(1);
}
display.clearDisplay();
// 显示图形
display.drawCircle(64, 32, 20, SSD1306_WHITE); // 绘制圆形
display.drawLine(0, 0, 127, 63, SSD1306_WHITE); // 绘制直线
display.setTextColor(SSD1306_WHITE);
display.setCursor(30, 30);
display.println("SPI OLED");
display.display();
}
void loop() {
// 屏幕翻转
display.invertDisplay(true);
delay(500);
display.invertDisplay(false);
delay(500);
}
13. 独立按键
独立按键核心是「消抖」(硬件 / 软件),以下为软件消抖示例。
实例代码:独立按键长按 / 短按识别
const int keyPin = 2;
unsigned long pressTime = 0; // 按下时间
bool keyPressed = false;
void setup() {
pinMode(keyPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
int keyState = digitalRead(keyPin);
if (keyState == LOW && !keyPressed) { // 按键按下
pressTime = millis();
keyPressed = true;
} else if (keyState == HIGH && keyPressed) { // 按键松开
unsigned long pressDuration = millis() - pressTime;
if (pressDuration < 500) {
Serial.println("短按");
} else {
Serial.println("长按");
}
keyPressed = false;
delay(50); // 消抖
}
}
14. 矩阵键盘
4x4 矩阵键盘通过行 / 列扫描识别按键,需安装Keypad库。
硬件接线(4x4 矩阵键盘)
| 键盘行 | Arduino 引脚 | 键盘列 | Arduino 引脚 |
|---|---|---|---|
| R1 | 9 | C1 | 5 |
| R2 | 8 | C2 | 4 |
| R3 | 7 | C3 | 3 |
| R4 | 6 | C4 | 2 |
实例代码:4x4 矩阵键盘读取按键
#include <Keypad.h>
const byte ROWS = 4; // 行数
const byte COLS = 4; // 列数
// 按键定义
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9,8,7,6}; // 行引脚
byte colPins[COLS] = {5,4,3,2}; // 列引脚
// 创建键盘对象
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup() {
Serial.begin(9600);
}
void loop() {
char key = keypad.getKey(); // 读取按键
if (key) { // 有按键按下
Serial.print("按下按键:");
Serial.println(key);
}
}
15. EEPROM 读写
Arduino 内置 EEPROM(电可擦除只读存储器),掉电数据不丢失,Uno 有 1024 字节(地址 0~1023)。
核心函数(EEPROM 库)
| 函数 | 作用 |
|---|---|
EEPROM.write(addr, val) | 向指定地址写入字节(0~255) |
EEPROM.read(addr) | 从指定地址读取字节 |
EEPROM.update(addr, val) | 仅当值不同时写入(减少擦写次数) |
EEPROM.clear() | 清空所有数据(写入 0) |
实例代码:EEPROM 存储 / 读取计数器
#include <EEPROM.h>
const int addr = 0; // 存储地址
int count = 0;
void setup() {
Serial.begin(9600);
// 读取EEPROM中的值
count = EEPROM.read(addr);
Serial.print("上次计数:");
Serial.println(count);
// 计数+1并写入EEPROM
count++;
EEPROM.write(addr, count);
// EEPROM.update(addr, count); // 推荐使用update
Serial.print("当前计数:");
Serial.println(count);
}
void loop() {
// 如需持续计数,可在loop中添加逻辑
delay(1000);
}
16. 蓝牙模块(HC-05)
HC-05 是串口蓝牙模块,通过 UART 与 Arduino 通信,支持主从模式。
硬件接线
| HC-05 引脚 | Arduino Uno 引脚 |
|---|---|
| VCC | 5V |
| GND | GND |
| TX | RX(0) |
| RX | TX(1)(需串联 1kΩ 电阻分压) |
实例代码:蓝牙控制 LED
const int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600); // 与HC-05波特率一致(默认9600)
}
void loop() {
if (Serial.available() > 0) {
char cmd = Serial.read();
if (cmd == '1') {
digitalWrite(ledPin, HIGH);
Serial.println("LED ON"); // 反馈给蓝牙
} else if (cmd == '0') {
digitalWrite(ledPin, LOW);
Serial.println("LED OFF");
}
}
}
17. WiFi 模块(ESP8266/ESP32)
ESP8266/ESP32 内置 WiFi,可直接编程,无需外接模块,以下为 ESP8266 连接 WiFi 并实现 TCP 客户端示例。
实例代码:ESP8266 连接 WiFi+TCP 通信
#include <ESP8266WiFi.h>
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
const char* host = "192.168.1.100"; // 服务器IP
const int port = 8080; // 服务器端口
WiFiClient client;
void setup() {
Serial.begin(115200);
delay(10);
// 连接WiFi
Serial.println();
Serial.print("连接WiFi:");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi已连接");
Serial.println("IP地址:");
Serial.println(WiFi.localIP());
// 连接TCP服务器
Serial.print("连接服务器:");
Serial.println(host);
if (!client.connect(host, port)) {
Serial.println("连接失败");
return;
}
// 发送数据到服务器
client.println("Hello ESP8266 TCP Client");
}
void loop() {
// 读取服务器返回数据
if (client.available()) {
String data = client.readStringUntil('\n');
Serial.print("服务器返回:");
Serial.println(data);
}
// 断开连接后重连
if (!client.connected()) {
Serial.println("连接断开,重连中...");
client.connect(host, port);
}
delay(1000);
}

被折叠的 条评论
为什么被折叠?



