admin管理员组

文章数量:1313786

I'm working on a NodeMCU project that uses an nRF24L01, SD card, MPU6050, and BMP280. Individually, both the SD card and nRF24 work fine, but when I plug in the SD card, the nRF24 stops working (doesn't send or receive data).

Hardware Setup: NodeMCU ESP8266 nRF24L01 (CE: D4 (GPIO2), CSN: D8 (DPIO15)) SD card module (CS: D0(GPIO16)) Works Perfectly - MPU6050 & BMP280 (I2C - SDA: D2, SCL: D1) Works Perfectly - Servo on D0 Code Snippet:

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <SD.h>
#include <Servo.h> // Include Servo library
#include <RF24.h>

RF24 radio(2, 15); // CE, CSN pins on NodeMCU

#define BMP_SCK  (13)
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS   (10)
#define APOGEE_THRESHOLD 1.5 // Adjust this threshold as needed

Servo parachuteServo; // Define servo object

// Constants for smoothing
const int numReadings = 10;
float accelXReadings[numReadings];
float accelYReadings[numReadings];
float accelZReadings[numReadings];
float pressureReadings[numReadings];
int readIndex = 0;

float sumAccelX = 0.0;
float sumAccelY = 0.0;
float sumAccelZ = 0.0;
float sumPressure = 0.0;

float averageAccelX = 0.0;
float averageAccelY = 0.0;
float averageAccelZ = 0.0;
float averagePressure = 0.0;

// Function prototypes
void initializeMPU();
void initializeBMP();
void initializeSDCard();
void saveDataToFile(const char *filename, String data);

Adafruit_BMP280 bmp;
Adafruit_MPU6050 mpu;

float initialAltitude = 0.0; // Initial altitude
float initialZAccel = 0.0;   // Initial Z acceleration
unsigned long prevTime = 0;  // Previous time for time difference calculation

bool shakeDetected = true; // Flag to indicate if shake is detected
bool loggingStarted = false; // Flag to indicate if data logging has started
bool chuteDeployed = false;

// Addresses for communication
const byte slaveAddress[5] = {'R','x','A','A','A'};
const byte masterAddress[5] = {'T','X','a','a','a'};

// Initialize the nRF24 radio
char dataToSend[32];  // Increased buffer size for sensor data
char receivedCommand[10] = {0}; // Buffer for received command
bool newData = false;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(10);
  }

  initializeMPU();
  initializeBMP();
  initializeSDCard();

  radio.begin();
  radio.setDataRate(RF24_250KBPS);
  radio.openWritingPipe(slaveAddress);
  radio.openReadingPipe(1, masterAddress);
  radio.setRetries(3, 5);
  radio.startListening();

  Serial.println("Transmitter ready!");

  // Wait for shake detection
  while (!shakeDetected) {
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);

    // Calculate total acceleration magnitude
    float totalAccel = sqrt(pow(a.acceleration.x, 2) + pow(a.acceleration.y, 2) + pow(a.acceleration.z, 2));

    // Check if total acceleration exceeds threshold for shake detection
    if (totalAccel > 12.0) { // Adjust threshold as needed
      shakeDetected = true;
    }

    delay(100); // Adjust delay as needed
  }

  Serial.println("Shake detected!");

  parachuteServo.attach(0); // Attach servo to pin number
  parachuteServo.write(0);
  delay(300);

  // Initialize smoothing arrays
  for (int i = 0; i < numReadings; i++) {
    accelXReadings[i] = 0.0;
    accelYReadings[i] = 0.0;
    accelZReadings[i] = 0.0;
    pressureReadings[i] = 0.0;
  }
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  float accelX = a.acceleration.x;
  float accelY = a.acceleration.y;
  float accelZ = a.acceleration.z;
  float gyroX = g.gyro.x;
  float gyroY = g.gyro.y;
  float gyroZ = g.gyro.z;

  // Update smoothing arrays
  sumAccelX -= accelXReadings[readIndex];
  sumAccelY -= accelYReadings[readIndex];
  sumAccelZ -= accelZReadings[readIndex];
  sumPressure -= pressureReadings[readIndex];

  accelXReadings[readIndex] = accelX;
  accelYReadings[readIndex] = accelY;
  accelZReadings[readIndex] = accelZ;
  pressureReadings[readIndex] = bmp.readPressure(); // Read pressure here

  sumAccelX += accelXReadings[readIndex];
  sumAccelY += accelYReadings[readIndex];
  sumAccelZ += accelZReadings[readIndex];
  sumPressure += pressureReadings[readIndex];

  averageAccelX = sumAccelX / numReadings;
  averageAccelY = sumAccelY / numReadings;
  averageAccelZ = sumAccelZ / numReadings;
  averagePressure = sumPressure / numReadings;

  readIndex = (readIndex + 1) % numReadings;

  float temperature = bmp.readTemperature();

  // Calculate altitude using provided BMP280 library code
  float currentAltitude = bmp.readAltitude(1013.25); /* Adjusted to local forecast! */
  float currentAltitudeFt = currentAltitude * 3.28084; // Convert altitude to feet

  // Calculate relative altitude
  int relativeAltitude = (int)(currentAltitudeFt - initialAltitude); // Convert to integer

  // Calculate vertical speed (Z acceleration)
  unsigned long currentTime = millis();
  float deltaTime = (currentTime - prevTime) / 1000.0; // Convert to seconds
  float currentZAccel = (averageAccelZ - initialZAccel) * 9.81; // Convert from g to m/s^2
  float verticalSpeed = currentZAccel * deltaTime * 3.6; // Convert from m/s to km/h
  float maxAltitude = 0.0;    // Variable to store the maximum altitude
  bool apogeeDetected = false;

  // Update previous time for next iteration
  prevTime = currentTime;

  // Prepare data packet
  char dataToSend[128]; // Buffer large enough to hold full data
  snprintf(dataToSend, sizeof(dataToSend), 
           "AccelX:%.2f, AccelY:%.2f, AccelZ:%.2f, GyroX:%.2f, GyroY:%.2f, GyroZ:%.2f, "
           "Altitude:%d, VSpeed:%.2f", 
           averageAccelX, averageAccelY, averageAccelZ, 
           gyroX, gyroY, gyroZ, 
           relativeAltitude, 
           verticalSpeed);
  
  // Send data in chunks
  sendDataInChunks(dataToSend);

  getData();
  if (newData) {
      executeCommand();
      newData = false;
  }
  checkSerialCommand();

  Serial.println("Data sent: " + String(dataToSend));

  // Print structured data to Serial monitor
  Serial.print("AccelX:");
  Serial.print(accelX);
  Serial.print(", AccelY:");
  Serial.print(accelY);
  Serial.print(", AccelZ:");
  Serial.print(accelZ);
  Serial.print(", GyroX:");
  Serial.print(gyroX);
  Serial.print(", GyroY:");
  Serial.print(gyroY);
  Serial.print(", GyroZ:");
  Serial.print(gyroZ);
  Serial.print(", Altitude:");
  Serial.print(relativeAltitude);
  Serial.print(", VSpeed:");
  Serial.print(verticalSpeed);
  Serial.println("");


  if (accelZ < 0) {
    Serial.println("Negative AccelZ detected! Rotating servo...");
    parachuteServo.write(180); // Rotate servo to 180 degrees
    delay(600); // Allow time for servo to rotate
    parachuteServo.write(0); // Return servo to initial position
    delay(600); // Allow time for servo to rotate back
  }

  delay(100); // Adjust delay as needed

  // Check for serial input and process it
  if (Serial.available() > 0) {
    String command = Serial.readStringUntil('\n'); // Read until newline

    // Check if command is "deploy" or "eject"
    if (command.equals("a") || command.equals("eject")) {
      Serial.println("Chute Deployed!");
      parachuteServo.write(180); // Rotate servo to 180 degrees
      delay(600); // Allow time for servo to rotate
    }

    // Check if command is "deploy" or "eject"
    if (command.equals("initial") || command.equals("b")) {
      Serial.println("Chute Ready!");
      parachuteServo.write(0); // Set to a neutral or initial position
      delay(600); // Allow time for servo to rotate
    }

    // Check if command is "test" or "t"
if (command.equals("test") || command.equals("t")) {
  Serial.println("Testing components...");

  int pos;
  for (pos = 0; pos <= 180; pos += 5) {
    parachuteServo.write(pos);
    delay(15);
  }
  for (pos = 190; pos >= 0; pos -= 1) {
    parachuteServo.write(pos);
    delay(15);
  }
  delay(2000);

  // Test MPU
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  Serial.println("MPU6050 Test:");
  Serial.print("AccelX: "); Serial.print(a.acceleration.x); Serial.print(" ");
  Serial.print("AccelY: "); Serial.print(a.acceleration.y); Serial.print(" ");
  Serial.print("AccelZ: "); Serial.print(a.acceleration.z); Serial.println(" ");
  Serial.print("GyroX: "); Serial.print(g.gyro.x); Serial.print(" ");
  Serial.print("GyroY: "); Serial.print(g.gyro.y); Serial.print(" ");
  Serial.print("GyroZ: "); Serial.print(g.gyro.z); Serial.println(" ");
  Serial.println("MPU6050 Test Complete!");
  delay(2000);

  // Test BMP
  float temperature = bmp.readTemperature();
  float pressure = bmp.readPressure();
  float altitude = bmp.readAltitude(1013.25);
  Serial.println("BMP280 Test:");
  Serial.print("Temperature: "); Serial.print(temperature); Serial.print(" C ");
  Serial.print("Pressure: "); Serial.print(pressure); Serial.print(" Pa ");
  Serial.print("Altitude: "); Serial.print(altitude); Serial.println(" m ");
  Serial.println("BMP280 Test Complete!");
  delay(2000);

  // Test SD Card
  if (SD.begin(16)) {
    Serial.println("SD Card Test: SD card initialized successfully.");
    File testFile = SD.open("testfile.txt", FILE_WRITE);
    if (testFile) {
      testFile.println("SD Card Test Successful!");
      testFile.close();
      Serial.println("SD Card Test: Test file written successfully.");
    } else {
      Serial.println("SD Card Test: Failed to open file for writing.");
    }
  } else {
    Serial.println("SD Card Test: Failed to initialize SD card.");
  }
  delay(2000);
}


    // Check if "start log" command received and logging not started yet
    if (command.equals("start log") && !loggingStarted || command.equals("l") && !loggingStarted) {
      loggingStarted = true;
      Serial.println("Data logging started!");
    }

    // Check if "stop log" command received and logging currently active
    if (command.equals("stop log") && loggingStarted || command.equals("s") && loggingStarted) {
      loggingStarted = false;
      Serial.println("Data logging stopped!");
    }
  }

  // Save sensor data to SD card if logging started
  if (loggingStarted) {
    saveDataToFile("datalogg.csv", String(averageAccelX) + "," + String(averageAccelY) + "," + String(averageAccelZ) + "," +
                   String(gyroX) + "," + String(gyroY) + "," + String(gyroZ) + "," +
                   String(temperature) + "," + String(averagePressure) + "," + String(relativeAltitude) + "," + String(verticalSpeed));
  }

  // Check for apogee detection if logging started
  if (loggingStarted && !apogeeDetected) {
    if (relativeAltitude > maxAltitude) {
      maxAltitude = relativeAltitude; // Update maximum altitude
    } else if ((maxAltitude - relativeAltitude) > APOGEE_THRESHOLD) {
      // Apogee detected
      apogeeDetected = true;

      // Save apogee data to SD card
      saveApogeeData(maxAltitude, currentTime);
    }
  }

  delay(100); // Adjust delay as needed
}

void initializeMPU() {
  if (!mpu.begin()) {
    Serial.println("Failed to initialize MPU6050!");
    while (1);
  }
  Serial.println("MPU6050 initialized.");
}

void initializeBMP() {
  if (!bmp.begin(BMP280_ADDRESS_ALT, BMP280_CHIPID)) {
    Serial.println("Failed to initialize BMP280!");
    while (1);
  }
  Serial.println("BMP280 initialized.");
  initialAltitude = bmp.readAltitude(1013.25); // Set initial altitude
  initialZAccel = 0.0;
}

void initializeSDCard() {
  // Ensure BMP280 is not using the SPI bus
  digitalWrite(BMP_CS, HIGH);

  if (!SD.begin(16)) {
    Serial.println("Failed to initialize SD card!");  
    // while (1);
  }
  Serial.println("SD card initialized.");
}

void sendDataInChunks(const char *data) {
    int dataLength = strlen(data);
    int chunkSize = 32;
    int chunks = (dataLength / chunkSize) + ((dataLength % chunkSize) > 0 ? 1 : 0);

    for (int i = 0; i < chunks; i++) {
        radio.stopListening();
        char chunk[32] = {0};  // Initialize buffer with null characters
        strncpy(chunk, data + (i * chunkSize), chunkSize); // Copy 32 bytes or remaining bytes

        radio.write(chunk, sizeof(chunk));  // Send chunk
        radio.startListening();  // Start listening again
        // delay(10); // Short delay to ensure proper transmission
    }
}

void getData() {
    if (radio.available()) {
        radio.read(&receivedCommand, sizeof(receivedCommand));
        newData = true;
    }
}

void executeCommand() {
    String command = String(receivedCommand);
    command.trim(); // Remove any extra spaces or newlines

    // Check if command is "deploy" or "eject"
    if (command.equals("a") || command.equals("eject")) {
        Serial.println("Chute Deployed!");
        parachuteServo.write(180); // Rotate servo to 180 degrees
        delay(600); // Allow time for servo to rotate
    }
    // Check if command is "initial" or "b"
    else if (command.equals("initial") || command.equals("b")) {
        Serial.println("Chute Ready!");
        parachuteServo.write(0); // Set to a neutral or initial position
        delay(600); // Allow time for servo to rotate
    }
    // Check if command is "test" or "t"
    else if (command.equals("test") || command.equals("t")) {
        Serial.println("Testing components...");

        // Test parachute servo movement
        int pos;
        for (pos = 0; pos <= 180; pos += 5) {
            parachuteServo.write(pos);
            delay(15);
        }
        for (pos = 180; pos >= 0; pos -= 5) { // Adjusted range to start from 180 and decrement by 5
            parachuteServo.write(pos);
            delay(15);
        }
        delay(2000);

        // Test MPU
        sensors_event_t a, g, temp;
        mpu.getEvent(&a, &g, &temp);
        Serial.println("MPU6050 Test:");
        Serial.print("AccelX: "); Serial.print(a.acceleration.x); Serial.print(" ");
        Serial.print("AccelY: "); Serial.print(a.acceleration.y); Serial.print(" ");
        Serial.print("AccelZ: "); Serial.print(a.acceleration.z); Serial.println(" ");
        Serial.print("GyroX: "); Serial.print(g.gyro.x); Serial.print(" ");
        Serial.print("GyroY: "); Serial.print(g.gyro.y); Serial.print(" ");
        Serial.print("GyroZ: "); Serial.print(g.gyro.z); Serial.println(" ");
        Serial.println("MPU6050 Test Complete!");
        delay(2000);

        // Test BMP
        float temperature = bmp.readTemperature();
        float pressure = bmp.readPressure();
        float altitude = bmp.readAltitude(1013.25);
        Serial.println("BMP280 Test:");
        Serial.print("Temperature: "); Serial.print(temperature); Serial.print(" C ");
        Serial.print("Pressure: "); Serial.print(pressure); Serial.print(" Pa ");
        Serial.print("Altitude: "); Serial.print(altitude); Serial.println(" m ");
        Serial.println("BMP280 Test Complete!");
        delay(2000);

        // Test SD Card
        if (SD.begin(16)) {
            Serial.println("SD Card Test: SD card initialized successfully.");
            File testFile = SD.open("testfile.txt", FILE_WRITE);
            if (testFile) {
                testFile.println("SD Card Test Successful!");
                testFile.close();
                Serial.println("SD Card Test: Test file written successfully.");
            } else {
                Serial.println("SD Card Test: Failed to open file for writing.");
            }
        } else {
            Serial.println("SD Card Test: Failed to initialize SD card.");
        }
        delay(2000);
    }
    // Check if "start log" command received and logging not started yet
    else if ((command.equals("start log") || command.equals("l")) && !loggingStarted) {
        loggingStarted = true;
        Serial.println("Data logging started!");
    }
    // Check if "stop log" command received and logging currently active
    else if ((command.equals("stop log") || command.equals("s")) && loggingStarted) {
        loggingStarted = false;
        Serial.println("Data logging stopped!");
    }
    else {
        Serial.println("Unknown command!");
    }

    memset(receivedCommand, 0, sizeof(receivedCommand)); // Clear buffer
}

void checkSerialCommand() {
    if (Serial.available() > 0) {
        String command = Serial.readStringUntil('\n');
        command.trim();
        executeCommandFromSerial(command);
    }
}

void executeCommandFromSerial(String command) {
    // Check if command is "deploy" or "eject"
    if (command.equals("a") || command.equals("eject")) {
        Serial.println("Chute Deployed!");
        parachuteServo.write(180); // Rotate servo to 180 degrees
        delay(600); // Allow time for servo to rotate
    }
    // Check if command is "initial" or "b"
    else if (command.equals("initial") || command.equals("b")) {
        Serial.println("Chute Ready!");
        parachuteServo.write(0); // Set to a neutral or initial position
        delay(600); // Allow time for servo to rotate
    }
    // Check if command is "test" or "t"
    else if (command.equals("test") || command.equals("t")) {
        Serial.println("Testing components...");

        // Test parachute servo movement
        int pos;
        for (pos = 0; pos <= 180; pos += 5) {
            parachuteServo.write(pos);
            delay(15);
        }
        for (pos = 180; pos >= 0; pos -= 5) { // Adjusted range to start from 180 and decrement by 5
            parachuteServo.write(pos);
            delay(15);
        }
        delay(2000);

        // Test MPU
        sensors_event_t a, g, temp;
        mpu.getEvent(&a, &g, &temp);
        Serial.println("MPU6050 Test:");
        Serial.print("AccelX: "); Serial.print(a.acceleration.x); Serial.print(" ");
        Serial.print("AccelY: "); Serial.print(a.acceleration.y); Serial.print(" ");
        Serial.print("AccelZ: "); Serial.print(a.acceleration.z); Serial.println(" ");
        Serial.print("GyroX: "); Serial.print(g.gyro.x); Serial.print(" ");
        Serial.print("GyroY: "); Serial.print(g.gyro.y); Serial.print(" ");
        Serial.print("GyroZ: "); Serial.print(g.gyro.z); Serial.println(" ");
        Serial.println("MPU6050 Test Complete!");
        delay(2000);

        // Test BMP
        float temperature = bmp.readTemperature();
        float pressure = bmp.readPressure();
        float altitude = bmp.readAltitude(1013.25);
        Serial.println("BMP280 Test:");
        Serial.print("Temperature: "); Serial.print(temperature); Serial.print(" C ");
        Serial.print("Pressure: "); Serial.print(pressure); Serial.print(" Pa ");
        Serial.print("Altitude: "); Serial.print(altitude); Serial.println(" m ");
        Serial.println("BMP280 Test Complete!");
        delay(2000);

        // Test SD Card
        if (SD.begin(16)) {
            Serial.println("SD Card Test: SD card initialized successfully.");
            File testFile = SD.open("testfile.txt", FILE_WRITE);
            if (testFile) {
                testFile.println("SD Card Test Successful!");
                testFile.close();
                Serial.println("SD Card Test: Test file written successfully.");
            } else {
                Serial.println("SD Card Test: Failed to open file for writing.");
            }
        } else {
            Serial.println("SD Card Test: Failed to initialize SD card.");
        }
        delay(2000);
    }
    // Check if "start log" command received and logging not started yet
    else if ((command.equals("start log") || command.equals("l")) && !loggingStarted) {
        loggingStarted = true;
        Serial.println("Data logging started!");
    }
    // Check if "stop log" command received and logging currently active
    else if ((command.equals("stop log") || command.equals("s")) && loggingStarted) {
        loggingStarted = false;
        Serial.println("Data logging stopped!");
    }
    else {
        Serial.println("Unknown command!");
    }
}

void saveDataToFile(const char *filename, String data) {
  Serial.print("Attempting to open file: ");
  Serial.println(filename);

  File file = SD.open(filename, FILE_WRITE);
  if (file) {
    file.println(data);
    file.close();
    Serial.println("Data saved to file.");
  } else {
    Serial.println("Failed to open file for writing.");
  }
}

void saveApogeeData(float maxAltitude, unsigned long apogeeTime) {
  Serial.println("Attempting to save apogee data...");
  File file = SD.open("apogeee.csv", FILE_WRITE);
  if (file) {
    file.print("MaxAltitude: ");
    file.print(maxAltitude);
    file.print(" ft, Time: ");
    file.println(apogeeTime);
    file.close();
    Serial.println("Apogee data saved.");
  } else {
    Serial.println("Failed to open file for writing apogee data.");
  }
}

String getDataString() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  float accelX = a.acceleration.x;
  float accelY = a.acceleration.y;
  float accelZ = a.acceleration.z;
  float gyroX = g.gyro.x;
  float gyroY = g.gyro.y;
  float gyroZ = g.gyro.z;
  float pressure = bmp.readPressure();
  float temperature = bmp.readTemperature();
  float currentAltitude = bmp.readAltitude(1013.25);
  float currentAltitudeFt = currentAltitude * 3.28084;
  int relativeAltitude = (int)(currentAltitudeFt - initialAltitude); // Convert to integer
  unsigned long currentTime = millis();
  float deltaTime = (currentTime - prevTime) / 1000.0;
  float currentZAccel = (accelZ - initialZAccel) * 9.81;
  float verticalSpeed = currentZAccel * deltaTime * 3.6;

  // Prepare data packet
  String dataPacket = String(accelX) + "," + String(accelY) + "," + String(accelZ) + "," +
                     String(gyroX) + "," + String(gyroY) + "," + String(gyroZ) + "," +
                     String(relativeAltitude) + "," + String(verticalSpeed);

  return dataPacket;
}

Issue: SD card and nRF24 work fine separately. When SD is plugged in, nRF24 stops working (doesn't send or receive data). No errors, just no radio communication.

Using different CS pins → SD (D10), nRF (D15) Changing SPI speeds → SD.begin(10, SPI_HALF_SPEED); Checking power supply → SD and nRF24 get 3.3V from NodeMCU Adding decoupling capacitors (330µF) to nRF24

本文标签: cnRF24 Stops Working When SD Card is Plugged In (NodeMCURF24SDMPU6050BMP280)Stack Overflow