Soft SPI for SD card module

I wanted to include a datalogger to my simple brewing controller. I used an arduino UNO together with an LCD keypad shield which unfortunately uses the PINs for SPI.
When checking the forum I figuered there should be a Soft SPI which can be used in such cases but unfortunately I cant get the SD card initialized.
Has someone an idea what is wrong with my code?

code:

/*******************************
 - Start: Grüner Button (ca. 6s betätigen bis Heizen erscheint)
 - Reset: Roter Knopf (ca. 6s betätigen bis Reset erscheint) kann jederzeit betätigt werden und setzt das Programm zurück
 - Temperaturregelung +/- 0.3°C
 - Timer in min bei den Haltezeiten
 
 Maischeprogramm:
 - Heizen auf 50°C
 - Einmaisen 15 min
 - Heizen auf 62°C
 - Maltoserast 60 min
 - Heizen auf 72°C
 - Zuckerrast 15 min
 - Heizen auf 78°C
  
 ******************************/



//Libraries:
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SD.h>
#include <SPI.h>
#include <SoftSPI.h>
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float Celsius = 0;
float Fahrenheit = 0;

// Pin - Definitionen
const int pin_RS = 8;                         // LCD Pin
const int pin_EN = 9;                         // LCD Pin 
const int pin_d4 = 4;                         // LCD Pin
const int pin_d5 = 5;                         // LCD Pin
const int pin_d6 = 6;                         // LCD Pin
const int pin_d7 = 7;                         // LCD Pin
const int pin_BL = 10;                        // LCD Pin
LiquidCrystal lcd( pin_RS,  pin_EN,  pin_d4,  pin_d5,  pin_d6,  pin_d7);
int CS_PIN = A4;                            //Pin für SD Karte
const int RelaisPin = 3;                      //Heizung
int x;                                        //Pin für Taster

SoftSPI mySPI(A1, A2, A3);                     // MOSI,MISO,SCK

File Textdatei;

//Switch Variables:
int state_s1 = 0;
//Intervalle:
long interval1 = 6000; //Intervall Temperaturabfrage Heizung (6s)
long interval2 = 900000; //Intervall Einmaischen (15min) 
long interval3 = 3600000; //Intervall Maltoserast (60min)
long interval4 = 900000; //Intervall Zuckerrast (15min)
long previousMillis2 = 0; //Speicher der letzten Zeit vor umschalten nächsten State
long previousMillis3 = 0; //Speicher der letzten Zeit vor umschalten nächsten State

//Temperaturen:
const int Temp1 = 50; //50
const int Temp2 = 62; //62
const int Temp3 = 72; //72
const int Temp4 = 78; //78

//Temperatur Funktion
void Temp_loop()
{
  int i;
  float tempData[3];
  
  for(i=0; i<3; i++)
  {
    sensors.requestTemperatures();
    tempData[i] = sensors.getTempCByIndex(0);
  }
  Celsius = (tempData[0] + tempData[1] + tempData[2]) / 3;
  //Celsius = sensors.getTempCByIndex(0);
  
  Fahrenheit = sensors.toFahrenheit(Celsius);
  // set the cursor to column 0, line 1
  lcd.setCursor(0, 1);
  lcd.print(Celsius);   
  Serial.println(Celsius); 
  lcd.print("C");
  // Print State
  lcd.setCursor(0, 0);
  switch(state_s1)
  {
    case 0:
      lcd.clear();
      lcd.print("Reset");
      break;
    case 1:
      lcd.print("Start");
      break;
    case 2:
      lcd.print("Heizen auf 50C");
      break;
    case 3:
      lcd.print("Einmaischen  ");
      break;
    case 4:
      lcd.print("Heizen auf 62C");
      break;
    case 5:
      lcd.print("Maltoserast ");
      break;
    case 6:
      lcd.print("Heizen auf 72C");
      break;
    case 7:
      lcd.print("Zuckerrast  ");
      break;
    case 8:
      lcd.print("Heizen auf 78C");
      break;                  
    default: 
      lcd.print("Reset");
      break;
  }
  Serial.println(Celsius);
}

void SPI_loop() 
{
  static uint8_t v = 0;

  Serial.print("Sending value: ");
  Serial.print(v, HEX);
  uint8_t in = mySPI.transfer(v);
  Serial.print(" Got value: ");
  Serial.print(in, HEX);
  Serial.println(v == in ? " PASS" : " FAIL");
  delay(100);
  v++;
}


void button_loop()
{
   x = analogRead (0);
}

// Setup Befehle
void setup()
{
  pinMode (RelaisPin, OUTPUT);
    mySPI.begin();
  pinMode(CS_PIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Debugging is ON");
  lcd.begin(16, 2);
  Serial.println("Initialisiere SD-Karte");   
  if (!SD.begin(A4)) {                                     // Wenn die SD-Karte nicht (!SD.begin) gefunden werden kann, ...
    Serial.println("Initialisierung fehlgeschlagen!");    // ... soll eine Fehlermeldung ausgegeben werden. ....
    return;
  }
  
  Serial.println("Initialisierung abgeschlossen");        // ... Ansonsten soll die Meldung "Initialisierung abgeschlossen." ausgegeben werden.


  Textdatei = SD.open("Ansatz.txt", FILE_WRITE);            // An dieser Stelle wird die Textdatei erstellt. Unsere Textdatei soll "test" heißen und im Format ".txt" (Text) erstellt werden.

}

// State machine Zustäbde
void SM_s1()
{
  unsigned long currentMillis;
  Temp_loop();
  button_loop();
  SPI_loop();

  //State Machine
  switch (state_s1)
  {
    
    case 0: //RESET!
      digitalWrite (RelaisPin, LOW);
      state_s1 = 1;
      break;

    case 1: //Start
      //Warten bis der Schalter aktiviert wird   
      Temp_loop();
      if (x >600 && x < 800)
      {
        Serial.println("State 1, Start"); 
        state_s1 = 2;
      }
      break;

    case 2: //Heizen
      Temp_loop();
      currentMillis = millis();
      digitalWrite (RelaisPin, HIGH);
      Serial.println("State 2, Heizen");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if ((Celsius) - Temp1 > 0)
      {
        previousMillis2 = currentMillis;
        Serial.println("State 3, Einmaischen");
        lcd.clear();
        previousMillis3 = millis();
        state_s1 = 3;
      }
      break;
    
    case 3: //Einmaischen
      Temp_loop();
      
      currentMillis = millis();
      lcd.print (((interval2 + previousMillis3) / 60000)- (currentMillis/60000));
      lcd.print ("m");
      Serial.println("State 3, Einmaischen");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if (Celsius - Temp1 > 0.3)
      {
        digitalWrite (RelaisPin, LOW);
        Serial.println("State 3, Einmaischen Kühlen");
      }
      if (Temp1 - Celsius > 0.3)
      {
        digitalWrite (RelaisPin, HIGH);
        Serial.println("State 3, Einmaischen, Heizen");
      }
      if (currentMillis- previousMillis2 > interval2)
      {
        Serial.println("State 4, Heizen 2");
        lcd.clear();
        state_s1 = 4;
      } 
      break;

    case 4: //Heizen 2
      Temp_loop();
      digitalWrite (RelaisPin, HIGH);
      Serial.println("State 4, Heizen 2");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if (Celsius - Temp2 > 0)
      {
        previousMillis2 = millis();
        Serial.println("State 5, Maltoserast");
        lcd.clear();
        previousMillis3 = millis();
        state_s1 = 5;
      }
      break;
      
    case 5: //Maltoserast
      Temp_loop();
      currentMillis = millis();
      lcd.print (((interval3 + previousMillis3) / 60000)- (currentMillis/60000));
      lcd.print ("m");
      Serial.println("State 5, Maltoserast");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if (Celsius - Temp2 > 0.3)
      {
        digitalWrite (RelaisPin, LOW);
        Serial.println("State 5, Maltoserast Kühlen");
      }
      if (Temp2 - Celsius > 0.3)
      {
        digitalWrite (RelaisPin, HIGH);
        Serial.println("State 5, Maltoserast, Heizen");
      }
      if (currentMillis- previousMillis2 > interval3)
      {
        Serial.println("State 6, Heizen 3");
        lcd.clear();
        state_s1 = 6;
      } 
      break;

    case 6: //Heizen 3
      Temp_loop();
      digitalWrite (RelaisPin, HIGH);
      Serial.println("State 6, Heizen 3");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if (Celsius - Temp3 > 0)
      {
        previousMillis2 = millis();
        Serial.println("State 6, Zuckerrast");
        lcd.clear();
        previousMillis3 = millis();
        state_s1 = 7;
      }
      break;

    case 7: //Zuckerrast
      Temp_loop();
      currentMillis = millis();
      lcd.print (((interval4 + previousMillis3) / 60000)- (currentMillis/60000));
      lcd.print ("m");
      Serial.println("State 7, Zuckerrast");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if (Celsius - Temp3 > 0.3)
      {
        digitalWrite (RelaisPin, LOW);
        Serial.println("State 7, Zuckerrast Kühlen");
      }
      if (Temp3 - Celsius > 0.3)
      {
        digitalWrite (RelaisPin, HIGH);
        Serial.println("State 7, Zuckerrast, Heizen");
      }
      if (currentMillis- previousMillis2 > interval4)
      {
        Serial.println("State 8, Heizen 4");
        lcd.clear();
        state_s1 = 8;
      } 
      break;

    case 8: //Heizen 4
      Temp_loop();
      digitalWrite (RelaisPin, HIGH);
      Serial.println("State 8, Heizen 4");
      if(x < 600)
      {
        state_s1 = 0;
      }
      if (Celsius - Temp4 > 0)
      {
        previousMillis2 = millis();
        Serial.println("Maische Läutern");
        lcd.clear();
        state_s1 = 9;
      }
      break;

    case 9: //Reset
      lcd.clear();
      state_s1 = 0;
      break;
      
    default: //Zurücksetzten
      Serial.println("default");
      digitalWrite (RelaisPin, LOW);
      lcd.clear();
      state_s1 = 0;
      break;
  }
}

void loop()
{
  SM_s1();
}

Your post was MOVED to its current location as it is more suitable.

Could you also take a few moments to Learn How To Use The Forum.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

Your program should work fine.
Uno SPI uses pins 11, 12, 13.
You can use A4 for SD_CS ok.

A4 is safe because you have not used I2C.

David.

Thanks for your feedback, this is exactly the problem. I added a picture of the LCD shield. It blocks Pins 8-13, so I was looking for an option to shift the SPI Pins to A1 - A3.

Please post a link to the Display Shield.

It looks as if it uses pins 4-10 and A0.

Use hardware SPI pins 11, 12, 13 for the SD.
There is no point in trying to use Soft SPI for the SD card. It is fairly complicated to set up.

You can access pins 11, 12, 13 from the ICSP header for your SD card.
And choose A4 for SD_CS.

David.

The shield is from Vellman Article No VMA203.

Ok if the SoftSPI is too complex I may need to look for other solutions.
Thanks so much
Daniel

The LCD shield lets you access the unused pins. Either use Dupont connectors or a 6-way ribbon for the 3x2 header. Or some female header strip.

This is pretty simple. When you get the SD working in hardware SPI, I will show how to do it in software.

David.

Hi @steindan1981 .
2 years ago I made a project using UNO.
I also needed a lot of pins and used an LCD.
As I didn't use the analog pins, I used them for the LCD.
In UNO the analog pins are mapped like this:
A0 is pin 14;
A1 is pin 15;
A2 is pin 16;
A3 is pin 17;
A4 is pin 18;
A5 is pin 19;

you can for example use pins A0 to A5 for RS, EN, d4 to d7, or A0 to A3 as d4 to d7, etc..
So the native SPI pins are free.

RV mineirin

const int pin_RS = 14;                   // LCD Pin
const int pin_EN = 15;                  // LCD Pin 
const int pin_d4 = 16;                  // LCD Pin
const int pin_d5 = 17;                  // LCD Pin
const int pin_d6 = 18;                  // LCD Pin
const int pin_d7 = 19;                  // LCD Pin
const int pin_BL = 4;

The OP has an LCD Keypad Shield. The Shield wiring is fixed. i.e. 4-10 and A0.

The hardware SPI pins are on the 3x2 ICSP header. The OP is using a Uno. So he is going to plug the Shield into the Uno header sockets as Nature intended.

Yes, he could use

SoftSpiDriver<A1, A2, A3> softSpi; //Bit-Bang on the Shield pins SDFat.h v2
#define SD_CS SdSpiConfig(A4, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)

but it involves installing a third party library, editing a library configuration file, and working with a SLOW SD.

Whereas he could just access 11, 12, 13, A4, 3.3V, GND for his SD Card in the regular manner. i.e. every SD project will work out of the box without installing extra third party libraries.

David.

Where? I don't see 11,12,13 called out for use here:

// Pin - Definitionen
const int pin_RS = 8;                         // LCD Pin
const int pin_EN = 9;                         // LCD Pin 
const int pin_d4 = 4;                         // LCD Pin
const int pin_d5 = 5;                         // LCD Pin
const int pin_d6 = 6;                         // LCD Pin
const int pin_d7 = 7;                         // LCD Pin
const int pin_BL = 10;                        // LCD Pin
LiquidCrystal lcd( pin_RS,  pin_EN,  pin_d4,  pin_d5,  pin_d6,  pin_d7);
int CS_PIN = A4;                            //Pin für SD Karte
const int RelaisPin = 3;                      //Heizung
int x;                                        //Pin für Taster

SoftSPI mySPI(A1, A2, A3);                     // MOSI,MISO,SCK

D10 needs to be an output for the Uno to be SPI Master, but any pin can be used for chip select to the SD card.
If the SD module does not have 5V to 3.3V level adapters for chip select, SCK, and MOSI, you will need to add that, and preferably 3.3V to 5V for MISO coming back from the module.

Thanks all, this is so great!
It already took me some time to get the hardware solution to work though :wink:

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