通过SPI协议,实现Arduino和esp32的稳定和快速通信。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43034503/article/details/135325219
一、项目描述
Arduino Uno R3没有联网的功能,借助esp32,可以将Arduino获取的信息传输到网络上。
Arduino和esp32能够通过RX/TX、I2C和SPI进行通信。其中,RX/TX用于连接计算机以烧录程序,I2C通常作为传感器接口,SPI很少被使用,因此,本项目使用的是SPI。
SPI(Serial Peripheral Interface,串行外设接口)是一种同步外设接口,可以使单片机以串行方式实现双工通信。SPI的特点如下。
(1)主从架构:SPI通信基于主从架构。在这个架构中,有一个主设备(如Arduino)和一个或多个从设备。主设备控制通信流程,包括时钟信号的生成。
(2)四线连接:SPI通常使用四条线进行通信:MISO(主设备输入,从设备输出)、MOSI(主设备输出,从设备输入)、SCK(时钟线)、SS(从设备选择)。SS线用于选择通信的从设备,因为一个主设备可以连接多个从设备。
(3)全双工通信:SPI支持全双工通信,这意味着数据可以同时双向传输(发送和接收)。
(4)高速:SPI是一种高速通信协议,适用于需要快速数据传输的应用。
(5)灵活:SPI协议的实现在不同的设备间可能有所不同,包括数据位宽、时钟极性和相位配置的不同。
(6)简单:与其他通信协议(如I2C或UART)相比,SPI结构相对简单,易于实现和调试。
本项目旨在使用SPI,将Arduino获取的温度值和湿度值(温湿度传感器DHT11)传输给esp32,作为“数据上网”的前提。
二、硬件连接
如下表所示,esp32和Arduino均具有SPI,只是引脚序号不同。按照下表将相同功能的引脚连接起来,即可完成SPI通信的硬件连接。例如,esp32的MISO在GPIO19引脚,Arduino的MISO在D12引脚,只需要将这两个引脚连接起来即可,其它引脚类推。
Arduino | esp32 | |
SS | D10 | GPIO5 |
MOSI | D11 | GPIO23 |
MISO | D12 | GPIO19 |
SCK | D13 | GPIO18 |
三、软件编程
Arduino和esp32基于两种不同的芯片,但都支持由Arduino IDE上传程序。因此,本项目使用Arduino IDE作为编程软件。
为了平衡Arduino和esp32的工作量,使两个硬件的程序长度不要相差太远,本项目将arduino作为SPI的从设备,将esp32作为SPI的主设备。
首先,新建一个arduino_slave.ino,负责读取温湿度传感器(DHT11)获取的温度值和湿度值,并且以字符的格式发送出去。DHT11库在通过Arduino IDE中的“库管理”进行安装。
#include <DHT11.h>
#include <SPI.h>
DHT11 dht11(2);
String dataToSend;
volatile int index = 0;
void setup() {
// 设置串口波特率
Serial.begin(9600);
// 启动SPI,设置为SPI从设备
pinMode(MISO, OUTPUT);
// 启动SPI的中断例程ISR
SPCR |= _BV(SPE);
SPI.attachInterrupt();
}
ISR(SPI_STC_vect) {
if (index < dataToSend.length()) {
// 发送当前字符,具体的数据处理由主设备实现
SPDR = dataToSend[index++];
} else {
// 发送结束字符
SPDR = 0;
// 重置索引
index = 0;
}
}
void loop() {
// 从DHT11读取温度和湿度
int temperature = dht11.readTemperature();
int humidity = dht11.readHumidity();
if (temperature != DHT11::ERROR_CHECKSUM && temperature != DHT11::ERROR_TIMEOUT && humidity != DHT11::ERROR_CHECKSUM && humidity != DHT11::ERROR_TIMEOUT) {
// 创建带有标志位的字符串
dataToSend = "<Temperature:" + String(temperature) + ",Humidity:" + String(humidity) + ">";
Serial.println(dataToSend);
} else {
// 打印错误信息
dataToSend = "<Error: Sensor Read Failed>";
Serial.println(dataToSend);
}
// 重置索引,准备下一次发送
index = 0;
// 延时
delay(1000);
}

然后,新建一个esp32_master.ino,接收来自Arduino发送过来的字符。
#include <SPI.h>
const int ssPin = 5;
String receivedData;
void setup() {
// 设置串口波特率
Serial.begin(9600);
// 启动SPI,设置为SPI主设备
SPI.begin();
pinMode(ssPin, OUTPUT);
}
void loop() {
// 开始通信
digitalWrite(ssPin, LOW);
// 准备接收数据
receivedData = "";
bool isMessageStarted = false;
char receivedChar = 0;
//
while (true) {
// 接收字符
receivedChar = (char)SPI.transfer(0x00);
// 整合数据,不包括标志位<>
if (receivedChar == '<') {
isMessageStarted = true;
} else if (receivedChar == '>' && isMessageStarted) {
break;
} else if (isMessageStarted) {
receivedData += receivedChar;
}
}
// 结束通信
digitalWrite(ssPin, HIGH);
// 打印接收到的数据
Serial.println(receivedData);
// 延时
delay(1000);
}

在上述两个程序中,发送的数据内容和接收的数据内容一致,“<”是开始标志,“>”是结束标志。之所以采用开始标志和结束标志,是为了保障收发数据的完整性和统一性。
发送的数据内容是:<Temperature:temperature,Humidity:humidity>
接收的数据内容是:<Temperature:temperature,Humidity:humidity>
当运行程序时,可以观察到esp32的串口监视器打印出如下信息。这是因为esp32接收到数据后,丢弃开始标志“<”和结束标志“>”,只保留真正需要的信息。
`Temperature:temperature,Humidity:humidity`
由此,Arduino通过DHT11获取了当前环境的温度值和湿度值,并通过SPI传送给esp32,使Arduino获取的数据可以借助esp32上传到网络。
内容来源:csdn.net
作者昵称:ice小游
原文链接:https://blog.csdn.net/weixin_43034503/article/details/135325219