数字 I/O
数字输入输出(Digital I/O)是 Arduino 最基础也是最常用的功能。本章将详细介绍如何使用数字引脚控制 LED、读取按钮状态等。
数字引脚概述
Arduino Uno 有 14 个数字引脚(D0-D13),每个引脚都可以配置为输入或输出模式:
- D0 (RX) 和 D1 (TX):用于串口通信,一般不建议他用
- D2-D13:可自由使用的数字引脚
- D3、D5、D6、D9、D10、D11:支持 PWM 输出(带
~标记) - D13:连接板载 LED
引脚模式设置
在使用数字引脚前,必须先使用 pinMode() 函数设置其模式:
void setup() {
pinMode(pin, mode);
}
三种引脚模式
| 模式 | 说明 | 用途 |
|---|---|---|
INPUT | 输入模式(高阻抗) | 读取传感器、按钮 |
OUTPUT | 输出模式 | 控制 LED、继电器 |
INPUT_PULLUP | 输入上拉模式 | 简化按钮接线 |
数字输出
digitalWrite() 函数
控制数字引脚输出高电平(5V)或低电平(0V):
digitalWrite(pin, value);
pin:引脚编号(0-13)value:HIGH(高电平)或LOW(低电平)
点亮 LED 示例
硬件连接:
Arduino D13 ──┬── LED 正极(长脚)
└── 220Ω 电阻 ── GND
代码:
const int LED_PIN = 13; // 使用引脚 13
void setup() {
pinMode(LED_PIN, OUTPUT); // 设置为输出模式
}
void loop() {
digitalWrite(LED_PIN, HIGH); // 点亮 LED
delay(1000); // 等待 1 秒
digitalWrite(LED_PIN, LOW); // 熄灭 LED
delay(1000); // 等待 1 秒
}
流水灯效果
硬件连接:将 4 个 LED 分别连接到 D2-D5,每个串联 220Ω 电阻到 GND
const int ledPins[] = {2, 3, 4, 5}; // LED 连接的引脚
const int numLEDs = 4;
void setup() {
// 初始化所有 LED 引脚
for (int i = 0; i < numLEDs; i++) {
pinMode(ledPins[i], OUTPUT);
}
}
void loop() {
// 从左到右依次点亮
for (int i = 0; i < numLEDs; i++) {
digitalWrite(ledPins[i], HIGH);
delay(200);
digitalWrite(ledPins[i], LOW);
}
// 从右到左依次点亮
for (int i = numLEDs - 1; i >= 0; i--) {
digitalWrite(ledPins[i], HIGH);
delay(200);
digitalWrite(ledPins[i], LOW);
}
}
数字输入
digitalRead() 函数
读取数字引脚的电平状态:
int value = digitalRead(pin);
- 返回
HIGH(高电平,约 5V)或LOW(低电平,约 0V)
读取按钮状态
硬件连接方式一:外部下拉电阻
5V ── 按钮 ── D2 ──┬── 10kΩ 电阻 ── GND
│
Arduino 读取
const int BUTTON_PIN = 2;
void setup() {
pinMode(BUTTON_PIN, INPUT); // 输入模式
Serial.begin(9600);
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == HIGH) {
Serial.println("按钮被按下");
} else {
Serial.println("按钮未按下");
}
delay(100); // 减少串口输出频率
}
硬件连接方式二:内部上拉电阻(推荐)
D2 ── 按钮 ── GND
const int BUTTON_PIN = 2;
void setup() {
// 使用内部上拉电阻,按钮未按下时为 HIGH
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
// 注意:使用上拉时,按下为 LOW,未按下为 HIGH
if (buttonState == LOW) {
Serial.println("按钮被按下");
}
delay(100);
}
按钮消抖
机械按钮按下时会产生抖动,导致多次触发:
const int BUTTON_PIN = 2;
const int LED_PIN = 13;
int ledState = LOW;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50; // 消抖延时 50ms
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int reading = digitalRead(BUTTON_PIN);
// 如果按钮状态发生变化,重置消抖计时器
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
// 超过消抖时间后,确认状态变化
if ((millis() - lastDebounceTime) > debounceDelay) {
// 如果按钮被按下(上拉模式下 LOW 表示按下)
if (reading == LOW && lastButtonState == HIGH) {
ledState = !ledState; // 切换 LED 状态
digitalWrite(LED_PIN, ledState);
}
}
lastButtonState = reading;
}
综合示例:交通灯
模拟交通信号灯的工作流程:
硬件连接:
- 红灯 → D10
- 黄灯 → D9
- 绿灯 → D8
// 引脚定义
const int RED_PIN = 10;
const int YELLOW_PIN = 9;
const int GREEN_PIN = 8;
// 时间设置(毫秒)
const int RED_TIME = 5000; // 红灯 5 秒
const int YELLOW_TIME = 2000; // 黄灯 2 秒
const int GREEN_TIME = 5000; // 绿灯 5 秒
void setup() {
// 初始化引脚
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
// 初始状态:全部熄灭
allOff();
}
void loop() {
// 绿灯亮(通行)
digitalWrite(GREEN_PIN, HIGH);
delay(GREEN_TIME);
digitalWrite(GREEN_PIN, LOW);
// 黄灯亮(警示)
digitalWrite(YELLOW_PIN, HIGH);
delay(YELLOW_TIME);
digitalWrite(YELLOW_PIN, LOW);
// 红灯亮(停止)
digitalWrite(RED_PIN, HIGH);
delay(RED_TIME);
digitalWrite(RED_PIN, LOW);
}
// 辅助函数:关闭所有灯
void allOff() {
digitalWrite(RED_PIN, LOW);
digitalWrite(YELLOW_PIN, LOW);
digitalWrite(GREEN_PIN, LOW);
}
按键控制 LED
实现按下按钮切换 LED 开关状态:
const int BUTTON_PIN = 2;
const int LED_PIN = 13;
bool ledState = false; // LED 当前状态
bool buttonPressed = false; // 按钮是否已被处理
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
// 检测按钮按下(上拉模式下 LOW 为按下)
if (buttonState == LOW && !buttonPressed) {
ledState = !ledState; // 切换状态
digitalWrite(LED_PIN, ledState); // 更新 LED
buttonPressed = true; // 标记已处理
delay(200); // 简单消抖
}
// 检测按钮释放
if (buttonState == HIGH) {
buttonPressed = false;
}
}
多位数码管显示
使用 74HC595 移位寄存器控制数码管(节省引脚):
// 74HC595 引脚连接
const int DATA_PIN = 11; // DS (数据)
const int LATCH_PIN = 12; // ST_CP (锁存)
const int CLOCK_PIN = 13; // SH_CP (时钟)
// 数码管段码(共阴极,0-9)
const byte segmentPatterns[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
void setup() {
pinMode(DATA_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
}
void loop() {
// 循环显示 0-9
for (int i = 0; i <= 9; i++) {
displayNumber(i);
delay(1000);
}
}
// 显示单个数字
void displayNumber(int num) {
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, segmentPatterns[num]);
digitalWrite(LATCH_PIN, HIGH);
}
常见问题
1. LED 不亮
检查清单:
- LED 极性是否正确(长脚接正极)
- 电阻是否正确连接(220Ω-1kΩ)
- 引脚号是否与代码一致
- 是否设置了
pinMode(pin, OUTPUT)
2. 按钮读取不稳定
解决方法:
- 添加消抖延时(硬件或软件)
- 使用
INPUT_PULLUP模式简化接线 - 检查按钮接线是否松动
3. 引脚冲突
注意:
- D0、D1 用于串口通信,使用时无法上传程序
- D13 连接板载 LED,同时使用时可能互相影响
- PWM 引脚(带 ~)才能使用
analogWrite()
下一步
掌握了数字 I/O 后,我们将学习模拟 I/O,包括读取模拟传感器和使用 PWM 实现更精细的控制。