Why Does Code 1 Not Work with the SD Card, While Code 2 Works Fine on Arduino Uno?

I'm using an Arduino Uno with an SD card, and while Code 2 works fine, Code 1 doesn’t. I’ve checked the wiring, card format, and connections, so I suspect the issue lies in how the SD card is initialized or configured. Differences in SPI setup, the CS pin, or delays between the two codes could be causing the problem. This post looks into why one code works and the other doesn't and offers troubleshooting tips.

Code nr1:

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

#include <SoftwareSerial.h>
SoftwareSerial sim(3, 2);   // RX, TX
int _timeout;
String _buffer;



// Zmienne globalne do przechowywania odczytanych danych z karty SD
String nazwa_wifi = "";
String haslo_wifi = "";
String smtp_host = "";
int smtp_port = 0;
String nadawca_email = "";
String nadawca_haslo = "";
String odbiorca_email = "";
String odbiorca_nrtel = "";
int powiadomienieSMS = 0;
int powiadomienieEMAIL = 0;



const int czujnikAkumlator = A0;      // Czujnik dla odczytu napięcia akumulatora
const int czujnik5V = A0;             // Czujnik dla odczytu napięcia 5V
const int czujnik1Pin = A3;           // Czujnik nr 1
const int czujnik2Pin = A3;           // Czujnik nr 2
const int chipSelect = 4;             // Ustawienie odpowiedniego pinu CS dla karty SD
const int diodaPin = 8;               // Pin wbudowanje diody LED na Arduino
const int laserNPN = 5;               // Pin tranyzsotra ktory wylacza lasery podczas przerwy w pomiarach
const int progAktywacji = 250;        // Prog, poniżej którego uznajemy stan za "ciemno"


bool obecnyStan1 = 0;                 // Stan czujnika 1 (0 - jasno, 1 - ciemno)
bool obecnyStan2 = 0;                 // Stan czujnika 2 (0 - jasno, 1 - ciemno)
bool poprzedniStan1 = 0;              // Poprzedni stan czujnika 1 (0 - jasno, 1 - ciemno)
bool poprzedniStan2 = 0;              // Poprzedni stan czujnika 2 (0 - jasno, 1 - ciemno)
bool akcjaWykonana = 0;               // Zmienna, ktora sledzi, czy akcja została juz wykonana

bool stanAkumulatorPowiadomienie = 0; // Zmienna dla powiadomienia dla akumulatora (0 - brak powiadomienia, 1 - powiadomienie wysłane)
bool stan5VPowiadomienie = 0;         // Zmienna dla powiadomienia dla napięcia 5V (0 - brak powiadomienia, 1 - powiadomienie wysłane)


int napiecieAkumulator = 0;
int napiecie5V = 0;

int licznikAkumulator = 0;            // Licznik odczytów niskiego napięcia akumulatora


const String tekstSMS1 = "Wykryto list";                                      // Wiadomosc tekstowa gdy wykryto list
const String tekstSMS2 = "Poziom Akumlatora spada, konieczne naladownaie.";   // wiadomosc tekstowa gdy poziom akulmlatora spada


int odczytajNapiecie(int pin) {
  // Odczyt napięcia (przykładowy zakres 0-1023 przeliczany na mV)
  int odczytAnalogowy = analogRead(pin);
  int napiecie = map(odczytAnalogowy, 0, 1023, 0, 5000); // Dostosuj do skali napięcia (np. 0-5V)
  return napiecie / 1000; // Zwracaj napięcie w Voltach (zakładając podział przez 1000)
}

void setup() {

  pinMode(czujnikAkumlator, INPUT);
  pinMode(czujnik5V, INPUT);
  pinMode(czujnik1Pin, INPUT);
  pinMode(czujnik2Pin, INPUT);
  pinMode(diodaPin, OUTPUT);
  pinMode(laserNPN, OUTPUT);
  digitalWrite(laserNPN, LOW);


  // Uruchomienie komunikacji szeregowej
  Serial.begin(9600);
  while (!Serial) {
    ; // Czekaj na otwarcie portu szeregowego
  }

  Serial.println("Inicjalizacja karty SD...");

  // Próba inicjalizacji karty SD
  if (!SD.begin(chipSelect)) {
    Serial.println("Nie można zainicjować karty SD! Sprawdź połączenia.");
    while (true); // Zatrzymanie programu w przypadku błędu
  }
  Serial.println("Karta SD zainicjowana.");

  // Otwieranie pliku konfiguracyjnego
  File file = SD.open("config.txt");
  if (!file) {
    Serial.println("Nie udało się otworzyć pliku config.txt!");
    while (true); // Zatrzymanie programu w przypadku błędu
  }

  Serial.println("Odczyt danych z pliku:");

  // Odczytanie danych z pliku linia po linii
  while (file.available()) {
    String line = file.readStringUntil('\n');
    line.trim(); // Usuwanie ewentualnych białych znaków na początku i końcu
    
    if (line.startsWith("nazwa_wifi=")) {
      nazwa_wifi = line.substring(11);
    } else if (line.startsWith("haslo_wifi=")) {
      haslo_wifi = line.substring(11);
    } else if (line.startsWith("smtp_host=")) {
      smtp_host = line.substring(10);
    } else if (line.startsWith("smtp_port=")) {
      smtp_port = line.substring(10).toInt();
    } else if (line.startsWith("nadawca_email=")) {
      nadawca_email = line.substring(14);
    } else if (line.startsWith("nadawca_haslo=")) {
      nadawca_haslo = line.substring(14);
    } else if (line.startsWith("odbiorca_email=")) {
      odbiorca_email = line.substring(15);
    } else if (line.startsWith("odbiorca_nrtel=")) {
      odbiorca_nrtel = line.substring(15);
    } else if (line.startsWith("powiadomienieSMS=")) {
      powiadomienieSMS = line.substring(17).toInt();
    } else if (line.startsWith("powiadomienieEMAIL=")) {
      powiadomienieEMAIL = line.substring(19).toInt();
    }
  }
  file.close();

  Serial.println("\nDane zapisane w zmiennych:");
  Serial.println("SSID Wi-Fi: " + nazwa_wifi);
  Serial.println("Hasło Wi-Fi: " + haslo_wifi);
  Serial.println("Serwer SMTP: " + smtp_host);
  Serial.println("Port SMTP: " + String(smtp_port));
  Serial.println("E-mail nadawcy: " + nadawca_email);
  Serial.println("Hasło nadawcy: " + nadawca_haslo);
  Serial.println("E-mail odbiorcy: " + odbiorca_email);
  Serial.println("Numer telefonu odbiorcy: " + odbiorca_nrtel);
  Serial.println("Powiadomienie SMS: " + String(powiadomienieSMS));
  Serial.println("Powiadomienie EMAIL: " + String(powiadomienieEMAIL));

}



void loop() {
  digitalWrite(laserNPN, HIGH);
  delay(500);

  // Odczyt stanu czujnika 1
  if (analogRead(czujnik1Pin) > progAktywacji) {
    obecnyStan1 = 1;
  } else {
    obecnyStan1 = 0;
  }

  // Odczyt stanu czujnika 2
  if (analogRead(czujnik2Pin) > progAktywacji) {
    obecnyStan2 = 1;
  } else {
    obecnyStan2 = 0;
  }

  // Logika działania na podstawie stanów czujników
  if ((obecnyStan1 == 1 || obecnyStan2 == 1) && akcjaWykonana == 0) {
    wykonajAkcje();
    akcjaWykonana = 1;
  }

  // Jeśli oba czujniki wrociły do stanu 0, resetujemy flage
  if (obecnyStan1 == 0 && obecnyStan2 == 0) {
    akcjaWykonana = 0;
  }

  // Wpisanie stanu czujnikow do konsoli
  Serial.print("Czujnik 1: ");
  Serial.print(obecnyStan1);
  Serial.print(", Czujnik 2: ");
  Serial.println(obecnyStan2);

  // Zapisujemy poprzedni stan czujników
  poprzedniStan1 = obecnyStan1;
  poprzedniStan2 = obecnyStan2;

  delay(500);
  digitalWrite(laserNPN, LOW);
  delay(1000);
}

void wykonajAkcje() {
  digitalWrite(diodaPin, HIGH);
  Serial.println("Akcja zostala wywolana");
  delay(100);
  digitalWrite(diodaPin, LOW);
  wyslijSMS();

}

void wyslijSMS() {
  sim.println("AT+CMGF=1");
  delay(200);
  sim.println("AT+CMGS=\"" + odbiorca_nrtel + "\"\r");
  delay(200);
  sim.println(tekstSMS1);
  delay(100);
  sim.println((char)26);
  delay(200);
  _buffer = _readSerial();
  Serial.println("Zakończono funkcję 2.");
}

String _readSerial() {
  _timeout = 0;
  while  (!sim.available() && _timeout < 12000  )
  {
    delay(13);
    _timeout++;
  }
  if (sim.available()) {
    return sim.readString();
  }
}

Code nr2:

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

// Zmienne globalne do przechowywania odczytanych danych
String nazwa_wifi = "";
String haslo_wifi = "";
String smtp_host = "";
int smtp_port = 0;
String nadawca_email = "";
String nadawca_haslo = "";
String odbiorca_email = "";
String odbiorca_nrtel = "";
int powiadomienieSMS = 0;
int powiadomienieEMAIL = 0;


const int chipSelect = 4; // Ustawienie odpowiedniego pinu CS dla karty SD

void setup() {
  // Uruchomienie komunikacji szeregowej
  Serial.begin(9600);
  while (!Serial) {
    ; // Czekaj na otwarcie portu szeregowego
  }

  Serial.println("Inicjalizacja karty SD...");

  // Próba inicjalizacji karty SD
  if (!SD.begin(chipSelect)) {
    Serial.println("Nie można zainicjować karty SD! Sprawdź połączenia.");
    while (true); // Zatrzymanie programu w przypadku błędu
  }
  Serial.println("Karta SD zainicjowana.");

  // Otwieranie pliku konfiguracyjnego
  File file = SD.open("config.txt");
  if (!file) {
    Serial.println("Nie udało się otworzyć pliku config.txt!");
    while (true); // Zatrzymanie programu w przypadku błędu
  }

  Serial.println("Odczyt danych z pliku:");

  // Odczytanie danych z pliku linia po linii
  while (file.available()) {
    String line = file.readStringUntil('\n');
    line.trim(); // Usuwanie ewentualnych białych znaków na początku i końcu

    // Przypisanie danych do zmiennych na podstawie kluczy
    if (line.startsWith("nazwa_wifi=")) {
      nazwa_wifi = line.substring(11);
    } else if (line.startsWith("haslo_wifi=")) {
      haslo_wifi = line.substring(11);
    } else if (line.startsWith("smtp_host=")) {
      smtp_host = line.substring(10);
    } else if (line.startsWith("smtp_port=")) {
      smtp_port = line.substring(10).toInt();
    } else if (line.startsWith("nadawca_email=")) {
      nadawca_email = line.substring(14);
    } else if (line.startsWith("nadawca_haslo=")) {
      nadawca_haslo = line.substring(14);
    } else if (line.startsWith("odbiorca_email=")) {
      odbiorca_email = line.substring(15);
    } else if (line.startsWith("odbiorca_nrtel=")) {
      odbiorca_nrtel = line.substring(15);
    } else if (line.startsWith("powiadomienieSMS=")) {
      powiadomienieSMS = line.substring(17).toInt();
    } else if (line.startsWith("powiadomienieEMAIL=")) {
      powiadomienieEMAIL = line.substring(19).toInt();
    }
  }
  file.close();

  Serial.println("\nDane zapisane w zmiennych:");
  Serial.println("SSID Wi-Fi: " + nazwa_wifi);
  Serial.println("Hasło Wi-Fi: " + haslo_wifi);
  Serial.println("Serwer SMTP: " + smtp_host);
  Serial.println("Port SMTP: " + String(smtp_port));
  Serial.println("E-mail nadawcy: " + nadawca_email);
  Serial.println("Hasło nadawcy: " + nadawca_haslo);
  Serial.println("E-mail odbiorcy: " + odbiorca_email);
  Serial.println("Numer telefonu odbiorcy: " + odbiorca_nrtel);
  Serial.println("Powiadomienie SMS: " + String(powiadomienieSMS));
  Serial.println("Powiadomienie EMAIL: " + String(powiadomienieEMAIL));
}

void loop() {

}

So what does Code 1 fail to do that Code 2 doesn't?
What's the error?

Are you running both code examples on the same Arduino or different ones? Same SD card/reader or a different one for each code example?

The reason I ask is, because if you are running both code examples on the same hardware and code 2 works, then the connections to the SD card and hardware must be OK.

Yea, on the same Uno R3, error is can't open file config.txt

So is it failing on this message?

Or this one?

Sorry for this polish comments, it is this second one.

In your code 1, try adding a delay after:

delay(400) ;

and before;

Just curious if its a timing issue because in code 1 the MCU also has the overhead of having to ]process SoftwareSerial.

BTW, is this on a UNO R3? When you compile code example 1, how much dynamic memory is used / available?

You are using a few String variables and with the addition of SoftwareSerial in code example 1, I am wondering whether there is simply not enough dynamic memory left to properly initialise the file object once SoftwareSerial and SD have been started..

Here's the updated response:


Thank you for your suggestion! I added the delay(400) as you recommended, but unfortunately, it didn’t resolve the issue on my Arduino Uno R3. The dynamic memory usage on the Uno R3 for code example 1 is around 80%, so it does seem likely that memory constraints were a factor.

To test further, I switched to an Arduino Uno R4 WiFi, and applied your advice. On the Uno R4, the same code works flawlessly, with dynamic memory usage at around 20%. This confirms that the increased memory capacity of the Uno R4 made a significant difference.

Honestly, I would have never thought of this myself—your insight really helped me pinpoint the issue and find a solution. Thank you so much! :blush:

1 Like

No problem. Glad it works on the R4.

At 80% that would indeed leave the dynamic memory space very tight. At some point in the consumption of resources the compiler warns about possible instability, but you have to have the appropriate level of warnings turned on in:

Under File -> Preferences -> Compiler warnings.

The default setting only shows the lowest level of messages, but when running into unexplained difficulty, it is sometimes useful to set that to 'All' which provides a lot more detail.

Anyway, I hope you can now move forward with your project using a board with more memory.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.