top of page
Writer's pictureDario Pittera

Arduino data logger - part 1 (SD card)

During this long winter we needed to buy a dehumidifier for our flat; but was it really working?



So, this time I just wanted to collect some data on the effect of opening the window, turning on the heaters and the humidifier on the level of humidity and temperature in the bedroom.

To do this, I put together a small Arduino project with a DHT22 sensor, a SD module and the LEDs and button of my proto shield.


What we need

  • Arduino Uno

  • DHT22 (or others) temperature and humidity sensor

  • SD module

  • a proto shield (optional)



The wiring




Initially, I was just logging data every minute. Just to test if everything was working was fine, but didn't have a way to insert a flag in my data log to signal an external event, like me opening a window or turning on the dehumidifier. I had to unplug and plug again the USB cable so that a new set of headers would be written into the txt file. Plus, if I'd disconnect the cable while the Arduino was writing the data file (really bad timing), I could have some issue. To try it out was fine, but I decided to use one of the two LEDs on the proto shield to signal me that the Arduino was writing. Then I used a button on the proto shield so that when I would press it, a flag was printed onto the log file, while another LED was lighting up to confirm me I successfully pressed the button.


Let's see the code!


Code


You can find the code below on my GitHub, here👀.


Let's see.. We will start by import the useful libraries and defining some useful variables for the temperature and humidity sensor and for the SD module. Also, we want to make sure the button on the proto shield is interpreted as "pressed" only when we are sure it is indeed pressed, excluding any eventual electrical "noise". We will implement a specific function for that later on.



// libraries for temp sensor
#include <DHT.h>
#include <Adafruit_Sensor.h>

// libraries for SD reader
#include <SPI.h>
#include <SD.h>

// DHT SENSOR: Initialize DHT sensor for normal 16mhz Arduino
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht = DHT(DHTPIN, DHTTYPE);

// SD MODULE: change this to match the CS pin of the SD module
const int chipSelect = 10;

// PUSH BUTTON on the proto board
const int buttonPin = 1;
const int debounceDelay = 10;   // milliseconds to wait until stable

// LEDs on the proto board
const int ledPinWriting = 8;    // proto shield led to signal we are 
                                   writing on the SD card
const int ledPinButton = 7;     // proto shield led 2 pin for button
                                   pressed feedback

// USEFUL VARIABLES

// these will be needed to keep track of the time and decide when to log data and turn on/off the proto shield LEDs

// while still being able to check for the pressed button of the proto shield
unsigned long previousMillis4onoff = 0;     // to keep track of time
long ontime = 59000;                        // led1 on time
long SDwriting = 60000;                     // when to log data on SD
long offtime = 61000;                       // led1 off time

bool on = false;                            // to check if the LED was
                                               on
bool wrote = false;                         // to check if to write or
                                               not
bool flag = false;                          // to signal if the button
                                               was pressed (to signal
                                               an event: open windows,
                                               dehumidifier on, etc.)

File myFile;                                // my log file
int id = 1;                                 // to later increase the ID
                                               on the log file

Now let's write the function to catch the button press only when it is sure we really pressed the button and the signal is not due to some "electrical fluctuation".



// DEBOUNCE FUNCTION to precisely state when the button was pressed
bool debounce(int pin) {
 bool state;
 bool previousState;
 previousState = digitalRead(pin); // store button state
 for (int counter = 0; counter < debounceDelay; counter++) {
    delay(1); // wait for 1 millisecond
    state = digitalRead(pin); // read the pin
 if (state != previousState) {
      counter = 0;           // reset the counter if the state changes
      previousState = state; // and save the current state
    }
  }
  // here when the button state has been stable longer than the 
     debounce period
 return state;
}
 

OK, now let's see the setup function:



void setup() {
    // LEDs on the proto board
    pinMode(ledPinWriting, OUTPUT);
    pinMode(ledPinButton, OUTPUT);

    // PUSH BUTTON on the proto board as an input
    pinMode(buttonPin, INPUT);

    // Begin serial communication at a baud rate of 9600
    Serial.begin(9600);
 
    // Setup DHT sensor
    dht.begin();

    // initialise SD card
    Serial.print("Initializing SD card...");

 if (!SD.begin()) {
      Serial.println("initialization failed!");
 return;
    }
    Serial.println("initialization done.");

    // initialise data file with headers
    myFile = SD.open("data.txt", FILE_WRITE);

    // if the file opened okay, write the headers in it
 if (myFile) {
      Serial.print("Initialising data file...");
      // write the headers in one line comma separated, every time the
         Arduino starts (ID, Temp, Hum, Flag)
      myFile.print("ID");myFile.print(",");myFile.print("Temperature");myFile.print(",");myFile.print("Humidity");myFile.print(",");myFile.println("Flag");
         
      // close the file:
      myFile.close();
      Serial.println("Done, all good!");
    }

OK, now the juicy part, our loop function:


void loop() {

  // READ THE BUTTON by calling the debounce function and turn on or
     off the LED1
 if (debounce(buttonPin)) {
    digitalWrite(ledPinButton, LOW);
  } else {
    digitalWrite(ledPinButton, HIGH);
    flag = true;
  }

 // start milliseconds timer
 unsigned long currentMillis = millis();

 // Read the humidity (in %) from the DHT22 sensor
 float h = dht.readHumidity();
 // Read the temperature (in Celsius) from the DHT22 sensor
 float t = dht.readTemperature();

 // Check if everything's good with the reading from the DHT22:
 if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
 return;
  }

  // ACTION 1: check if the waiting time for the led signalling the writing event passed (ontime), and if it wan't already on turn it on
 if ((currentMillis - previousMillis4onoff >= ontime) && (on == false)) {
    on = true;
    digitalWrite(ledPinWriting, HIGH);
  }

  // ACTION 2: if we didn't log any data yet (bool wrote) after the writing waiting time passed (SDwriting) start writing data
 if ((currentMillis - previousMillis4onoff >= SDwriting) && (wrote == false)) {
    wrote = true;
 
    // write on the txt the temperature and humidity taken from the 
       sensor every minute
    myFile = SD.open("data.txt", FILE_WRITE);

    // if the file opened okay, write to it:
 if (myFile) {
      Serial.println("I'm writing"); // for debug reasons

      // now check if flag == true, that is, if the button was pressed
         to signal an external event
      // if there was an event, write 1 in the "flag" column along with
         the other information in one line
      // else write 0
 if (flag == true) {
           myFile.print(id);myFile.print(",");myFile.print(t);myFile.print(",");myFile.print(h);myFile.print(",");myFile.println(1);
        // debug on serial (you can skip this code)   Serial.print(id);Serial.print(",");Serial.print(t);Serial.print(",");Serial.print(h);Serial.print(",");Serial.println(1);
        // reset the flag boolean
        flag = false;
      } else {     myFile.print(id);myFile.print(",");myFile.print(t);myFile.print(",");myFile.print(h);myFile.print(",");myFile.println(0);
        // debug on serial (again, you can skip it)
Serial.print(id);Serial.print(",");Serial.print(t);Serial.print(",");Serial.print(h);Serial.print(",");Serial.println(0);
      }

      // close the file:
      myFile.close();

      // increase ID
      id++;
    }
  }

  // ACTION 3: if the waiting time to turn the led off is passed (offtime), turn off the led and reset all the boolean
 if ((currentMillis - previousMillis4onoff >= offtime)) {
    //Serial.println("sono nel OFFOFF"); // debug reasons
    digitalWrite(ledPinWriting, LOW);
    // reset the previousMillisonoff variable to count to the next interval for all of the 3 actions (led on, writing, led off)
    previousMillis4onoff = currentMillis; // Remember the time
    // reset the boolean variables for the next action
    wrote = false;
    on = false;
  }
}
  

Basically, now we are always able to check if the button was pressed, while we also have a timer (through the function millis) for the different events to happen. In this case, as you can see from the first block of code, I wait 59 seconds to turn on the LED, then at second 60 I write on my SD, and at second 61 I turn off the LED. In this way, I am sure I don't disconnect my Arduino while it is writing on my SD.


Also, from the block of code above, we can see how I write "0" on the flag column if nothing happens. If instead, the button is pressed, I write "1" on the flag column so that later, when I will have a look at my data, I know when an event happened. For instance, I turn on the heating, I press the button, I get a "1" in the flag column. I press it again when I turn the heating off, I get another "1" in the flag column. This way I can try to correlate my data with my actions. Obviously, I didn't code anything advanced yet to keep track of what type of action I made, but well.. to see the effect of my dehumidifier/heating system on my temperature and humidity levels, it is good enough.


And here a quick line plot of some data collected to try out my device:


OK, not the most beautiful graph, but it will do for a quick check. Humidity is in percentage and temperature in Celsius. The grey vertical lines are my "flags". Well, it seems the dehumidifier is working well :) plus, I get some additional Celsius :) (the second temperature rise is due only to the dehumidifier) two in one! Plus, since for once was not raining, around 9am, also opening the window made the humidity levels to drop.


Next, I ordered a shield with an integrated clock (above I just wrote down the starting time and count 1 minute for each entry).


Comments


bottom of page