Arduino 核心外设与通信模块使用指南

本文详细整理了 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)

绑定外部中断:

pin:中断引脚(Uno 为 2/3);

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 波:

pin:支持 PWM 的引脚(Uno 3/5/6/9/10/11);

value:0~255(0=0% 占空比,255=100%)

实例代码:呼吸灯

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)

设置参考电压:

DEFAULT(5V)

INTERNAL(1.1V)

EXTERNAL(外部参考)

实例代码:读取电位器值控制 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 SSD1306Adafruit GFX库。

硬件接线

OLED 引脚Arduino Uno 引脚
VCC3.3V(勿接 5V)
GNDGND
SDAA4
SCLA5

实例代码: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 引脚
VCC3.3V
GNDGND
SCL13(SCK)
SDA11(MOSI)
RES8
DC9
CS10

实例代码: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 引脚
R19C15
R28C24
R37C33
R46C42

实例代码: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 引脚
VCC5V
GNDGND
TXRX(0)
RXTX(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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值