You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32/ESP8266双SPI配置问题:RFID与SD卡无法同时工作

问题描述

我正在实现读取RFID标签并将数据保存到SD卡的功能,SD卡连接到HSPI总线,RFID连接到VSPI总线。单独运行RFID代码时功能正常,但同时运行两者时SD卡无法工作;修改为SD.begin(cs_pin, HSPISD)后SD卡恢复工作,但RFID又无法正常运行。需要在ESP32和ESP8266上解决该问题。

ESP32引脚配置

RFID_MISO = G19
RFID_MOSI = G23
RFID_SCK = G18
RFID_CS = G5

SD_MISO = G12
SD_MOSI = G13
SD_SCK = G14
SD_CS = G15

测试代码

#include <SPI.h>
#include <SD.h>
#include <MFRC522.h>

File myFile;
const int CS = 15;

constexpr uint8_t RST_PIN = 22;
constexpr uint8_t SS_PIN = 5;
String tag;
SPIClass VSPIID(VSPI);
SPIClass HSPISD(HSPI);
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;

void WriteFile(const char * path, const char * message){
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open(path, FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.printf("Writing to %s ", path);
    myFile.println(message);
    myFile.close(); // close the file:
    Serial.println("completed.");
  } 
  // if the file didn't open, print an error:
  else {
    Serial.println("error opening file ");
    Serial.println(path);
  }
}

void ReadFile(const char * path){
  // open the file for reading:
  myFile = SD.open(path);
  if (myFile) {
     Serial.printf("Reading file from %s\n", path);
     // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close(); // close the file:
  } 
  else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  digitalWrite(CS, HIGH);    //  DESELECT (high) SD Card SPI
  SD.end();
}

void setup() {
  Serial.begin(115200);
  pinMode(SS_PIN, OUTPUT);
  pinMode(CS, OUTPUT);
  VSPIID.begin();
  HSPISD.begin();
  // pinMode(vspi->pinSS(), OUTPUT); //VSPI SS
  // pinMode(hspi->pinSS(), OUTPUT); //HSPI SS
  if (!SD.begin(CS, HSPISD)) {
    Serial.println("initialization failed!");
  }
  Serial.println("initialization done.");
  WriteFile("/test.txt", "ElectronicWings.com");
  ReadFile("/test.txt");
  rfid.PCD_Init();
  Serial.println(digitalRead(SS_PIN));
  Serial.println(digitalRead(CS));
  digitalWrite(CS, HIGH);
  digitalWrite(SS_PIN, LOW);
}

void loop() {
  if (rfid.PICC_IsNewCardPresent()){
    if (rfid.PICC_ReadCardSerial()) {
      for (byte i = 0; i < 4; i++) {
        tag += rfid.uid.uidByte[i];
      }
      rfid.PICC_HaltA();
      rfid.PCD_StopCrypto1();
      Serial.println(tag);
      tag = "";
      // if (digitalRead(D3) == LOW){
      //   while (true) {
      //     delay(100);
      //     if (digitalRead(D3) == HIGH)
      //         break;
      //   }

      // }
    }
  }
}
解决方案

针对ESP32的修复

问题核心是MFRC522库默认使用系统默认SPI总线,你手动创建了VSPI实例但未传递给RFID对象,导致总线冲突;同时手动控制片选引脚的逻辑干扰了库的正常操作。

修改要点:

  1. 给RFID绑定自定义VSPI总线:替换原RFID实例化代码,将自定义VSPI实例传入
    MFRC522 rfid(SS_PIN, RST_PIN, &VSPIID);
    
  2. 显式初始化SPI总线引脚:避免总线引脚复用冲突,初始化时指定对应引脚
    VSPIID.begin(18, 19, 23, SS_PIN); // VSPI: SCK=G18, MISO=G19, MOSI=G23, CS=G5
    HSPISD.begin(14, 12, 13, CS);    // HSPI: SCK=G14, MISO=G12, MOSI=G13, CS=G15
    
  3. 移除手动拉低RFID片选的代码:片选逻辑由MFRC522库自动处理,手动拉低会导致设备一直被选中,干扰总线
  4. 修复SD卡操作逻辑:移除ReadFile()中的SD.end(),仅在操作后拉高片选即可,否则后续使用SD卡需要重新初始化

修改后的核心代码片段:

// 替换RFID实例化
MFRC522 rfid(SS_PIN, RST_PIN, &VSPIID);

// 修改ReadFile函数
void ReadFile(const char * path){
  myFile = SD.open(path);
  if (myFile) {
     Serial.printf("Reading file from %s\n", path);
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    myFile.close();
  } 
  else {
    Serial.println("error opening test.txt");
  }
  digitalWrite(CS, HIGH); // 仅拉高片选,不调用SD.end()
}

// 修改setup函数
void setup() {
  Serial.begin(115200);
  pinMode(SS_PIN, OUTPUT);
  pinMode(CS, OUTPUT);
  
  // 显式初始化两个SPI总线
  VSPIID.begin(18, 19, 23, SS_PIN);
  HSPISD.begin(14, 12, 13, CS);
  
  if (!SD.begin(CS, HSPISD)) {
    Serial.println("SD卡初始化失败!");
  }
  Serial.println("SD卡初始化完成.");
  WriteFile("/test.txt", "ElectronicWings.com");
  ReadFile("/test.txt");
  
  // 初始化RFID
  rfid.PCD_Init();
  
  // 确保两个设备片选都处于未选中状态
  digitalWrite(CS, HIGH);
  digitalWrite(SS_PIN, HIGH);
}

针对ESP8266的修复

ESP8266只有一组硬件SPI总线,无法像ESP32那样拆分VSPI/HSPI,因此需要用软件模拟SPI给其中一个设备使用,避免总线冲突(建议SD卡用硬件SPI以保证读写速度)。

修改要点:

  1. 引入SoftwareSPI库,为RFID创建软件SPI实例
  2. 将RFID绑定到软件SPI总线,SD卡保留硬件SPI

示例代码片段:

#include <SPI.h>
#include <SD.h>
#include <MFRC522.h>
#include <SoftwareSPI.h>

// SD卡硬件SPI引脚
const int SD_CS = 15;
// RFID软件SPI引脚
constexpr uint8_t RFID_RST = 22;
constexpr uint8_t RFID_CS = 5;
constexpr uint8_t RFID_SCK = 18;
constexpr uint8_t RFID_MISO = 19;
constexpr uint8_t RFID_MOSI = 23;

// 创建软件SPI实例
SoftwareSPI rfidSpi(RFID_SCK, RFID_MOSI, RFID_MISO);
// 将RFID绑定到软件SPI
MFRC522 rfid(RFID_CS, RFID_RST, &rfidSpi);

void setup() {
  Serial.begin(115200);
  
  // 初始化SD卡(硬件SPI)
  if (!SD.begin(SD_CS)) {
    Serial.println("SD卡初始化失败!");
  }
  Serial.println("SD卡初始化完成.");
  
  // 初始化RFID软件SPI
  rfidSpi.begin();
  rfid.PCD_Init();
}

内容的提问来源于stack exchange,提问作者LoNE WoLvES

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:22:14