Issue to save data on a SD card using an Arduino Nano 33 BLE without opening up serial monitor

Hi,

For my project, I want to send data (height and RPM) from two Arduino Nano 33 BLEs (peripherals) to another Arduino Nano 33 BLE (central) and save the data on a SD card without opening up their serial monitors. I could able to save data by opening up the serial monitors of all three boards. However, when I commented all serial monitor lines in the codes (below), I could see the Yellow light on the two peripheral boards is ON (sending data), but the data was not saved on the SD card attached to the central board.
How can I solve this issue?
Thank you for your help in Advance.

Height sensor code

#include <ArduinoBLE.h>

BLEService HeightRPMService("170C");

BLEFloatCharacteristic HeightRPMChar("2A57",  // standard 16-bit characteristic UUID
   BLERead | BLENotify | BLEBroadcast); // remote clients will be able to get notifications if this characteristic changes

int noPin1 = 4;
int buttonState1 = 0;
int noPin2 = 5; 
int buttonState2 = 0;
int noPin3 = 6;
int buttonState3 = 0;
long previousMillis = 0;  
int OldHeightRPM=0;
String myString;
float Height_Interval=0.5; 


void setup() {
//  Serial.begin(9600);    
pinMode(noPin1,INPUT_PULLUP);
pinMode(noPin2,INPUT_PULLUP);
pinMode(noPin3,INPUT_PULLUP);
  
//  while (!Serial);

  pinMode(LED_BUILTIN, OUTPUT); 

  // begin initialization
  if (!BLE.begin()) {
//    Serial.println("starting BLE failed!");

    while (1);
  }

  BLE.setLocalName("HeightRPMMonitor");
  BLE.setAdvertisedService(HeightRPMService); 
  HeightRPMService.addCharacteristic(HeightRPMChar); 
  BLE.addService(HeightRPMService); 
  HeightRPMChar.writeValue(OldHeightRPM);

  
  BLE.advertise();
//  Serial.println("Bluetooth device active, waiting for connections...");
}


void loop() {
  
  BLEDevice central = BLE.central();

  if (central) {
//    Serial.print("Connected to central: ");
//    Serial.println(central.address());
    digitalWrite(LED_BUILTIN, HIGH);

    while (central.connected()) {
      long currentMillis = millis();

      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
       updateHeight();
    }
    }
    digitalWrite(LED_BUILTIN, LOW);
//    Serial.print("Disconnected from central: ");
//    Serial.println(central.address());
  }
}



void updateHeight() {
  delay(1000); 
  buttonState1 = digitalRead(noPin1);
  buttonState2 = digitalRead(noPin2);
  buttonState3 = digitalRead(noPin3);
  int Deciaml=(buttonState1*1)+(buttonState2*2)+(buttonState3*4);//convert binary values to decimal
  float Height = Deciaml*Height_Interval;//Height in inch

//      Serial.print("Height: "); 
//      Serial.print(Height);
//      Serial.println(" in");
      HeightRPMChar.writeValue(Height);

}

RPM sensor code

#include <ArduinoBLE.h>

BLEService HeightRPMService("170C");

BLEFloatCharacteristic HeightRPMChar("2A57",  // standard 16-bit characteristic UUID
    BLERead | BLENotify| BLEBroadcast); // remote clients will be able to get notifications if this characteristic changes

int sensor = 2; 
volatile byte counts;
unsigned int rpm;
unsigned long previoustime;
const byte interruptPin = 2;
long previousMillis = 0;  
int OldHeightRPM=0;


void count_function()
{
  counts++;         
}

void setup() {
//  Serial.begin(9600);    
  
  
  attachInterrupt(digitalPinToInterrupt(interruptPin), count_function, RISING); 
  pinMode(sensor, INPUT); 
  counts = 0; 
  rpm = 0;   
  previoustime = 0;
  
//  while (!Serial);

  pinMode(LED_BUILTIN, OUTPUT); 

  if (!BLE.begin()) {
//    Serial.println("starting BLE failed!");

    while (1);
  }

  BLE.setLocalName("HeightRPMMonitor");
  BLE.setAdvertisedService(HeightRPMService);
  HeightRPMService.addCharacteristic(HeightRPMChar); 
  BLE.addService(HeightRPMService); 
  HeightRPMChar.writeValue(OldHeightRPM); 

  BLE.advertise();

//  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  
  BLEDevice central = BLE.central();

  if (central) {
//    Serial.print("Connected to central: ");
//    Serial.println(central.address());

    digitalWrite(LED_BUILTIN, HIGH);

    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
       updateRPM();
    }
    }
    digitalWrite(LED_BUILTIN, LOW);
//    Serial.print("Disconnected from central: ");
//    Serial.println(central.address());
  }
}



void updateRPM() {

      delay(1000);
      noInterrupts();
      float rpm= (counts * 60000) / (millis() - previoustime); 
      previoustime = millis(); 
      counts = 0; 
      interrupts();

//      Serial.print("RPM: "); 
//      Serial.println(rpm);
      HeightRPMChar.writeValue(rpm);
}

Central board code:

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

#define BLE_UUID_HEIGHTRPM_SERVICE                  "170C"
#define BLE_UUID_HEIGHTRPM_LEVEL                    "2A57"

#define BLE_MAX_PERIPHERALS 2
#define BLE_SCAN_INTERVALL 10000

BLEDevice peripherals[BLE_MAX_PERIPHERALS];
BLECharacteristic HeightRPMLevelCharacteristics[BLE_MAX_PERIPHERALS];
int peripheralsConnected = 0;

const int BLE_LED_PIN = LED_BUILTIN;
const int BLE_SCAN_LED_PIN = LED_BUILTIN;

File myFile;
int pinCS = 10; 


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

  pinMode(pinCS, OUTPUT);
  
//  while ( !Serial );

  pinMode( BLE_SCAN_LED_PIN, OUTPUT );

  BLE.begin();

  digitalWrite( BLE_SCAN_LED_PIN, HIGH );
  BLE.scanForUuid( BLE_UUID_HEIGHTRPM_SERVICE );

  int peripheralCounter = 0;
  unsigned long startMillis = millis();
  while ( millis() - startMillis < BLE_SCAN_INTERVALL && peripheralCounter < BLE_MAX_PERIPHERALS )
  {
    BLEDevice peripheral = BLE.available();

    if ( peripheral )
    {
      if ( peripheral.localName() == "HeightRPMMonitor" )
      {
        boolean peripheralAlreadyFound = false;
        for ( int i = 0; i < peripheralCounter; i++ )
        {
          if ( peripheral.address() == peripherals[i].address() )
          {
            peripheralAlreadyFound = true;
          }
        }
        if ( !peripheralAlreadyFound )
        {
          peripherals[peripheralCounter] = peripheral;
          peripheralCounter++;
        }
      }
    }
  }

  BLE.stopScan();
  digitalWrite( BLE_SCAN_LED_PIN, LOW );

  for ( int i = 0; i < peripheralCounter; i++ )
  {
    peripherals[i].connect();
    peripherals[i].discoverAttributes();
    BLECharacteristic HeightRPMLevelCharacteristic = peripherals[i].characteristic( BLE_UUID_HEIGHTRPM_LEVEL );
    if ( HeightRPMLevelCharacteristic )
    {
      HeightRPMLevelCharacteristics[i] = HeightRPMLevelCharacteristic;
      HeightRPMLevelCharacteristics[i].subscribe();
    }
  }
  peripheralsConnected = peripheralCounter;
}

void loop()
{

  myFile = SD.open("test.txt", FILE_WRITE);
  float HeightRPMLevels[BLE_MAX_PERIPHERALS];
  bool newDataPrint = false;
  for ( int i = 0; i < peripheralsConnected; i++ )
  {
    if ( HeightRPMLevelCharacteristics[i].valueUpdated() )
    {
      newDataPrint = true;
      float HeightRPMLevel;
      HeightRPMLevelCharacteristics[i].readValue( &HeightRPMLevel,4 );
      HeightRPMLevels[i] = HeightRPMLevel;
    }
  }
  
  if ( newDataPrint )
  {
    for ( int i = 0; i < peripheralsConnected; i++ )
    {
      delay(1000); 
//      Serial.print( HeightRPMLevels[i] );
//      Serial.print( "," );
     
     if (myFile) { 
        myFile.print(HeightRPMLevels[i]); 
        myFile.print( "," ); 
    }
    }
  myFile.print( "\n" );
//  Serial.print( "\n" );   
  }
  myFile.close(); // close the file
}

Did this unit actually "close" the SD file before it ended? If not, the result you have is the normal, expected, results.

Hi Paul_KD7HB,

Thank you for your prompt reply. I think the unit can close the SD card when I am using serial monitor lines in the codes because the data is saved on the SD card. Since, I am using the same code to save data (without serial monitor), I think the unit should be able to repeat the saving process and close the SD card. What do you think? How can I check if the SD card is actually closed by the unit?

The certain way is the condition you explained. It was not closed, so the directory entry showed it was never updated with the new length of the data file.
If you still have access to the IDE while it is running, you can print some message after the file close.
But, what code do you have to close the file and are you sure it is being executed?

Paul_KD7HB,

As you suggested, I modified the code such that it prints "File was closed!" and I can see this line is printed in the serial monitor with 1 second interval.

Modified code

  myFile.close(); // close the file
  Serial.println( "File was closed!" );

Actually, I am using myFile.close(); to close the file. As I said before, since the code works to save data with serial monitor, I guess the code should be executed correctly to close the file.