非常好,既然你目前 **暂时不需要使用超声波**,我们可以彻底释放 `Trig` 和 `Echo` 所占用的引脚(原为 GPIO 27 和 GPIO 34),并进一步优化整体引脚布局,为后续扩展 **I²C、UART、SPI 或其他传感器** 留出更多空间。
---
### ✅ 目标
1. **完全移除超声波相关代码和引脚占用**
2. **确保 I²C 接口安全保留:SDA=21, SCL=22**
3. **释放 GPIO 27 和 GPIO 34,可用于未来功能扩展**
4. **保持电机、红外等核心功能不变**
---
### ✅ 当前已使用与可释放引脚
| 引脚 | 原用途 | 是否可释放 | 说明 |
|------|--------|------------|------|
| 12 | 左电机正转 | ❌ 使用中 | 必需 |
| 13 | 左电机反转 | ❌ 使用中 | 必需 |
| 14 | 右电机正转 | ❌ 使用中 | 必需 |
| 15 | 右电机反转 | ❌ 使用中 | 必需 |
| 32 | 红外1 | ❌ 使用中 | 巡线必需 |
| 33 | 红外2 | ❌ 使用中 | 巡线必需 |
| 25 | 红外3 | ❌ 使用中 | 巡线必需 |
| 26 | 红外4 | ❌ 使用中 | 巡线必需 |
| 27 | 超声波 Trig | ✅ 可释放 | 暂不使用 |
| 34 | 超声波 Echo | ✅ 可释放 | 暂不使用 |
| 21 | I²C SDA | ✅ 保留 | 不接其他 |
| 22 | I²C SCL | ✅ 保留 | 不接其他 |
> 📌 所有非必要外设均已移除,系统更简洁稳定!
---
## ✅ 最终精简版代码(无超声波,仅巡线 + 预留通信接口)
```cpp
#include <Arduino.h>
// ==================== 核心功能引脚定义 ====================
// 电机控制 (L9110S)
#define LEFT_FORWARD 12
#define LEFT_BACKWARD 13
#define RIGHT_FORWARD 14
#define RIGHT_BACKWARD 15
// 四路红外传感器
#define IR_LEFTMOST 32
#define IR_LEFT 33
#define IR_RIGHT 25
#define IR_RIGHTMOST 26
// I2C 保留引脚(用于后续 OLED、MPU6050 等)
#define I2C_SDA 21
#define I2C_SCL 22
// 可选串口扩展(如蓝牙、GPS)
#define UART2_TX 5
#define UART2_RX 4
// ==================== 巡线参数 ====================
const int BASE_SPEED = 120; // 基础速度
const int MAX_SPEED = 200;
const int MIN_SPEED = 80;
// PID 控制参数(建议调试时调整)
float Kp = 18.0, Ki = 0.0, Kd = 80.0;
float integral = 0, last_error = 0;
// ==================== setup() 初始化 ====================
void setup() {
Serial.begin(115200); // 调试输出
Serial2.begin(9600, SERIAL_8N1, UART2_RX, UART2_TX); // 扩展串口
// 设置电机引脚
pinMode(LEFT_FORWARD, OUTPUT);
pinMode(LEFT_BACKWARD, OUTPUT);
pinMode(RIGHT_FORWARD, OUTPUT);
pinMode(RIGHT_BACKWARD, OUTPUT);
// 设置红外传感器为输入
pinMode(IR_LEFTMOST, INPUT);
pinMode(IR_LEFT, INPUT);
pinMode(IR_RIGHT, INPUT);
pinMode(IR_RIGHTMOST, INPUT);
// 初始化 PWM 控制
initPWM();
delay(1000);
Serial.println("✅ 巡线小车启动完成");
Serial.println("📌 I2C 已预留: SDA=21, SCL=22");
Serial.println("📌 UART2 已启用: TX=5, RX=4");
Serial.println("📌 所有超声波引脚已释放(GPIO 27 & 34 可用)");
}
// ==================== 读取红外传感器状态 ====================
int readSensors() {
bool onLine[4] = {
digitalRead(IR_LEFTMOST) == LOW,
digitalRead(IR_LEFT) == LOW,
digitalRead(IR_RIGHT) == LOW,
digitalRead(IR_RIGHTMOST) == LOW
};
// 判断位置并返回误差值 (-3 ~ +3)
if (onLine[0] && !onLine[1] && !onLine[2] && !onLine[3]) return -3; // 极左
if (!onLine[0] && onLine[1] && !onLine[2] && !onLine[3]) return -2; // 偏左
if (!onLine[0] && !onLine[1] && onLine[2] && !onLine[3]) return 2; // 偏右
if (!onLine[0] && !onLine[1] && !onLine[2] && onLine[3]) return 3; // 极右
if (!onLine[0] && onLine[1] && onLine[2] && !onLine[3]) return -1; // 中偏左
if (!onLine[0] && !onLine[1] && onLine[2] && onLine[3]) return 1; // 中偏右
if (onLine[0] && onLine[1] && !onLine[2] && !onLine[3]) return -1;
if (!onLine[0] && onLine[1] && onLine[2] && onLine[3]) return 1;
if (onLine[0] && onLine[1] && onLine[2] && onLine[3]) return 0; // 全黑(交叉或终点)
if (!onLine[0] && !onLine[1] && !onLine[2] && !onLine[3]) return 0; // 全白(脱线)
return 0;
}
// ==================== PWM 初始化 ====================
void initPWM() {
ledcSetup(0, 5000, 8); // 左正
ledcSetup(1, 5000, 8); // 左反
ledcSetup(2, 5000, 8); // 右正
ledcSetup(3, 5000, 8); // 右反
ledcAttachPin(LEFT_FORWARD, 0);
ledcAttachPin(LEFT_BACKWARD, 1);
ledcAttachPin(RIGHT_FORWARD, 2);
ledcAttachPin(RIGHT_BACKWARD, 3);
}
// ==================== 电机控制函数 ====================
void setMotorSpeed(int leftSpeed, int rightSpeed) {
leftSpeed = constrain(leftSpeed, 0, 255);
rightSpeed = constrain(rightSpeed, 0, 255);
// 左电机
if (leftSpeed > 0) {
ledcWrite(0, leftSpeed);
ledcWrite(1, 0);
} else {
ledcWrite(0, 0);
ledcWrite(1, -leftSpeed);
}
// 右电机
if (rightSpeed > 0) {
ledcWrite(2, rightSpeed);
ledcWrite(3, 0);
} else {
ledcWrite(2, 0);
ledcWrite(3, -rightSpeed);
}
}
// ==================== 主循环:纯巡线 ====================
void loop() {
int error = readSensors();
// PID 计算
float derivative = error - last_error;
integral += error;
float power_diff = Kp * error + Ki * integral + Kd * derivative;
last_error = error;
// 计算左右轮速度
int leftSpeed = BASE_SPEED - power_diff;
int rightSpeed = BASE_SPEED + power_diff;
// 限幅
leftSpeed = constrain(leftSpeed, MIN_SPEED, MAX_SPEED);
rightSpeed = constrain(rightSpeed, MIN_SPEED, MAX_SPEED);
// 驱动电机
setMotorSpeed(leftSpeed, rightSpeed);
// 实时调试信息
Serial.print("Err:");
Serial.print(error);
Serial.print(" | L:");
Serial.print(leftSpeed);
Serial.print(" R:");
Serial.print(rightSpeed);
Serial.println();
// 可通过 UART2 接收外部命令(例如切换模式)
if (Serial2.available()) {
String cmd = Serial2.readStringUntil('\n');
Serial.print("🔹 收到指令: ");
Serial.println(cmd);
// 示例处理
if (cmd == "STOP") setMotorSpeed(0, 0);
if (cmd == "FORWARD") setMotorSpeed(150, 150);
}
delay(20); // 小延时,避免过快刷新
}
```
---
### ✅ 当前空闲可用的引脚(可扩展新功能)
| 引脚 | 可用途 |
|------|-------|
| 27 | 可用于 SPI CS、数字输入、LED 指示灯 |
| 34 | 输入专用 → 可接按键、限位开关、模拟比较输出 |
| 35 | 输入专用 → 可接另一路传感器 |
| 4 | UART2 RX(已用) |
| 5 | UART2 TX(已用) |
| 23 | 完全空闲 → 可用于 SPI CLK 或额外控制信号 |
> 💡 提示:GPIO 34/35 是输入专用,不能输出,但非常适合接按钮、比较器输出等。
---
### ✅ 后续扩展建议
| 功能 | 推荐引脚 | 接口类型 |
|------|----------|---------|
| OLED 显示屏 | SDA=21, SCL=22 | I²C |
| MPU6050 陀螺仪 | 同上 | I²C |
| 蓝牙模块 HC-05 | TX=5, RX=4 | UART2 |
| 按键/急停开关 | GPIO 34 | 数字输入 |
| RGB 指示灯 | GPIO 27 | PWM 输出 |
| SPI Flash 或传感器 | GPIO 23(SCK), 19(MISO), 26(MOSI), 自定义 CS | SPI |
---