Arduino间串口通信
一、实验目的(本次实验所涉及并要求掌握的知识点)
a) 了解Arduino间串口通信的相关协议。
Arduino间的串口通信是一种基于串行数据传输的通信方式,主要用于两个Arduino设备或Arduino与其他设备之间的数据交换。
b) 掌握I2C主机从机通讯的连接方式及工作原理。
I2C(Inter-Integrated Circuit)是一种多主多从的同步串行通信协议,广泛应用于低速设备之间的通信。
c) 熟悉Wire库函数的使用。
Wire库是Arduino用于实现I2C通信的标准库,提供了丰富的函数来简化I2C通信的编程。
二、实验内容(设计思路)
设计I2C主机从机通讯实验,主要的功能如下:
a)当主机给从机发送“ON”时,从机点亮LED灯,从机串口监视器显示“ON”,并回送“OK”给主机,主机串口监视器显示从机发来的信息“OK”;
b) 当主机给从机发送“OFF”时,从机熄灭LED灯,从机串口监视器显示“OFF”,并回送“NO”给主机,主机串口监视器显示从机发来的信息“NO”。
可以总结出以下实验要求:
主机功能:
向从机发送控制指令,包括 “ON” 和 “OFF”。
接收从机返回的响应信息(“OK” 或 “NO”),并将其显示在主机的串口监视器上。
从机功能:
接收主机发送的控制指令。
根据接收到的指令控制 LED 灯的亮灭:收到 “ON” 点亮 LED 灯,收到 “OFF” 熄灭 LED 灯。
在从机的串口监视器上显示接收到的指令。
根据接收到的指令向主机回送响应信息:收到 “ON” 回送 “OK”,收到 “OFF” 回送 “NO”。
三、实验环境(本次实验所使用的平台和相关软硬件)
Win10 Arduino软件 UNO
四、实验步骤和调试过程(实验步骤、测试结果分析)
将编写完的主机代码和从机代码分别上传到对应的开发板上。
打开主机和从机的串口监视器,确保波特率都设置为 9600。
在主机的串口监视器中输入 “ON” 或 “OFF” 并按回车键,观察从机的 LED 灯状态变化以及主机和从机串口监视器的输出信息。
代码:
①主机代码:
#include <Wire.h>
void setup() {
Wire.begin(); // 初始化I2C主机
Serial.begin(9600); // 初始化串口通信
}
void loop() {
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n');
command.trim();
if (command == "ON") {
Wire.beginTransmission(8); // 从机地址
Wire.write("ON");
Wire.endTransmission();
Serial.println("Sent: ON");
} else if (command == "OFF") {
Wire.beginTransmission(8); // 从机地址
Wire.write("OFF");
Wire.endTransmission();
Serial.println("Sent: OFF");
}else
{
Serial.println("Enter Error");
// continue;
}
delay(100); // 等待从机发送数据
Wire.requestFrom(8, 2); // 从机地址和请求的字节数
if (Wire.available() == 2) { // 确保返回的字节数正确
char status[3]; // 创建一个字符数组来存储返回的数据
Wire.readBytes(status, 2);
status[2] = '\0'; // 添加字符串终止符
Serial.print("Received:");
Serial.println(status);
} else {
Serial.println("Received: Error");
}
}
}
从机代码:
#include <Wire.h>
int ledPin = 13;
char buffer[4];
void setup() {
Wire.begin(8); // 初始化I2C从机,地址为8
Serial.begin(9600); // 初始化串口通信
pinMode(ledPin, OUTPUT);
}
void loop() {
Wire.onReceive(receiveEvent); // 注册接收事件处理函数
Wire.onRequest(requestEvent); // 注册请求事件处理函数
}
void receiveEvent(int byteCount) {
int i = 0;
while (Wire.available()) {
buffer[i++] = Wire.read();
}
buffer[i] = '\0'; // 添加字符串终止符
if (strcmp(buffer, "ON") == 0) {
digitalWrite(ledPin, HIGH);
Serial.println("ON");
//Wire.write("OK");
Serial.println("OK");
} else if (strcmp(buffer, "OFF") == 0) {
digitalWrite(ledPin, LOW);
Serial.println("OFF");
// Wire.write("NO");
Serial.println("NO");
}
}
void requestEvent() {
// 主机请求数据时,从机发送数据
if (strcmp(buffer, "ON") == 0) {
Wire.write("OK");
} else if (strcmp(buffer, "OFF") == 0) {
Wire.write("NO");
}
}
运行截图:
①模拟仿真图:
②电路连接图:
③当主机输入ON时得到:
当主机输入OFF时得到:
五、实验总结(实验中遇到的问题及解决过程、实验体会和收获)
实验过程中,我不仅掌握了I2C通信的基本原理和实现方法,还深入了解了如何通过I2C总线发送指令,从而精准地控制从机上的LED灯状态。这不仅让我在硬件控制领域的技能得到了提升,也为后续进行更复杂的嵌入式系统设计奠定了坚实的基础。
在实验初期,首先通过查阅相关资料和文档,对I2C通信协议有了初步的认识。随后,我利用Arduino IDE和Wire库,开始着手编写主机与从机的通信代码。在编写代码的过程中,体会到了Arduino编程的灵活性和强大功能,尤其是在处理I2C通信时,Wire库提供了极大的便利。通过巧妙地利用Wire库的beginTransmission、write、endTransmission等函数,我成功地实现了主机向从机发送指令的功能。
与此同时,我还实现了串口通信功能,使得主机和从机之间能够相互反馈信息。这一功能的实现,不仅让我能够实时监控通信状态,还为调试代码提供了极大的帮助。在调试过程中,我通过观察串口监视器上的输出信息,及时发现并解决了许多潜在的问题。
在实验过程中,我还遇到了许多挑战和困难:
硬件连接问题
问题:I2C总线连接不稳定,导致通信失败。
解决:检查SDA和SCL线的连接是否牢固,确保没有短路或断路。
软件设计问题
问题:从机在接收数据时,未能正确处理字符串结束符\0,导致数据解析错误。
解决:在从机接收事件中,增加对字符串结束符的处理逻辑。
串口通信问题
问题:串口通信速率不匹配,导致数据丢失或乱码。
解决:确保主机和从机的串口波特率设置一致,通常为9600。
I2C地址冲突
问题:如果系统中存在多个I2C设备,地址冲突可能导致通信异常。
解决:检查并确保所有I2C设备的地址唯一,必要时通过跳线或软件配置修改地址。
延时处理
问题:在I2C通信过程中,由于处理速度差异,可能需要适当的延时处理。
解决:在发送和接收数据后,加入适当的延时(如delay(100)),以确保数据稳定传输。