Arduino Mega2560, GPS, DHT11, and microSD card

Can anyone help me develop the code to collect data from GPS and DHT11 sensor and write to an microSD card? I'd like to collect all the data points every "x" minutes. I'm looking to form a comma separated list within the text file that can be manipulated when inserting the SD card into your computer.

I have all the components working individually but cannot get them to work collectively. I have very little experience in writing code so my skills are minimal.

The components I'm using are:

  1. Arduino Mega2560 R3
  2. DHT11 - three pin temperature and humidity sensor
  3. NEO-6M-V1 GPS module
  4. SenMod Micro SD Card Adapter - Catalex

Desperate for help. Please and thanks.

Post the code, in code tags, from your attempt. If the code compiles but does not "work", describe what the code actually does and how that differs from what it is supposed to do. If it does not compile, post the complete text of the error message(s). Read the how to use this forum-please read sticky to see how to post code and errors.

A schematic of the wiring including all components and their values and power supplies would also be very helpful. Realize that we know nothing of your project except what you tell us. The more that we know the better we can help.

As mentioned previously, I have been able to get each of these components to run individually. Below is the pin outs and code I used for each component. I have not been able to run more than one component at a time. I set up each component and code, verified it worked, disassembled, and moved to the next component. I have made attempts to combine these combine these components but feel I am no where close to developing a valid solution. Like I said, nearly zero arduino programming experience.

DHT11
Pin 1 (Data Pin) - Digital PWM Pin 7 of Arduino Mega
Pin 2 (Vcc Pin) - Power 5V Pin of Arduino Mega
Pin 3 (GND Pin) - Power GND Pin of Arduino Mega

#include <dht.h>

dht DHT;

#define DHT11_PIN 7

void setup(){
  Serial.begin(9600);
}

void loop()
{
  int chk = DHT.read11(DHT11_PIN);
  Serial.print(DHT.temperature);
  Serial.print(",");
  Serial.print(DHT.humidity);
  Serial.println("");
  delay(2000);
}

NEO-6M-V1 GPS module
Pin 1 (Vcc Pin) - Power 3.3V Pin of Arduino Mega
Pin 2 (TX Pin) - Digital PWM Pin 10 of Arduino Mega
Pin 3 (RX Pin) - Digital PWM Pin 11 of Arduino Mega
Pin 4 (GND Pin) - Power GND Pin of Arduino Mega

#include "TinyGPS++.h"
#include "SoftwareSerial.h"
//----------------------------------------------------------

//---------------------------------------------------------

//RX=pin 11, TX=pin 10 , 3.3V=Vcc, GND=GND

SoftwareSerial serial_connection(10, 11); //RX=pin 10, TX=pin 11 
TinyGPSPlus gps;//This is the GPS object that will pretty much do all the grunt work with the NMEA data
void setup()
{
  Serial.begin(9600);//This opens up communications to the Serial monitor in the Arduino IDE
  serial_connection.begin(9600);//This opens up communications to the GPS
  Serial.println("Global Positioning System Launching...");//Just show to the monitor that the sketch has started
}

void loop()
{
  while(serial_connection.available())//While there are characters to come from the GPS
  {
    gps.encode(serial_connection.read());//This feeds the serial NMEA data into the library one char at a time
  }
  if(gps.location.isUpdated())//This will pretty much be fired all the time anyway but will at least reduce it to only after a package of NMEA data comes in
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    Serial.println("Time:");
    Serial.println(gps.time.value()); 
    Serial.println("Satellite Count:"); 
    Serial.println(gps.satellites.value());
    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);
    Serial.println("Speed MPH:");
    Serial.println(gps.speed.mph());
    Serial.println("Altitude Feet:");
    Serial.println(gps.altitude.feet());
    Serial.println("");
  }
}

SenMod Micro SD Card Adapter - Catalex
Pin 1 (GND Pin) - Power GND Pin of Arduino Mega
Pin 2 (Vcc Pin) - Power 5V Pin of Arduino Mega
Pin 3 (MISO Pin) - Digital Pin 50 of Arduino Mega
Pin 4 (MOSI Pin) - Digital Pin 51 of Arduino Mega
Pin 5 (SCK Pin) - Digital Pin 52 of Arduino Mega
Pin 6 (CS Pin) - Digital Pin 53 of Arduino Mega

/*
 *  Arduino SD Card Tutorial Example
 *  
 *  by Dejan Nedelkovski, www.HowToMechatronics.com
 */
#include <SD.h>
#include <SPI.h>
File myFile;
int pinCS = 53; // Pin 10 on Arduino Uno
void setup() {
    
  Serial.begin(9600);
  pinMode(pinCS, OUTPUT);
  
  // SD Card Initialization
  if (SD.begin())
  {
    Serial.println("SD card is ready to use.");
  } else
  {
    Serial.println("SD card initialization failed");
    return;
  }
  
  // Create/Open file 
  myFile = SD.open("test.txt", FILE_WRITE);
  
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.println("Writing to file...");
    // Write to file
    myFile.println("This is a test to see if we can successfully write");
    myFile.println("to a text file and save it on an micro SD card.");
    myFile.println("------------------------------------------------");
    myFile.println("If you see this, it was a success! Congrats!");
    myFile.close(); // close the file
    Serial.println("Done.");
  }
  // if the file didn't open, print an error:
  else {
    Serial.println("error opening test.txt");
  }
  // Reading the file
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("Read:");
    // Reading the whole file
    while (myFile.available()) {
      Serial.write(myFile.read());
   }
    myFile.close();
  }
  else {
    Serial.println("error opening test.txt");
  }
  
}
void loop() {
  // empty
}

NEO-6M-V1 GPS module
Pin 1 (Vcc Pin) - Power 3.3V Pin of Arduino Mega
Pin 2 (TX Pin) - Digital PWM Pin 10 of Arduino Mega
Pin 3 (RX Pin) - Digital PWM Pin 11 of Arduino Mega
Pin 4 (GND Pin) - Power GND Pin of Arduino Mega

That's just plain stupid. The Mega has 4 hardware serial ports, and you choose to use SoftwareSerial instead. For God's sake, why?

You have three pieces of code that work (for some less-than-optimal definition of work), and some code that doesn't work.

Yet you failed to post the code that doesn't do what you want, you failed to describe what that code actually does, and you failed to describe how what it does differs from what you expect.

And yet you expect us to tell you what is wrong. Doesn't seem bloody likely.

I apologize for my lack of knowledge in the matter. I have no idea on how to program these components as I have zero Arduino experience. The programs I listed were simply ones I found online.

I do not have any program code developed to allow these components to work together. That is why I am asking for help. Based on the codes I already posted I am no where near where I need to be.

I can try to explain what I want my code to do:

I'd like to collect the latitude, longitude, date, and time from the GPS module and the humidity and temperature from the DHT sensor every few minutes. I'd like these values to be saved to a text file in the micro SD card so I can use the data elsewhere. Ultimately, I'm looking to create a data logger that will collect latitude, longitude, temperature, and humidity with a date and time stamp. The data will be saved to the sd card.

Thank you for your time in helping me out. I'm sure it is frustrating to help such a novice as myself.

I'm sure it is frustrating to help such a novice as myself.

No. It is fun. But, the novice has to want to learn, and be willing to expend the effort to understand the code that he/she has, and to make some attempt to create the desired program from the building materials at hand.

You've not demonstrated that you are such a novice.

You've got a pile of cement bags, an endless supply of water, lumber to build forms and walls and trusses, all the nails you need, and endless plans available. It is up to you to build the forms, mix the concrete, build the walls, put the roof on, and paint the building.

We'll toss in useful advice as needed, but I'm allergic to actually working.

This tutorial on merging code may be a place to start. And here is another.

Thank you. I will give this a try. I appreciate the quick response times. I wasn't sure how helpful posting to this forum would be but it already seems like great support. I look forward to you coaching me.

Additionally:

You mentioned that I should be using hardware serial ports. I've managed to find that the mega has three serial ports. Serial1 on pins 19 (RX) and 18 (TX), Serial2 on pins 17 (RX) and 16 (TX), Serial3 on pins 15 (RX) and 14 (TX). Should I be using these pin outs for all my devices?

Would you recommend using specific ports for each of my devices? Ensuring that I have each component connected to the Mega correctly is a concern of mine. My programming knowledge is minimal so I'd like to ensure my connection pin outs are not the issue. I think this will get me going in the right direction.

I've managed to find that the mega has three serial ports.

It has FOUR hardware serial ports.

Serial1 on pins 19 (RX) and 18 (TX), Serial2 on pins 17 (RX) and 16 (TX), Serial3 on pins 15 (RX) and 14 (TX).

And Serial, on pins 0 and 1.

Should I be using these pin outs for all my devices?

For all of your serial devices, yes. You only have one - the GPS.

I've made some (little) progress. I've managed to pull temperature and gps data from the DHT11 and GPS module, respectively. However, my code pulls data into the serial monitor too fast for the DHT and for the GPS I think. My serial monitor looks like this:

Date,Time,Latitude,Longitude,Speed,Altitude,Number of Satellites,Temperature,Humidity
....
261018,22001000,40.196266,-84.500762,0.03,305.00,11,-999.00,-999.00 //This line has everything
,22001000,40.196266,-84.500762,0.03,305.00,11,-999.00,-999.00 //Missing date? Why?
,22001000,40.196266,-84.500762,0.03,305.00,11,-999.00,-999.00

The -999 values at the end of each line are from the DHT sensor. I believe the sensor needs 2 seconds between each data sample. I confirmed this my putting in a 2 second delay. The DHT values came in great then but all GPS data went to zero.

Can someone tell me how to slow the rate I can bring all the data into the serial monitor accurately. Ultimately, Id only like to bring data in every 60 seconds.

Sorta stuck...any advice would be great.

#include <dht.h>
dht DHT;
#define DHT11_PIN 7

#include <TinyGPS++.h>
TinyGPSPlus gps;

void setup()
{
  Serial.begin(9600);
  Serial.println("Date,Time,Latitude,Longitude,Speed,Altitude,Number of Satellites,Temperature,Humidity");
  Serial1.begin(9600);
  
}

void loop() // run over and over
{

int chk = DHT.read11(DHT11_PIN);
  
while (Serial1.available() > 0)
  gps.encode(Serial1.read());

  if (gps.date.isUpdated())
  Serial.print(gps.date.value()); // Raw date in DDMMYY format (u32)
  Serial.print(",");
  Serial.print(gps.time.value()); // Raw time in HHMMSSCC format (u32)
  Serial.print(",");
  Serial.print(gps.location.lat(), 6); // Latitude in degrees (double)
  Serial.print(",");
  Serial.print(gps.location.lng(), 6); // Longitude in degrees (double)
  Serial.print(",");
  Serial.print(gps.speed.mps()); // Speed in meters per second (double)
  Serial.print(",");
  Serial.print(gps.altitude.meters());
  Serial.print(",");
  Serial.print(gps.satellites.value()); // Number of satellites in use (u32)
  Serial.print(",");
  Serial.print(DHT.temperature);
  Serial.print(",");
  Serial.println(DHT.humidity);
    
}

However, my code pulls data into the serial monitor too fast for the DHT and for the GPS I think.

Your code PUSHes data to the serial port, where the Serial Monitor PULLs the data.

You can NOT push data too fast.

  Serial.begin(9600);

You can push data too slow, though.

I believe the sensor needs 2 seconds between each data sample.

There are two modes that you can use that sensor in - blocking (needs at least 750 milliseconds) and non-blocking (Hey, I'll call you when I've got the data you need). It is obvious to me which mode to use.

  gps.encode(Serial1.read());

The encode() method returns a value. It is stupid to ignore that value.

I really do not understand what your device is trying to accomplish. Do you REALLY expect to use a GPS and cheap temperature/humidity sensor outdoors to learn anything about variations in temperature and humidity in some local area?

Are you suggesting a need to increase the serial baud rate? Is 9600 to slow for the data I'm attempting to acquire? Is this baud rate issue the reason why my "date data" isn't being printed on each line?

I'll look into this. Thank you. Hopefully, I this will lead to the DHT data not printing as 999 all the time.

There are two modes that you can use that sensor in - blocking (needs at least 750 milliseconds) and non-blocking (Hey, I'll call you when I've got the data you need). It is obvious to me which mode to use.

I really do not understand what your device is trying to accomplish. Do you REALLY expect to use a GPS and cheap temperature/humidity sensor outdoors to learn anything about variations in temperature and humidity in some local area?

I've verified the gps and DHT sensors accuracy and precision individually. Their data collection is satisfactory for my application. Based on this, do you see issue in why I can't approach collecting and recording data this way. (I'm in a situation where I have to work with what I have.) Any advice is greatly appreciated.

Is this baud rate issue the reason why my "date data" isn't being printed on each line?

No. You need to understand the difference between what encode() reports true or false concerning and what gps.date.isUpdated() reports true or false concerning, and when gps.date.isUpdated() discovers that the date is not current.

Hopefully, I this will lead to the DHT data not printing as 999 all the time.

It will have no impact.

You might want to look at what is being stored in chk, and what that value means.

Their data collection is satisfactory for my application.

Which is?

Based on this, do you see issue in why I can't approach collecting and recording data this way.

What way? If the way that you mean is using a very slow sensor, in blocking mode, causing GPS data to be lost, well, then, yes, I see an issue.

You need to understand the difference between what encode() reports true or false concerning and what gps.date.isUpdated() reports true or false concerning, and when gps.date.isUpdated() discovers that the date is not current

You might want to look at what is being stored in chk, and what that value means.

I will look into the above items. Thank you for the direction.

Their data collection is satisfactory for my application.

My application is that I want to create a data logging system for a remote controlled car. As the car travels, I'd like my data logger to generate the Date, Time, Latitude, Longitude, Speed, Altitude, Number of Satellites, Temperature, and Humidity every 60 seconds or so. I'd like to data to be stored on the micro SD card of the data logging system. Then I could remove the card and plug it into my computer for further data analysis. Is this possible with my given components?

Again, thank you for your time and input. Greatly appreciated.

I'd like my data logger to generate the Date, Time, Latitude, Longitude, Speed, Altitude, Number of Satellites, Temperature, and Humidity every 60 seconds or so.

When it takes two seconds to measure the temperature and humidity?

How fast is the car traveling? Do the temperature and humidity values change that much in the area that the car covers?

When it takes two seconds to measure the temperature and humidity?

This 2 second interval is what I personally tested. If I don't include at least a 2 second delay when printing data from the DHT sensor it reports it as 999. I'd like to have the temperature and humidity data pulled at the same time as the rest of the data.

How fast is the car traveling? Do the temperature and humidity values change that much in the area that the car covers?

The car will travel at slow speeds...around 10 m/s. I fully expect the temperate and humidity to show little change throughout the car's travel.

If I don't include at least a 2 second delay when printing data from the DHT sensor it reports it as 999. I'd like to have the temperature and humidity data pulled at the same time as the rest of the data.

As I said in my first reply, there are two modes for getting data from that sensor. One is to simply wait, ignoring GPS data, while the sensor does its thing. The other is to ask the sensor to take a reading and call you when it is done. While waiting for it to call, you can read and parse, if appropriate, GPS data.

You need to change how you use that sensor.

I fully expect the temperate and humidity to show little change throughout the car's travel.

What is the purpose of the project, then? To prove that hypothesis?

What is the purpose of the project, then? To prove that hypothesis?

Yes. The car will be used daily to pick these environmental conditions.

I am still struggling with generating the correct data. I looked into the blocking and non-blocking features of the DHT11 online but did not find anything too helpful.

My program code develops correct data every so often. Can you help me develop some code to pull the data in based on when DHT data is avaiable. I know you mentioed the non-blocking method but I am not having any luck on finding direction on that.

Any direction would be great.

my code as of now is:

//DHT11 SETUP
#include <dht.h>
dht DHT;
#define DHT11_PIN 7

//GPS SETUP
#include <TinyGPS++.h>
TinyGPSPlus gps;

//SD CARD SETUP
#include <SPI.h>
#include <SD.h>

void setup()
{
  Serial.begin(9600);
  Serial.println("Date,Time,Latitude,Longitude,Speed,Altitude,Number of Satellites,Temperature,Humidity");
  Serial1.begin(9600);
  
}

void loop() // run over and over
{

int chk = DHT.read11(DHT11_PIN);
  
while (Serial1.available() > 0)
  gps.encode(Serial1.read());

  //if (gps.date.isUpdated())
  
  Serial.print(gps.date.value()); // Raw date in DDMMYY format (u32)
  Serial.print(",");
  Serial.print(gps.time.value()); // Raw time in HHMMSSCC format (u32)
  Serial.print(",");
  Serial.print(gps.location.lat(), 2); // Latitude in degrees (double)
  Serial.print(",");
  Serial.print(gps.location.lng(), 2); // Longitude in degrees (double)
  Serial.print(",");
  Serial.print(gps.speed.mps()); // Speed in meters per second (double)
  Serial.print(",");
  Serial.print(gps.altitude.meters());
  Serial.print(",");
  Serial.print(gps.satellites.value()); // Number of satellites in use (u32)
  Serial.print(",");
  Serial.print(DHT.temperature);
  Serial.print(",");
  Serial.println(DHT.humidity);
  
}

My data generated looks like this:
21118,21051100,40.20,-84.50,0.03,305.30,9,23.00,62.00 <---- Good data set
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051100,40.20,-84.50,0.03,305.30,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.30,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.30,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00
21118,21051200,40.20,-84.50,0.10,305.10,9,23.00,61.00 <---- Good data set
21118,21051200,40.20,-84.50,0.10,305.10,9,-999.00,-999.00

Can someone explain to me how I would do what PaulS is instructing me to do. I can't seem to find any solutions online.

As I said in my first reply, there are two modes for getting data from that sensor. One is to simply wait, ignoring GPS data, while the sensor does its thing. The other is to ask the sensor to take a reading and call you when it is done.

Also, I'm trying to write all my serial data to an SD card. Any starting advice on that would be great.
The SD card wiring is: MOSI - 51, MOSI - 50, SCK - 52, CS - 53.

I used the Example provided by SD library to make sure the module is working...it does. I need some assistance in how to write to the SD card continuously as I receive new data.

//DHT11 SETUP
#include <dht.h>
dht DHT;
#define DHT11_PIN 7

//GPS SETUP
#include <TinyGPS++.h>
TinyGPSPlus gps;

//SD CARD SETUP
#include <SPI.h>
#include <SD.h>

File myFile;

void setup()
{
  Serial.begin(9600);
  Serial.println("Date,Time,Latitude,Longitude,Speed,Altitude,Number of Satellites,Temperature,Humidity");
  Serial1.begin(9600);

  myFile = SD.open("test.txt", FILE_WRITE);
  //close the file:
   // myFile.close();
   // Serial.println("done.");
  //} else {
    // if the file didn't open, print an error:
  //  Serial.println("error opening test.txt");
 // DO I NEED TO CLOSE FILE TO PRINT TO SD CARD?????
  
}

void loop() // run over and over
{

int chk = DHT.read11(DHT11_PIN);

  
while (Serial1.available() > 0)
  gps.encode(Serial1.read());

  //if (DHT.temperature.isUpdated())
  
  Serial.print(gps.date.value()); // Raw date in DDMMYY format (u32)
  Serial.print(",");
  Serial.print(gps.time.value()); // Raw time in HHMMSSCC format (u32)
  Serial.print(",");
  Serial.print(gps.location.lat(), 2); // Latitude in degrees (double)
  Serial.print(",");
  Serial.print(gps.location.lng(), 2); // Longitude in degrees (double)
  Serial.print(",");
  Serial.print(gps.speed.mps()); // Speed in meters per second (double)
  Serial.print(",");
  Serial.print(gps.altitude.meters());
  Serial.print(",");
  Serial.print(gps.satellites.value()); // Number of satellites in use (u32)
  Serial.print(",");
  Serial.print(DHT.temperature);
  Serial.print(",");
  Serial.println(DHT.humidity);
  delay(2000);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.println(DHT.temperature); //tried this just to see if it would print on card....it didn't
    
  }
}