[SOLVED]Logging multiple temp sensors questions(step by step)

Modifying this multiple sensors onewire sketch :
http://www.arduino.cc/playground/Learning/OneWire
I would like to log 4 sensors (later write to SD card and send to the web).
The best would be for the logfile later the lines look like :
"temp1,temp2,temp3,temp4,date,time" - date and time will be here later if this code will be fine.

Now int the code sprintf() looks like:

sprintf(buf, "%d:%c%d.%d\337C     ",sensor,SignBit ? '-' : '+', Whole, Fract < 10 ? 0 : Fract);
Serial.print(buf);

Please help how to modify the sketch from the current value.

full sketch at this point is:

#include <OneWire.h>

OneWire  ds(3);  // on pin 3
#define MAX_DS1820_SENSORS 4     //sensors max number
byte addr[MAX_DS1820_SENSORS][8];
void setup(void) 
{
   Serial.begin(9600);
    Serial.print(F("DS1820 Test"));
  if (!ds.search(addr[0])) 
  {
    Serial.print(F("No more addresses."));
    ds.reset_search();
    delay(250);
    return;
  }
  if ( !ds.search(addr[1])) 
  {
    Serial.print(F("No more addresses."));
    ds.reset_search();
    delay(250);
    return;
  }
}
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
char buf[20];

void loop(void) 
{
  byte i, sensor;
  byte present = 0;
  byte data[12];

  for (sensor=0;sensor<MAX_DS1820_SENSORS;sensor++)
  {
    if ( OneWire::crc8( addr[sensor], 7) != addr[sensor][7]) 
    {
      Serial.print(F("CRC is not valid"));
      return;
    }

    if ( addr[sensor][0] != 0x10) 
    {
      Serial.print(F("Device is not a DS18S20 family device."));
      return;
    }

    ds.reset();
    ds.select(addr[sensor]);
    ds.write(0x44,1);         // start conversion, with parasite power on at the end

    delay(1000);     // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.

    present = ds.reset();
    ds.select(addr[sensor]);    
    ds.write(0xBE);         // Read Scratchpad

    for ( i = 0; i < 9; i++) 
    {           // we need 9 bytes
      data[i] = ds.read();
    }

    LowByte = data[0];
    HighByte = data[1];
    TReading = (HighByte << 8) + LowByte;
    SignBit = TReading & 0x8000;  // test most sig bit
    if (SignBit) // negative
    {
      TReading = (TReading ^ 0xffff) + 1; // 2's comp
    }
    Tc_100 = (TReading*100/2);    

    Whole = Tc_100 / 100;  // separate off the whole and fractional portions
    Fract = Tc_100 % 100;

    sprintf(buf, "%d:%c%d.%d\337C     ",sensor,SignBit ? '-' : '+', Whole, Fract < 10 ? 0 : Fract);

// a little sprintf help:  
//%% prints a single % (percent sign). 
//%c prints a single character with the given ASCII number (66 is printed as B, for example). 
//%s prints a given string 
//%d a signed integer in decimal 
//%u an unsigned (can't be negative) integer in decimal 
//%o an unsigned integer in octal 
//%x an unsigned integer in hexadecimal 
//%e a floating point number in scientific notation 
//%f a floating point number in fixed decimal notation 
//%g same as %e or %f, whichever printf thinks is best. 
//%X is the same as %x, except it uses upper-case letters 
//%E like %e, but with an upper-case 'E' 
//%G same as %E when scientific notation is used for the value. 
//%p a pointer; it outputs Perl's value address in hexadecimal. 
//%n an odd little bugger that *stores* (in the variable given for the position) the number of characters output so far. 

    Serial.print(buf);
  }
}

Thanks!

Hello, you can do something like this for example:

char buf[128] = "\0"; // IMPORTANT

for (uint8_t i = 0; i < 4; i++)
{
  sprintf(buf, "%s%c%d.%d,", buf,'-', 32, 9);
}

sprintf(buf, "%s%s", buf, "11/12/13-12:34:56");
Serial.println( buf );

The output:

-32.9,-32.9,-32.9,-32.9,11/12/13-12:34:56

Adapt to your code :slight_smile:

great! thanks! I'll try this. Is it not a problem if there is an i using already here:

for ( i = 0; i < 9; i++) 
    {           // we need 9 bytes
      data[i] = ds.read();
    }

( please note I'm on beginner level :slight_smile: )

But you must NOT use my loop :slight_smile: you must just follow the "shape", your code must look like this:

char buf[128] = "\0"; // IMPORTANT

for (sensor=0;sensor<MAX_DS1820_SENSORS;sensor++)
{
    // rest of your code here
    //...

    Fract = Tc_100 % 100;

    sprintf(buf, "%s%c%d.%d,", buf, SignBit ? '-' : '+', Whole, Fract < 10 ? 0 : Fract); //modified sprintf
}

sprintf(buf, "%s%s", buf, "11/12/13-12:34:56");
Serial.print(buf); // this moved outside of the loop

thanks! I'll get back with the results! :smiley:

it seems the sprintf() is ok, but the code is not...it only gets one tempareture, and no more...but it should realise multiple ds sensors...

it seems the sprintf() is ok, but the code is not...it only gets one tempareture, and no more...but it should realise multiple ds sensors...

You need to post your code. All of it.

If the loop is being executed the correct number of times, but the temp is not being obtained correctly, there should be 0s in the buffer. If there are no 0s in the buffer, the loop is not executing the correct number of times. You can use Serial.print() to debug you know.

I have to think through the whole project...At the end I would like log to SD card and send data to the web ( thingspeak, cosm...whatever...).
I tried a lot of things, but did not manage to work the whole stuff.
So I started from the begining...I do not want to hardcode the sensor addresses, and do not wnt to set just one type. That's why I started before with Dallastemperature library and Onewire.
Using now Arduino 1.0.2. + The latest Onewire library + latest Dallas Temp. lib. (MilesBurton.com
Just for a full information: I have mega2560 board with wiznet shield ( what has sd card module, onewire, Realtime clock, and a ds1820 sensor on the shield). Beside these I have at this moment two DS18B20 sensor.
Example sketch for multiple ds18 temp sensors is not the best, because that is not good for minus degrees...
This code handles the ds18 family and working with minus degrees too:

include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 9

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device addresses
DeviceAddress insideThermometer, outsideThermometer;

void setup(void)
{
  // start serial port
  Serial.begin(9600);
  Serial.println("Dallas Temperature IC Control Library Demo");

  // Start up the library
  sensors.begin();

  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // report parasite power requirements
  Serial.print("Parasite power is: "); 
  if (sensors.isParasitePowerMode()) Serial.println("ON");
  else Serial.println("OFF");

  // assign address manually.  the addresses below will beed to be changed
  // to valid device addresses on your bus.  device address can be retrieved
  // by using either oneWire.search(deviceAddress) or individually via
  // sensors.getAddress(deviceAddress, index)
  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
  //outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };

  // search for devices on the bus and assign based on an index.  ideally,
  // you would do this to initially discover addresses on the bus and then 
  // use those addresses and manually assign them (see above) once you know 
  // the devices on your bus (and assuming they don't change).
  // 
  // method 1: by index
 // if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
 // if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); 

  // method 2: search()
  // search() looks for the next device. Returns 1 if a new address has been
  // returned. A zero might mean that the bus is shorted, there are no devices, 
  // or you have already retrieved all of them.  It might be a good idea to 
  // check the CRC to make sure you didn't get garbage.  The order is 
  // deterministic. You will always get the same devices in the same order
  //
  // Must be called before search()
  oneWire.reset_search();
  // assigns the first address found to insideThermometer
  if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
  // assigns the seconds address found to outsideThermometer
  if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer");

  // show the addresses we found on the bus
  Serial.print("Device 0 Address: ");
  printAddress(insideThermometer);
  Serial.println();

  Serial.print("Device 1 Address: ");
  printAddress(outsideThermometer);
  Serial.println();

  // set the resolution to 9 bit
  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);

  Serial.print("Device 0 Resolution: ");
  Serial.print(sensors.getResolution(insideThermometer), DEC); 
  Serial.println();

  Serial.print("Device 1 Resolution: ");
  Serial.print(sensors.getResolution(outsideThermometer), DEC); 
  Serial.println();
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print("0");
    Serial.print(deviceAddress[i], HEX);
  }
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print("Temp C: ");
  Serial.print(tempC);
  Serial.print(" Temp F: ");
  Serial.print(DallasTemperature::toFahrenheit(tempC));
}

// function to print a device's resolution
void printResolution(DeviceAddress deviceAddress)
{
  Serial.print("Resolution: ");
  Serial.print(sensors.getResolution(deviceAddress));
  Serial.println();    
}

// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
  Serial.print("Device Address: ");
  printAddress(deviceAddress);
  Serial.print(" ");
  printTemperature(deviceAddress);
  Serial.println();
}

void loop(void)
{ 
  // call sensors.requestTemperatures() to issue a global temperature 
  // request to all devices on the bus
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures();
  Serial.println("DONE");

  // print the device information
  printData(insideThermometer);
  printData(outsideThermometer);
}

is it a good point to start? if yes, i will try to make it simplier, than at the second point, put the upload to web, and than the SD.
Any advice would be appretiated!

is it a good point to start?

It looks OK. The important thing, though, is whether is produces good output. Does it?

vespapierre:
I have to think through the whole project...At the end I would like log to SD card and send data to the web ( thingspeak, cosm...whatever...).

I can't say much about the code - I don't know anything about that sprintf stuff, which I assume is the sole cause of your grief, but I would point out that checking out that the sensors are kosher, or should even be connected, every time the loop goes round is surely absurd. All this is doing is taking up space and giving you something more to worry about.

If I understand the philosophy of your intent correctly, I believe you might need to rethink the role of the SD card. You don't need it to send data to cosm, indeed I don't think you can send a file to cosm. I guess you could incrementally read data off the card and send that to cosm but that would serve little purpose other than prove that whoever snuck in under cover of darkness and stuck a bogus probe on your system, didn't steal the SD on the way out.

In short, the SD card is redundant as far as cosm is concerned. This is because it is intended to work in real time - more or less. I imagine thingspeak is the same, but I haven't followed up on your comment about that. You will see the in my cosm feed code, which we have discussed before, that the SD doesn't get a mention.

This doesn't mean the SD is redundant for the likes of you and I. I was recording to SD before cosm and will be adding that section into the cosm feed sketch soon. This is for backup.

All of the above equally applies if you are logging locally using the the likes of PLX. You don't actually need the SD, or a clock. They are just for backup, and you should be able to prove up your project without either of them.

(This is something I worked out after the event........)

Paul,
yes it is producing correct output(at least as it seems on the serial monitor).degrees below zero is ok and different ds sensors are ok too to handle.
Nick,
Exactly I would use sd for only backup. In case if something wrong with the internet connection.It is good to have a backup.
Thanks for the advices!I know I will be back with the results of each step.

so now without the date+time, logging works ok! But I have some converting problems...
full code is here:

#include <SD.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Rtc_Pcf8563.h>
#include <Wire.h>

// Data wire is plugged into port 3 on the Arduino
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 9

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device addresses
DeviceAddress Thermometer1, Thermometer2 ;

//init the real time clock 
Rtc_Pcf8563 rtc; 

//variables

int temp0;
int temp1;
char pageAdd[140];

// **********************************SETUP*****************************************************
void setup(void)
{

  // start serial port
  Serial.begin(9600);

  //start SD
  Serial.print(F("Starting SD..."));
  if(!SD.begin(8)) Serial.println(F("failed"));
  else Serial.print(F("ok "));
  delay(2000);
  Serial.println(F("Ready"));

  // Start up the library
  sensors.begin();

  // locate devices on the bus
  Serial.print(F("Locating devices..."));
  Serial.print(F("Found "));
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(F(" devices."));

  // report parasite power requirements
  Serial.print(F("Parasite power is: ")); 
  if (sensors.isParasitePowerMode()) Serial.println(F("ON"));
  else Serial.println(F("OFF"));

  oneWire.reset_search();
  if (!oneWire.search(Thermometer1)) Serial.println(F("Unable to find address for Thermometer1"));
  if (!oneWire.search(Thermometer2)) Serial.println(F("Unable to find address for Thermometer2"));

  // show the addresses we found on the bus
  Serial.print(F("Device 0 Address: "));
  printAddress(Thermometer1);
  Serial.println();

  Serial.print(F("Device 1 Address: "));
  printAddress(Thermometer2);
  Serial.println();

  // set the resolution to 9 bit
  sensors.setResolution(Thermometer1, TEMPERATURE_PRECISION);
  sensors.setResolution(Thermometer2, TEMPERATURE_PRECISION);

  Serial.print(F("Device 0 Resolution: "));
  Serial.print(sensors.getResolution(Thermometer1), DEC); 
  Serial.println();
  Serial.print(F("Device 1 Resolution: "));
  Serial.print(sensors.getResolution(Thermometer2), DEC); 
  Serial.println();
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
  for (uint8_t i = 0; i < 8; i++)
  {
    // zero pad the address if necessary
    if (deviceAddress[i] < 16) Serial.print(F("0"));
    Serial.print(deviceAddress[i], HEX);
  }
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(F("Temp C: "));
  Serial.print(tempC);
}

// function to print a device's resolution
void printResolution(DeviceAddress deviceAddress)
{
  Serial.print(F("Resolution: "));
  Serial.print(sensors.getResolution(deviceAddress));
  Serial.println();    
}

// main function to print information about a device
void printData(DeviceAddress deviceAddress)
{
  Serial.print(F("Device Address: "));
  printAddress(deviceAddress);
  Serial.print(F(" "));
  printTemperature(deviceAddress);
  Serial.println();
}

//********************************************LOOP**************************************

void loop(void)
{ 
  delay(5000);
  Serial.print(F("Requesting temperatures..."));
  sensors.requestTemperatures();
  Serial.println(F("DONE"));

  // print the device information
  //  printData(Thermometer1);
  //  printData(Thermometer2);

  Serial.print(F("Temperatures are "));
  Serial.print(sensors.getTempC(Thermometer1));
  Serial.print(F(" Celsius, "));
  Serial.print(sensors.getTempC(Thermometer2));
  Serial.print(F(" Celsius, "));
  Serial.print(F("\n\r"));

  temp0=(sensors.getTempC(Thermometer1));
  temp1=(sensors.getTempC(Thermometer2));

  //datetime
  char sdate[11] = ""; 
  char stime[9] =""; 
  strcpy(stime, rtc.formatTime()); 
  strcpy(sdate, rtc.formatDate(RTCC_DATE_ASIA)); 
  Serial.print(stime); 
  Serial.print(" "); 
  Serial.print(sdate); 
  Serial.println();  
   
  if(!logFile(sdate,stime,temp0,temp1)) Serial.println(F("Log failed"));
  else Serial.println(F("Log ok"));

}
int logFile(int sdate, int stime, int temp0, int temp1) {
  File fh = SD.open("test.txt",FILE_WRITE);
  if(!fh) {
    Serial.println(F("Open fail"));
    return 0;
  }

  sprintf(pageAdd,"%u,%u,%u,%u;",sdate,stime,temp0,temp1);
  fh.println(pageAdd);
  fh.close();
  return 1;
}

Here I have problems with converting char* to int:

if(!logFile(sdate,stime,temp0,temp1)) Serial.println(F("Log failed"));

How should I fix this?

I would like to test the sd logging with this code...if that works fine, than I will add somehow the ethernet and uploading to thinsgpeak for example...

Do not use int type here. Leave the date and time as a character array. Pass them like this:

int logFile(char* sdate, char* stime, int temp0, int temp1) {
  File fh = SD.open("test.txt",FILE_WRITE);
  if(!fh) {
    Serial.println(F("Open fail"));
    return 0;
  }

  // note change to %s on first two
  sprintf(pageAdd,"%s,%s,%u,%u;",sdate,stime,temp0,temp1);
  fh.println(pageAdd);
  fh.close();
  return 1;
}

thanks Tim! seems it iw working...I'm just going to test!

I have changed to this:

sprintf(pageAdd,"%s,%s,%u,%u;",sdate,stime,temp0,temp1);

because I need negative values for temp0, temp1...is it ok?

or is it possible to set it as float? like:

int logFile(char* sdate, char* stime, float temp0, float temp1)

Stay away from float when possible. If you want a signed integer for the temperatures, use this:

// note change from %u to %i
sprintf(pageAdd,"%s,%s,%i,%i;",sdate,stime,temp0,temp1);

I know this is C++ reference, but the format variable types are the same.
http://www.cplusplus.com/reference/cstdio/printf/

Stuffing all the data into a string and then writing the string to the file is no faster than just writing the data one piece at a time to the file. The only advantage to using sprintf() is that it allows formatted output of the data, but that requires something between the % and the type. Since you aren't putting anything there, the formatting will be exactly the same as the print() and println() methods of the File class.

log now seems :
2012-12-03,17:58:32,26,26;
2012-12-03,17:59:02,26,26;
2012-12-03,17:59:07,26,26;
2012-12-03,17:59:12,26,26;
2012-12-03,17:59:17,26,26;
2012-12-03,17:59:23,26,26;
2012-12-03,17:59:28,26,26;
2012-12-03,17:59:33,26,26;
2012-12-03,17:59:38,26,26;
2012-12-03,17:59:43,26,26;
2012-12-03,17:59:48,26,26;

I'm feeling better:) Can I define the temp values to store it as 26,5 instead of 26 ?

on serial monitor it is ok, but on Sd is not.

serial looks like:

Requesting temperatures...DONE
Temperatures are 26.75 Celsius, 26.00 Celsius,

18:02:48 2012-12-03
Log ok

Hi Paul,

a bit later maybe it will be useful ( sprintf) when I have to upload the datas to the web ( like thingspeak, etc...). But at this point I want to be sure, everything is working fine. But maybe you are right!

@PaulS: That is correct, but you should recognize what is about to happen. The OP will want to put this in a log type format, so I expect that sprintf to change to this shortly:

sprintf(pageAdd,"%s at %s temp0=%i temp1=%i",sdate,stime,temp0,temp1);

The int type does not support a fractional part. Only whole numbers. Does the temperature sensor support a fractional temperature? If so, I can probably help you convert that.

aah ok Tim. Not I leave it as is. SD log is just running...If that is right, I would like to put the ethernet stuff in... :blush: