跳到主要内容

串口通信

串口通信(Serial Communication)是 Arduino 与电脑、其他微控制器或外部设备交互的重要方式。本章将详细介绍串口通信的原理和应用。

什么是串口通信

串口通信是一种逐位传输数据的通信方式,数据一位一位顺序传送。Arduino 使用 UART(通用异步收发传输器)实现串口通信。

串口通信参数

配置串口通信时需要指定以下参数:

参数说明常用值
波特率每秒传输的比特数9600, 115200
数据位每个数据包的位数8 位
停止位数据包结束标志1 位
校验位错误检测

Arduino 串口引脚

  • D0 (RX):接收数据
  • D1 (TX):发送数据
注意

使用串口通信时,D0 和 D1 不能用于其他功能。上传程序时也需要断开这两脚的外部连接。

基础串口操作

初始化串口

setup() 中使用 Serial.begin() 初始化串口:

void setup() {
Serial.begin(9600); // 设置波特率为 9600
}

发送数据

发送字符串

Serial.print("Hello World");     // 不换行
Serial.println("Hello World"); // 换行

发送变量值

int count = 42;
float temp = 23.5;

Serial.print("计数: ");
Serial.println(count);

Serial.print("温度: ");
Serial.print(temp);
Serial.println(" °C");

格式化输出

int value = 255;

Serial.print("十进制: ");
Serial.println(value, DEC); // 255

Serial.print("十六进制: ");
Serial.println(value, HEX); // ff

Serial.print("二进制: ");
Serial.println(value, BIN); // 11111111

Serial.print("八进制: ");
Serial.println(value, OCT); // 377

完整发送示例

void setup() {
Serial.begin(9600);
}

void loop() {
static int counter = 0;
counter++;

// 多种输出方式
Serial.print("计数: ");
Serial.print(counter);
Serial.print(" | 时间: ");
Serial.print(millis() / 1000);
Serial.println(" 秒");

delay(1000);
}

接收数据

检查可用数据

void loop() {
if (Serial.available() > 0) { // 检查是否有数据可读
// 有数据到达,进行读取
}
}

读取数据

void loop() {
if (Serial.available() > 0) {
char incomingByte = Serial.read(); // 读取一个字节
Serial.print("收到: ");
Serial.println(incomingByte);
}
}

读取字符串

String inputString = "";
bool stringComplete = false;

void setup() {
Serial.begin(9600);
inputString.reserve(200); // 预分配内存,提高性能
}

void loop() {
if (stringComplete) {
Serial.print("收到命令: ");
Serial.println(inputString);

// 处理命令
processCommand(inputString);

// 清空字符串
inputString = "";
stringComplete = false;
}
}

void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();

if (inChar == '\n') {
stringComplete = true;
} else {
inputString += inChar;
}
}
}

void processCommand(String cmd) {
cmd.trim(); // 去除首尾空白
cmd.toLowerCase(); // 转为小写

if (cmd == "on") {
Serial.println("开启设备");
} else if (cmd == "off") {
Serial.println("关闭设备");
} else {
Serial.println("未知命令");
}
}

串口调试技巧

调试输出宏

// 定义调试开关
#define DEBUG 1

#if DEBUG
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#endif

void setup() {
Serial.begin(9600);
DEBUG_PRINTLN("调试模式已启动");
}

void loop() {
int sensorValue = analogRead(A0);
DEBUG_PRINT("传感器值: ");
DEBUG_PRINTLN(sensorValue);

delay(1000);
}

数据可视化

使用串口绘图器(Serial Plotter)可视化数据:

void setup() {
Serial.begin(9600);
}

void loop() {
int sensor1 = analogRead(A0);
int sensor2 = analogRead(A1);

// 格式:值1,值2(用逗号分隔)
Serial.print(sensor1);
Serial.print(",");
Serial.println(sensor2);

delay(50);
}

在 Arduino IDE 中点击 工具串口绘图器 即可看到实时波形。

综合示例:串口控制系统

通过串口命令控制 LED 和读取传感器:

const int LED_PIN = 13;
const int SENSOR_PIN = A0;

bool ledState = false;
bool autoReport = false;
unsigned long lastReportTime = 0;

void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);

Serial.println("=== Arduino 控制系统 ===");
Serial.println("命令列表:");
Serial.println(" on - 开启 LED");
Serial.println(" off - 关闭 LED");
Serial.println(" toggle - 切换 LED 状态");
Serial.println(" read - 读取传感器");
Serial.println(" auto - 开启/关闭自动上报");
Serial.println(" help - 显示帮助");
Serial.println("========================");
}

void loop() {
// 处理串口命令
handleSerialCommands();

// 自动上报传感器数据
if (autoReport && millis() - lastReportTime > 1000) {
reportSensorData();
lastReportTime = millis();
}
}

void handleSerialCommands() {
if (Serial.available() == 0) return;

String command = Serial.readStringUntil('\n');
command.trim();
command.toLowerCase();

if (command == "on") {
ledState = true;
digitalWrite(LED_PIN, HIGH);
Serial.println("LED 已开启");
}
else if (command == "off") {
ledState = false;
digitalWrite(LED_PIN, LOW);
Serial.println("LED 已关闭");
}
else if (command == "toggle") {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
Serial.println(ledState ? "LED 已开启" : "LED 已关闭");
}
else if (command == "read") {
reportSensorData();
}
else if (command == "auto") {
autoReport = !autoReport;
Serial.println(autoReport ? "自动上报已开启" : "自动上报已关闭");
}
else if (command == "help") {
printHelp();
}
else if (command.length() > 0) {
Serial.println("未知命令,输入 help 查看帮助");
}
}

void reportSensorData() {
int value = analogRead(SENSOR_PIN);
float voltage = value * 5.0 / 1023.0;

Serial.print("传感器值: ");
Serial.print(value);
Serial.print(" (");
Serial.print(voltage, 2);
Serial.println(" V)");
}

void printHelp() {
Serial.println("命令列表:");
Serial.println(" on - 开启 LED");
Serial.println(" off - 关闭 LED");
Serial.println(" toggle - 切换 LED 状态");
Serial.println(" read - 读取传感器");
Serial.println(" auto - 开启/关闭自动上报");
Serial.println(" help - 显示帮助");
}

软件串口

Arduino Uno 只有一个硬件串口。如需更多串口,可使用 SoftwareSerial 库:

#include <SoftwareSerial.h>

// 创建软串口,RX=10, TX=11
SoftwareSerial mySerial(10, 11);

void setup() {
// 硬件串口用于与电脑通信
Serial.begin(9600);

// 软串口用于与其他设备通信
mySerial.begin(9600);

Serial.println("软串口测试");
}

void loop() {
// 从软串口读取,转发到硬件串口
if (mySerial.available()) {
char c = mySerial.read();
Serial.write(c);
}

// 从硬件串口读取,转发到软串口
if (Serial.available()) {
char c = Serial.read();
mySerial.write(c);
}
}
软串口限制
  • 不能同时收发高速数据
  • 某些引脚可能不支持(取决于板子)
  • 会占用更多 CPU 资源

与其他设备通信

与 ESP8266 WiFi 模块通信

#include <SoftwareSerial.h>

SoftwareSerial esp8266(10, 11); // RX, TX

void setup() {
Serial.begin(9600);
esp8266.begin(115200);

delay(2000);

// 发送 AT 指令测试通信
sendCommand("AT");
sendCommand("AT+CWMODE=1"); // 设置为 Station 模式
sendCommand("AT+CWJAP=\"SSID\",\"PASSWORD\""); // 连接 WiFi
}

void loop() {
// 转发数据
if (esp8266.available()) {
Serial.write(esp8266.read());
}
if (Serial.available()) {
esp8266.write(Serial.read());
}
}

void sendCommand(String cmd) {
esp8266.println(cmd);
delay(1000);

while (esp8266.available()) {
Serial.write(esp8266.read());
}
}

两个 Arduino 通信

发送端

void setup() {
Serial.begin(9600);
}

void loop() {
Serial.print("TIME:");
Serial.println(millis());
delay(1000);
}

接收端

#include <SoftwareSerial.h>
SoftwareSerial receiver(10, 11);

void setup() {
Serial.begin(9600);
receiver.begin(9600);
}

void loop() {
if (receiver.available()) {
String data = receiver.readStringUntil('\n');

if (data.startsWith("TIME:")) {
String timeStr = data.substring(5);
Serial.print("收到时间: ");
Serial.println(timeStr);
}
}
}

串口监视器使用

Arduino IDE 内置串口监视器,用于查看串口输出:

  1. 点击工具栏的放大镜图标,或按 Ctrl+Shift+M
  2. 选择正确的波特率(必须与代码中一致)
  3. 选择换行符格式(通常选"换行和回车")

常用串口工具

工具平台特点
Arduino IDE 串口监视器全平台简单,集成在 IDE 中
串口调试助手Windows功能丰富,支持多种编码
CoolTerm全平台专业,支持数据记录
PuTTY全平台功能强大,支持多种协议
Serial Monitor (VS Code)全平台PlatformIO 集成

常见问题

1. 串口输出乱码

原因:波特率不匹配

解决:确保串口监视器波特率与代码中 Serial.begin() 一致

2. 无法上传程序

原因:D0/D1 被占用

解决:断开 D0/D1 上的外部连接,上传完成后再连接

3. 数据丢失

原因:缓冲区溢出

解决

  • 提高波特率
  • 减少发送频率
  • 增加接收端处理速度

4. 软串口不稳定

原因:引脚不支持或波特率过高

解决

  • 更换软串口引脚
  • 降低波特率
  • 使用硬件串口(如果可用)

下一步

掌握了串口通信后,我们将学习如何使用各种常用传感器,如温湿度传感器、超声波传感器等。