Almost there ! - can someone help with this last bit please ?

Hi,

I'm very much a newbie at this and I've managed to cobble together various bits of example code to almost do what I need (for now!).

Basically, I'm using a DHT22 temp/humidity sensor and want to continually record the time, date, humidity and temperature to an SD card.

I've almost got it working - and I know where the problem lies - it's in that last bit of code that tries to write the semicolon and add the leading zero (i.e. the 'printDigits' routine / whatever it's called) - I can see I'm trying to call that outside of the scope but I don't know how to fix it. My head is thumping - I've been on this all day and need some paracetamol !

Excuse the horrific code - I'm stumbling my way through this and it's a lot harder than I thought it was going to be !

Additionally, if anyone can see a far more efficient way of doing what I'm trying to do, don't be shy ! I'm here to learn :slight_smile:

Many thanks !

#include <SD.h>
#include <Time.h>
#include "DHT.h"

#define DHTPIN 2     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTPIN, DHTTYPE);
const int chipSelect = 4;

void setup() {
  Serial.begin(9600);  
  dht.begin();
  setTime(17,22,0,22,6,13); // set time to hh,mm,ss,dd,mm,yy
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  delay(1000);
 
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    Serial.print(h);
    Serial.print(",");
    Serial.println(t);
  // now send the data to the SD card  
    if (dataFile) {      //if file is able to be opened
      dataFile.print(hour());
      printDigits(minute());
      printDigits(second());
      dataFile.print(minute());
      dataFile.print(" ");
      dataFile.print(day());
      dataFile.print(" ");
      dataFile.print(month());
      dataFile.print(" ");
      dataFile.print(year());
      dataFile.println();
      dataFile.print(h);  //Now follow that with the humidity & temp data
      dataFile.print(",");
      dataFile.println(t);
      dataFile.close();  //and close the file
    }
  }
}

void printDigits(int digits){
  // utility function for clock display: prints preceding colon and leading 0
  dataFile.print(":");
  if(digits < 10)
    dataFile.print('0');
  dataFile.print(digits);
}

You use
</mark> <mark>#include "DTH11.h"</mark> <mark>
instead of
</mark> <mark>#include <DHT11.h></mark> <mark>
.
Did you add the DHT11 files to your project files ? That would be okay.
If you installed those files as a library, you should use the '<' and '>'.

For the outside the scope thing: you are right.
In the function "printDigits()" you can use the parameters and declare variables inside the function. You can also use global variables.
But you can't use "dataFile", since that is declared to be used inside the loop() function only.

The line:

File dataFile = SD.open("datalog.txt", FILE_WRITE);

creates the class "dataFile" on the stack in the "loop()" function.

Two things you can do:

  • Declare the "File dataFile;" global (declare it before the "setup()" function.
  • Or pass the "dataFile" variable via the parameters of the function. I'm not sure but I think I would use a pointer to the File class: void printDigits(int digits, File *pMyFile){

A couple of things I see quickly. You are printing the minute() twice. Once with the printDigits() and you probably left one behind. You also appear to sample the sensor once a second and save each time. That's over 86000 samples a day. I have a similar logging program and I found that every 86 seconds works nice as that's a 1000 samples a day.

Thanks for the replies folks. I've amended the code a little - put the file dataFile; statement at the top so it's a global now (do I still need the original line File dataFile = SD.open("datalog.txt", FILE_WRITE); lower down, or is that something completely different ?

I've removed the extra 'write the minutes' line - but it turns out it wasn't doing anything anyway... my output on the SD card is showing only the hour - no minutes or seconds. Obviously something is wrong with the printDigits function, even though it compiles ok. I can't debug that function myself as I don't really grasp how it works. This C stuff is a *^$! more complicated to understand than the ancient languages I used in my youth (Basic, Pascal and Cobol). Actually, I take it back about Cobol... that was hideous.

Anyway, here's the code now and the wonky output below it ! P.S. - I did try to construct a string of each sample's data and then write the whole string in one go to the SD card as I figured it would be tidier. I couldn't get that to work (I can't concatenate strings with text and integers for love nor money :0), hence the writing of each element at a time. :~

P.P.S - Jimmy60; I'm only using a 1 sec sample rate for testing ! In reality, I'm only after a reading perhaps once every ten minutes.

[code]#include <SD.h>
#include <Time.h>
#include "DHT.h"

#define DHTPIN 2        // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTPIN, DHTTYPE);
const int chipSelect = 4;
File dataFile;

void setup() {
  Serial.begin(9600);  
  dht.begin();
  setTime(20,02,0,22,6,13); // set time to hh,mm,ss,dd,mm,yy
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  delay(2000);
 
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    Serial.print(h);
    Serial.print(",");
    Serial.println(t);
    // now send the data to the SD card  
    if (dataFile) {      //if file is able to be opened
      dataFile.print(hour());
      printDigits(minute());
      printDigits(second());
      dataFile.print(",");
      dataFile.print(day());
      dataFile.print("/");
      dataFile.print(month());
      dataFile.print("/");
      dataFile.print(year());
      dataFile.print(",");
      dataFile.print(h);  //Now follow that with the humidity & temp data
      dataFile.print(",");
      dataFile.println(t);
      dataFile.close();  //and close the file
    }
  }
}

void printDigits(int digits){
  // utility function for clock display: prints preceding colon and leading 0
  dataFile.print(":");
  if(digits < 10)
    dataFile.print('0');
  dataFile.print(digits);
}

[/code]

20,22/6/2013,66.90,20.20
20,22/6/2013,66.80,20.20
20,22/6/2013,66.70,20.20
20,22/6/2013,66.50,20.20
20,22/6/2013,66.50,20.20
20,22/6/2013,66.90,20.20
20,22/6/2013,66.70,20.20
20,22/6/2013,67.10,20.20

You declare the "File" class "dataFile" twice.

Please change this:

File dataFile = SD.open("datalog.txt", FILE_WRITE);

into this:

dataFile = SD.open("datalog.txt", FILE_WRITE);

Now I see that you use the Adafruit libary, GitHub - adafruit/DHT-sensor-library: Arduino library for DHT11, DHT22, etc Temperature & Humidity Sensors

The 'C' language differs from Basic Pascal and Cobol. It is easier to structure code, but it is also possible to create awful compact lines of code.

I'm a little lost to compare your code with the result in the file.
You could make it easier by printing a lot more (just for testing).

dataFile.print("Hour: ");
dataFile.println(hour());
dataFile.print("Minute: ");
printDigits(minute());
datafile.println("");
dataFile.print("Second: ");
printDigits(second());
datafile.println("");
dataFile.print("Humidity: "); 
dataFile.println(h);
dataFile.print("Temperature: ");
dataFile.println(t);

Hi,

I'm not quite sure what I've done, but after adding and removing your amendments, it suddenly seems to work correctly. Initially I was getting nothing at all being written to the card, but then started trying to find out why, adding lines etc, and it just started working ! Either way... it's doing what I want now. Thankyou for your help. The code I'm using that works is as follows:-

#include <SD.h>
#include <Time.h>
#include "DHT.h"

#define DHTPIN 2        // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)

DHT dht(DHTPIN, DHTTYPE);
const int chipSelect = 4;
File dataFile;

void setup() {
  Serial.begin(9600);  
  dht.begin();
  setTime(20,02,0,22,6,13); // set time to hh,mm,ss,dd,mm,yy
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  delay(60000); //delay 1 minute - samples only needed 1 per min.
 
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    dataFile = SD.open("datalog.txt", FILE_WRITE);
    Serial.print(h);
    Serial.print(",");
    Serial.println(t);
    // now send the data to the SD card  
    if (dataFile) {      //if file is able to be opened
      dataFile.print(hour());
      printDigits(minute());
      //printDigits(second());
      dataFile.print(",");
      dataFile.print(day());
      dataFile.print("/");
      dataFile.print(month());
      dataFile.print("/");
      dataFile.print(year());
      dataFile.print(",");
      dataFile.print(h);  //Now follow that with the humidity & temp data
      dataFile.print(",");
      dataFile.println(t);
      dataFile.close();  //and close the file
    }
    else Serial.println("Error writing to SD card");
  }
}

void printDigits(int digits){
  // utility function for clock display: prints preceding colon and leading 0
  dataFile.print(":");
  if(digits < 10)
    dataFile.print('0');
  dataFile.print(digits);
}

Watch how you are sending the separator characters. While in this situation surrounding the comas and semicolons with double quotes works, other applications may lead to odd behavior. You should probably use single quotes simply for the habit.

My simple understanding is if you use double quotes it is interpreted as a C-style string which is an array of char for all the characters you have in the double quotes plus an additional null byte to terminate the string (note the lower-case 's' on the word string as used here). If you use single quotation marks it is a single char byte.

Other than that, congrats getting your sketch to work. :smiley:

True, but this way everything is a string, so it's easy to understand.

// The result of these lines is the same.
dataFile.print(",");  // write a string (but only the ',' is written)
dataFile.print(',');  // write a single character