Occasionally, it is necessary to store and recall more data than can fit on a standard Arduino board. With the addition of an SD data logger shield, we can store more data, but still access when needed. In this tutorial, you will sense light intensity through a photo sensor and store the readings every second on an SD card. You will also average the last 5 reading on the SD card and print this average to the serial port. This can be easily adapted to other sensor applications or averaging over a longer window.
Parts List
- Arduino Uno R3 Compatible Development Board
- Data Logger Shield XD-05 For Arduino
- Photo resistor
- SD Card
- Jumper wires
Schematic
Circuit and Board Setup
If your data logger shield did not come with header pins attached, then the first thing you will need to do is solder on those header pins. Once connected, carefully stack the data logger shield on your Arduino Uno (or other R3 compatible board). Wire the circuit according to the schematic, with a pull-up resistor between the 5V pin and the sensor pin (pin 0) and the photo-resistor between the sensor pin and ground.
Code
When working with files on an SD card, it can be challenging to name files and not overwrite previously recorded data. The code snippet below will create a new file each time Arduino restarts and advance the number at the end of the name by 1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <SD.h> //Load SD card library File SDfile; //initialize the SD file char filename[15]; //initializes the filename variable void setup() { pinMode(10, OUTPUT); //Must declare pin 10 as an output and reserve it to keep SD card happy SD.begin(10); //Initializes the SD card reader strcpy(filename, "SDLOG00.TXT"); //Copy string of filename to initialize filename //Increments filename until a value is found that does not exist on the SD card for (uint8_t i = 0; i < 100; i++) { filename[5] = '0' + i/10; //replaces first '0' with the tens value of i filename[6] = '0' + i%10; //replaces second '0' with the "ones" value of i // checks if filename exists on the SD card //if it exist, the for loop iterates to the next value of i //if it does not exist, the for loop is exited and the program continues if (! SD.exists(filename)) { break; } } } |
Once the file is named, there are three parts involved in writing to an SD file. Opening the file, writing to the file, and closing the file. In the following snippet, we open the SDfile, write two values separated by a tab character, and close the file.
1 2 3 4 5 6 7 8 9 10 11 12 |
void loop() { int sensorVoltage; //initializes sensorVoltage as local variable long secs = millis()/1000; //initilizes second count variable sensorVoltage = analogRead(sensorPin); //reads voltage from sensorPin (0) SDfile = SD.open(filename, FILE_WRITE); //Open 'filename' on SD card to write SDfile.print(secs); //writes second count to file SDfile.print('\t'); //writes tab to file SDfile.println(sensorVoltage); //writes voltage reading to sensor SDfile.close(); //closes file on SD card } |
We can also access data and work with information written to the SD card. In this last snippet, we read the last 5 values from the SD card and calculate their average.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
SDfile = SD.open(filename, FILE_READ); //open 'filename' to read in data int l_SDfile = SDfile.size(); //reads size of SD file int sum = 0; //initilizes variable 'sum' for calculating average if(l_SDfile >=35) { //check that SD file is greater than 5 lines (36 bytes) long for(int x = 1; x<=5; x++) { //for loop progresses through last 5 entries in SD file SDfile.seek(l_SDfile - (8*x)); //sets location in SD file to read from SDfile.parseInt(); //parses first int from SD file entry - not used sum = sum + SDfile.parseInt(); //adds previous reading of sensor voltage to sum variable } Serial.print("Average value: "); Serial.print(sum/5); //avarages last 5 voltage readings and prints to serial port } Serial.println(); //ends line in serial SDfile.close(); //closes SD file |
The complete code for this sketch is included below. The frequency of sensor readings can be manipulated by changing the value in the delay() function. You can also change the number of values used in calculating the average by changing the for loop to include more past values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/* Dave Buckler * Project revision date: 11/15/2017 * Hardware: Arduino Uno R3 * Programed: Arduino 1.8.4 * * Reading and writing photo sensor data to an SD Card and * using data from the card to calculate an average reading. */ #include <SD.h> //Load SD card library File SDfile; //initialize the SD file char filename[15]; //initializes the filename variable const int sensorPin = 0; //initializes definition for sensor pin void setup() { Serial.begin(115200); //Turn on serial monitor pinMode(10, OUTPUT); //Must declare pin 10 as an output and reserve it to keep SD card happy SD.begin(10); //Initializes the SD card reader strcpy(filename, "SDLOG00.TXT"); //Copy string of filename to initialize filename //Increments filename until a value is found that does not exist on the SD card for (uint8_t i = 0; i < 100; i++) { filename[5] = '0' + i/10; //replaces first '0' with the tens value of i filename[6] = '0' + i%10; //replaces second '0' with the "ones" value of i // checks if filename exists on the SD card //if it exist, the for loop iterates to the next value of i //if it does not exist, the for loop is exited and the program continues if (! SD.exists(filename)) { break; } } } void loop() { int sensorVoltage; //initializes sensorVoltage as local variable long secs = millis()/1000; //initilizes second count variable sensorVoltage = analogRead(sensorPin); //reads voltage from sensorPin (0) SDfile = SD.open(filename, FILE_WRITE); //Open 'filename' on SD card to write SDfile.print(secs); //writes second count to file SDfile.print('\t'); //writes tab to file SDfile.println(sensorVoltage); //writes voltage reading to sensor SDfile.close(); //closes file on SD card Serial.print(sensorVoltage); //prints last reading to serial port Serial.print('\t'); //prints tab character to serial port SDfile = SD.open(filename, FILE_READ); //open 'filename' to read in data int l_SDfile = SDfile.size(); //reads size of SD file int sum = 0; //initilizes variable 'sum' for calculating average if(l_SDfile >=35) { //check that SD file is greater than 5 lines (36 bytes) long for(int x = 1; x<=5; x++) { //for loop progresses through last 5 entries in SD file SDfile.seek(l_SDfile - (8*x)); //sets location in SD file to read from SDfile.parseInt(); //parses first int from SD file entry - not used sum = sum + SDfile.parseInt(); //adds previous reading of sensor voltage to sum variable } Serial.print("Average value: "); Serial.print(sum/5); //avarages last 5 voltage readings and prints to serial port } Serial.println(); //ends line in serial SDfile.close(); //closes SD file delay(1000); //waits 1 second before proceeding through loop } |
One reply on “Writing and Reading Data to an SD Card”
Thanks for your interesting post on writing/reading to/from SD.
Would appreciate any suggestions you can give for the following project: I use Arduino to read an analog sensor, display the values on TFT and store them as txt file on SD. I would like to play back the txt file from SD and display it on the TFT–in other words to redisplay the initial recording. My attempts so far have failed. I haven’t found any projects that purport to accomplish this goal although it sounds as if it should be simple and something that many people might like to do.