Students will:
SD cards are another amazing modern technology that usually gets overlooked. A “Micro SD” card is smaller than a dime but can hold billions of words, numbers, or other data. Like USB drives, SSDs, and phone memory, SD cards contain huge numbers of flash memroy cells. These are a special type of transistor that either allows electric current to flow through or blocks current. In the diagram below, current flows from the “IN” wire and across the gap in the N-type silicon, but only when there is no electric charge stored in the lower grey block. The upper grey block is used to add or remove charge, setting the flash memory cell to be off or on.
This either/or behavior can be used to store one binary bit of data. Eight flash memory cells make a byte, and then billions of those groups of eight make up the gigabytes of storage capacity on an SD card. The entire contents of the Normal Public Library could be stored on a single 64 Gb SD card! And in 2025, a micro SD card of this size was available for less than ten dollars. Storing information has never been cheaper or smaller. After this lesson, you can decide whether it is easy as well.
SD cards use a different communication protocol than sensors like the BMP180. Instead of I2C, the protocol is called the Serial Peripheral Interface or SPI (pronounced either as “s-p-i” or “spy”). It uses a few more wires that I2C but can also be much faster, which s handy for writing lots of data to an SD card. Like using I2C, we will make use of existing library code to handle the SPI communication with the SD card.
Open the Arduino IDE and start a new program.
#include "FS.h"
#include "SD.h"
#include "SPI.h"
// Define SPI and set pins for communication
SPIClass spi;
#define CS 4
#define MOSI 5
#define CLK 6
#define MISO 7
void setup() {
Serial.begin(115200); // set up the serial protocol to communicate with laptop
mountSDCard();
delay(1000); // pause to allow all initialization to finish
appendDataToFile("/test.txt","1,2,3,4");
}
If you try to comple this code now, you will get errors. The Arduino IDE does not know what “mountSDCard” or “appendDataToFile” are. That is because they are not built in to the library code. We will add them, telling the computer some specific instructions for each one.
void mountSDCard(){
Serial.println("Mounting SD Card....");
spi.begin(CLK, MISO, MOSI, CS); // init SPI with correct pins
if(!SD.begin(CS, spi)){ // try to communicate with SD card
Serial.println("Card mount failed");
}
int cardSize = SD.cardSize() / (1024 * 1024 * 1024);// find card size in gigbytes
Serial.print("Mounted SD card with size of ");
Serial.print(cardSize);
Serial.println(" Gb");
}
Notice that most of the code is print statements telling us what is going on. This is helpful for when things don’t work correctly. The two lines that actually do the work have the word “begin” in them.
Add this section of code to the very bottom of your program:
void appendDataToFile(const char * filename, const char * data){
File file = SD.open(filename, FILE_APPEND); // try to open the file to append (add on) data
if(!file){ // check file access error
Serial.println("Failed to open file");
}
if(file.println(data)){ // try to actually write the data
Serial.printf("Data written to %s: %s\n",filename, data);
} else { // check file writing error
Serial.println("File write failed");
}
file.close(); // close file to finish up
}
Again, there are some print statements telling us what is going on, but there is more activity in this code section. See if you can figure out what all of the lines are doing.
The SD card reader needs six wires connecting it to the circuit: 3.3V power, ground, CLK, CS, MOSI, and MISO. The purpose of the last four are: - CLK is the clock signal to set the timing for how fast bits should be sent - CS is the chip select signal that turns on the output of the card reader - MOSI carries data from the microcontroller to the card reader - MISO carries data from the card reader to the microconroller Notice that SPI has a separate line for data going in each direction, unlike I2C which can only carry data in one direction at a time. This is one reason why SPI is faster than I2C.
Unplug the microcontroller from power and USB. Do not remove the BMP180 sensor or its wiring. Place the SD card reader onto the breadboard slightly above the microcontroller. Place it so that the six pins are in six different rows of the breadbaord.
Connect a jumper wire from the SD card reader 3.3V pin to the red “power” rail of the breadboard. Also connect the same red power rail to the 3.3V pin on the microcontroller if you have not done so in a previous lesson.
Connect a jumper wire from the SD card reader GND pin to the blue “ground” rail of the breadboard. Also connect the same blue ground rail to the GND pin on the microcontroller if you have not done so in a previous lesson.
The CLK, CS, MOSI, and MISO pins of the card reader connect to pins 4 though 7 of your microcontroller. Look at your code in the Arduino IDE to figure out which pin to connect to which number. The photo below shows one way of neatly connecting these wires. It is okay to use longer wires with some slack, but try to keep your board neat.
Plug the microcontroller into your laptop and upload the code using the right arrow button. After the code has run, unplug the microcontroller, remove the SD card, and insert the SD card into your laptop. Check to see that the file was written correctly.
To complete this lesson, we will add code to repeatedly write data from the BMP180 sensor to the SD card. You will take lines from your working program from Lesson 4 and insert those lines into your SD card program in this lesson.
#include
lines are together, then keep the other groups together.
#include <Arduino.h>
#include <Wire.h>
#include <BMP180.h>
// create a sensor object (085 is not a typo) and set I2C pins for communication
BMP085 bmp;
#define SDA 46
#define SCL 45
setup()
section:
Wire.begin(SDA, SCL); // set up the I2C protocol to communicate with sensors
bmp.begin(); // start communicating with the BMP180 sensor
writeDataToFile("/test3.txt","1,2,3,4");
to the loop()
section and add a delay of about 3 seconds, like this:
void loop() {
appendDataToFile("/test.txt","1,2,3,4");
delay(3000);
}
double tempC =bmp.readTemperature();
Add this line to the top of the loop section. Then add these lines that create a neatly formatted output string:
void loop() {
double tempC = bmp.readTemperature();
char data[10]; // create a character array to hold output
dtostrf(tempC, 0, 2, data); // convert the temp int characters
appendDataToFile("/test.txt",data); // write the data characters to file
delay(3000);
}
Still stuck? With your mentor, take a look at the solution code linked on Github.