Comments & advices about my code

Hi all,

I am working on a project to multiple temperatures by the use of DS18B20 sensors (not in parasitic way). The idea is to measure air temperature, snow temperature (at different heights -14-), surface temperature and ground temperature (at different depths -10-), each one in a different bus. I also have other 2 sensors connected to analog pins, as well as the battery and a solar cell by voltaje dividers. The device is powered by a solar cell and a Energy shield (by seedstudio) connected to an arduino duemilanove board.

I use an ds1307 to send the arduino to sleep and allow to measure once per hour, and save the data into an SD card. I also added and 4n35 optocoupler to power the sensors only when measuring (so save power), and a led to show that the device is measuring, as well as to see if there is an error during the setup, freezing the program. If the setup is ok, and the program runs perfect, the user could check whenever he want if an error ocurred latter, for example by fault of one of the sensors or SD Card corruption. For that reason i added a push button connected to digital pin 2 to test if by the use of interrupts (digital pin 2). To save power i added a switch to disconnect the led when not needed, because the device will be only checked once per year (in the better case).

Additionally i added an 24LC256 eeprom to save the error in case of a complete dissaster or the battery drain. I still didn´t coded this part of the program.

I will post the code. Could you take a look? I would like to know your opinion and how to improve it, if able.
BTW, i observed a rare behaviour when pushing the button, because the checking code seems to repeat. I mean, when i push the button, the led should blink 3 times to say everything is ok. However, it occurs twice... Is not bad, because the user have two opportunities to count the led blinks to know the error, but i didn´t write the code in this way. So, just only i would like to know why.

Thanks so much, and thanks from now for any comment or idea.
Cheers!

Permarduino_v08.ino (17.7 KB)

//  DEVICE CONFIGURATION
//  Libraries definition
#include <Wire.h>                                // Library for I2C communications protocol
#include <RTClib.h>                              // Library for DS1307 RTC management
#include <eepromi2c.h>                           // Library for 24LC256 EEPROM management
#include <OneWire.h>                             // Library for 1-Wire communications protocol
#include <DallasTemperature.h>                   // Library for DS18B20 temperature sensor
#include <SD.h>                                  // Library for SD card management
#include <Sleep_n0m1.h>                          // Library for sleep and power save

//  Analogue pins definition
const int Battery = 0;                           // Battery voltage - Analog pin 0
const int SolarCell = 1;                         // Solar cell voltage - Analog pin 1
const int ThermalFlux1 = 3;                      // Geothermal Flux device - Analog pin 2
const int ThermalFlux2 = 2;                      // Geothermal Flux sensor - Analog pin 3

//  Digital pins definition
//const int TestButton = 2;                      // PermArduino working test button - Digital pin 2
const int TestLed = 9;                           // PermArduino working led - Digital pin 9
const int chipSelect = 10;                       // SD Card configuration - Digital pin 10
const int Power = 8;                             // Activation pin to power sensors - Digital pin 8
const int AirTemp = 4;                           // Air temperature sensor - Digital pin 4
const int SnowTemp = 5;                          // Snow temperature sensors chain - Digital pin 5
const int SurfaceTemp = 6;                       // Surface temperature sensor - Digital pin 6
const int GroundTemp = 7;                        // Ground temperature sensors chain- Digital pin 7

//  Variables definition
boolean abortSleep;                              // Cancel sleep cycle
unsigned int n = 0;                              // Measurements counter
volatile byte e = 0;                                      // Error type
byte sn[4];                                      // Sensors in each bus
unsigned int batt;                               // Store battery voltage
unsigned int solar;                              // Store solar cell voltage
float temp;                                      // Store temperature data
int flux1;                                       // Store geothermal flux (device) data
float flux2;                                     // Store geothermal flux (sensor) data

//  Constants definition
const float FluxRes = 41.8;                      // Resolution of Geothermal Flux 2 sensor (W·cm^-2/mV)

//  EEPROM data configuration
struct config {
  String header;
} config;

//  Log files
File datafile;                                   // File to store the adquired data
char filename1[] = "Data.csv";                   // Name of the file to store the data

//  Libraries configuration
RTC_DS1307 RTC;                                  // Configure library to read the Real Time Clock                      
Sleep sleep;                                     // Configure the library to sleep the Arduino board
unsigned long sleepTime;                         // Define the sleep time (in ms)
OneWire oneWire1(AirTemp);                       // Configure library to read air temperature sensors
DallasTemperature sensors1(&oneWire1);
OneWire oneWire2(SnowTemp);                      // Configure library to read snow temperature sensors
DallasTemperature sensors2(&oneWire2);
OneWire oneWire3(SurfaceTemp);                   // Configure library to read surface temperature sensors
DallasTemperature sensors3(&oneWire3);
OneWire oneWire4(GroundTemp);                    // Configure library to read ground temperature sensors
DallasTemperature sensors4(&oneWire4);
const byte sensorsnumber[4] = {1,14,1,10};       // Number of sensors in each bus
const byte Precision = 12;                       // DS18B20 precision configuration to 12 bits (0.0625ºC)

//  Sensors identification
uint8_t airsensors[1][8] = {                     // Air temperature sensors
  {0x28,0x96,0x38,0x20,0x05,0x00,0x00,0xE2}      // Sensor at 160 cm heigth
};
uint8_t snowsensors[14][8] = {                   // Snow temperature sensors
  {0x28,0x72,0x87,0x05,0x05,0x00,0x00,0xC6},     // Sensor at 2.5 cm height
  {0x28,0x72,0x8E,0x04,0x05,0x00,0x00,0xBA},     // Sensor at 5 cm height
  {0x28,0x22,0xF8,0x05,0x05,0x00,0x00,0xEA},     // Sensor at 10 cm height
  {0x28,0xB4,0xAE,0x04,0x05,0x00,0x00,0x6F},     // Sensor at 20 cm height
  {0x28,0xCB,0x84,0x04,0x05,0x00,0x00,0x96},     // Sensor at 30 cm height
  {0x28,0x79,0x10,0x06,0x05,0x00,0x00,0x50},     // Sensor at 40 cm height
  {0x28,0x52,0x30,0x05,0x05,0x00,0x00,0x6E},     // Sensor at 50 cm height
  {0x28,0xF8,0x77,0x05,0x05,0x00,0x00,0x45},     // Sensor at 60 cm height
  {0x28,0x60,0x41,0x06,0x05,0x00,0x00,0xC5},     // Sensor at 70 cm height
  {0x28,0xD2,0x8F,0x04,0x05,0x00,0x00,0x2B},     // Sensor at 80 cm height
  {0x28,0x04,0xA4,0x05,0x05,0x00,0x00,0x5A},     // Sensor at 100 cm height
  {0x28,0x51,0xF7,0x05,0x05,0x00,0x00,0x44},     // Sensor at 120 cm height
  {0x28,0x7E,0x2E,0x05,0x05,0x00,0x00,0x7B},     // Sensor at 140 cm height
  {0x28,0x42,0xEF,0x04,0x05,0x00,0x00,0x8B}      // Sensor at 160 cm height
};
uint8_t surfacesensors[1][8] = {                 // Surface temperatue sensors
  {0x28,0x4A,0x86,0x20,0x05,0x00,0x00,0xB6}      // Sensor at 1 cm depth  
};
uint8_t groundsensors[10][8]={                   // Ground temperature sensors
  {0x28,0x1C,0xC4,0x04,0x05,0x00,0x00,0x3E},     // Sensor at 2.5 cm depth
  {0x28,0xD4,0x2B,0x05,0x05,0x00,0x00,0x3A},     // Sensor at 5 cm depth
  {0x28,0x7E,0xFD,0x05,0x05,0x00,0x00,0x6B},     // Sensor at 10 cm depth
  {0x28,0xA5,0x57,0x04,0x05,0x00,0x00,0x56},     // Sensor at 20 cm depth
  {0x28,0xAF,0x1C,0x06,0x05,0x00,0x00,0x07},     // Sensor at 30 cm depth
  {0x28,0x7D,0x1E,0x05,0x05,0x00,0x00,0xA6},     // Sensor at 40 cm depth
  {0x28,0x6D,0xA6,0x04,0x05,0x00,0x00,0x03},     // Sensor at 50 cm depth
  {0x28,0x1E,0x86,0x05,0x05,0x00,0x00,0xB5},     // Sensor at 60 cm depth
  {0x28,0x3F,0x36,0x05,0x05,0x00,0x00,0x7B},     // Sensor at 70 cm depth
  {0x28,0xB4,0xFB,0x05,0x05,0x00,0x00,0xA7}      // Sensor at 80 cm depth
};
//  DEVICE INITIALIZATION
void setup(){
  pinMode(Power, OUTPUT);                        // Configure the power pin
  pinMode(TestLed, OUTPUT);                      // Configurate the working led
  pinMode(10, OUTPUT);                           // Configure SD card
  Wire.begin();                                  // Starts I2C communications
  //Serial.begin(9600);                          // Starts Serial comminications
  digitalWrite(TestLed, HIGH);                   // Turn off the test led
  RTC.begin();                                   // Start the RTC 
  delay(50);   
  if (! RTC.isrunning()) {                       // Check if RTC is running
    e = 1; 
    error();
    return;
  }
  if (! SD.begin(chipSelect)) {                   // Check if SD memory card is running
    e = 2;
    error();
    return;
  }
  if (! SD.exists(filename1)) {                  // Check and/or create the logdata file on SD Card
    datafile = SD.open(filename1, FILE_WRITE);   // Create the datafile if it doesn't exist 
    datafile.close();
    if (! SD.exists(filename1)) {                // Check if datafile was created
      e = 3;
      error();
      return;
    }
    eeRead(0,config);                            // Read the header information from the EEPROM memory
    delay(30);
    datafile = SD.open(filename1, FILE_WRITE);   // Open the datafile and save the header on it
    if (datafile){
      //Datafile.println(config.header);
      //datafile.print("No;Date;Time;Bat(V);Sol(V);InV(V);InT(C);Air1(C);Sn1(C);Sn2(C);Sn3(C);Sn4(C);Sn5(C);Sn6(C);Sn7(C);Sn8(C);Sn9(C);Sn10(C);Sn11(C);Sn12(C);Sn13(C);Sn14(C);");
      //datafile.println("Surf1(C);Gr1(C);Gr2(C);Gr3(C);Gr4(C);Gr5(C);Gr6(C);Gr7(C);Gr8(C);Gr9(C);Gr19(C);GF1(-);GF2(-);GF2(mW/m2)");
      delay(30);
      datafile.close();
    }
    else {
      e = 4;
      error();
      return;
    }     
  }
  
  // Sensors initilization, configuration  and test
  digitalWrite(Power, HIGH);                     // Turn on the sensors
  delay(1000);
  sensors1.begin();                              // Initialize air temperature sensor bus
  sensors2.begin();                              // Initialize snow temperature sensor bus
  sensors3.begin();                              // Initialize surface temperature sensor bus
  sensors4.begin();                              // Initialize ground temperature sensor bus
  sn[0] = sensors1.getDeviceCount();             // Establish the number of sensors on air temperature bus
  sn[1] = sensors2.getDeviceCount();             // Establish the number of sensors on snow temperature bus
  sn[2] = sensors3.getDeviceCount();             // Establish the number of sensors on surface temperature bus
  sn[3] = sensors4.getDeviceCount();             // Establish the number of sensors on ground temperature bus
  for (byte i=0; i<4; i++){                      // Check if the number of sensors is correct in each bus
    if (! sn[i] == sensorsnumber[i]){
      e = 5;
      error();
      return;
    }
  }
  sensors1.setResolution(airsensors[0], Precision);    // Set the resolution of air temperature sensors
  for (byte i=0; i < 14; i++){                         // Set the resolution of snow temperature sensors
   sensors2.setResolution(snowsensors[i], Precision);
  }
  sensors3.setResolution(airsensors[0], Precision);    // Set the resolution of surface temperature sensors
  for (byte i=0; i < 10; i++){                         // Set the resolution of ground temperature sensors
    sensors4.setResolution(airsensors[i], Precision);
  }
  Measurements();                                // Take an initial measurement from sensors
  digitalWrite(Power, LOW);                      // Turn off the sensors
  
  digitalWrite(TestLed, LOW);                    // Turn off the test led
  abortSleep = false;                            // 
  attachInterrupt(0, Awake, CHANGE);             // Activate the test button on the board 
}
//  MAIN DEVICE PROGRAM
void loop(){
  detachInterrupt(0);                            // Disable test button
  DateTime now = RTC.now();                      // Check the present time
  if ((now.minute() == 0) && (abortSleep == false)){      // Measure if it is the time o'clok and the test button was not pressed
    Measurements();
    delay(100);
  }
  if (abortSleep == true){                       // Shows device status if button was pressed
    Checking();
    delay(100);
  }
  RTC.now();                                     // Check the present time to calculate sleeping time (in ms)                             
  sleepTime = (3600000UL - (((now.minute()*60UL) + now.second())*1000UL));
  delay(100);
  abortSleep = false; 
  attachInterrupt(0, Awake, CHANGE);             //Activate again the test button on the board
  delay(100);
  sleep.pwrDownMode();                           // Set the sleep mode to maximum power save
  sleep.sleepDelay(sleepTime, abortSleep);       // Start to sleep during the calculated period, until waked up
}


//  PROCEDURES
// Sensors reading
void Measurements(){
  DateTime now = RTC.now();
  digitalWrite(Power, HIGH);                     // Turn on the sensor's power
  digitalWrite(TestLed, HIGH);                   // Turn on the led marking "Measurements in progress"
  delay(1000);
  n = n + 1;                                     // Update measurement counter
  datafile = SD.open(filename1, FILE_WRITE);     // Open the file to store the data
  if (datafile){
    datafile.print(n);                           // Save measurement number (counter)
    datafile.print(";");
    datafile.print(now.day(), DEC);              // Save date and time
    datafile.print("/");
    datafile.print(now.month(), DEC);
    datafile.print("/");
    datafile.print(now.year(), DEC);
    datafile.print(";");
    datafile.print(now.hour(), DEC);
    datafile.print(":");
    datafile.print(now.minute(), DEC);
    datafile.print(":");
    datafile.print(now.second(), DEC);
    datafile.print(";");
    datafile.print(readVcc());                   // Read and save battery voltage
    datafile.print(";");
    datafile.print(readTemp());                  // Read and save inner temperature
    datafile.print(";");
    datafile.print(analogRead(Battery));         // Read and save battery reading                    
    datafile.print(";");
    datafile.print(analogRead(SolarCell));       // Read and save solar cell reading                     
    datafile.print(";");
    sensors1.requestTemperatures();              // Read Air temperature sensor
    temp = sensors1.getTempC(airsensors[0]);
    datafile.print(temp);                        // Save Air temperature data
    datafile.print(";");
    if ((temp == -127)||(temp == 85)){           // Check for errors
      e = 6;
    }
    sensors2.requestTemperatures();              // Read Snow temperature sensors
    for (uint8_t i=0; i<14; i++){     
      temp = sensors2.getTempC(snowsensors[i]);
      datafile.print(temp);                      // Save Snow temperature data
      datafile.print(";");
      if ((temp == -127)||(temp == 85)){         // Check for errors
        e = 7;
      }
    }
    sensors3.requestTemperatures();              // Read Surface temperature sensors
    temp = sensors3.getTempC(surfacesensors[0]);
    datafile.print(temp);                        // Save Surface temperature data
    datafile.print(";");
    if ((temp == -127)||(temp == 85)){           // Check for errors
      e = 8;
    }
    sensors4.requestTemperatures();              // Read Ground temperature sensors
    for (uint8_t i = 0; i<10; i++){     
      temp = sensors4.getTempC(groundsensors[i]);
      datafile.print(temp);                      // Save Ground temperature data
      datafile.print(";");
      if ((temp == -127)||(temp == 85)){         // Check for errors
        e = 9;
      }
    }
    flux1 = analogRead(ThermalFlux1);            // Read Geothermal flux sensor 1
    datafile.print(flux1);                       // Save geothermal flux 1 (1023 levels)                    
    datafile.print(";");
    flux2 = analogRead(ThermalFlux2);            // Read Geothermal flux sensor 2
    datafile.print(flux2);                       // Save geothermal flux 2 (1023 levels)
    datafile.print(";");                        
    flux2 = (((flux2*5000)/2013)*FluxRes);       // Convert values
    datafile.print(flux2);                       // Save geothermal flux 2 (mW/cm^2)
    datafile.println(";");
    delay(100);
    datafile.close();                            // Close data file
  }
  else {                                         // Call error procedure if not able to save the data
    e = 5;
    error();
    return;
  }
  digitalWrite(Power, LOW);                      // Turn off the sensor's power
  digitalWrite(TestLed, LOW);                    // Turn off the led marking "Measurements in progress"
}


//Inner voltmeter
long readVcc() {
  long result;
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  // Read 1.1V reference against AVcc
  delay(2);                                      // Wait for Vref to settle
  ADCSRA |= _BV(ADSC);                           // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result;                    // Back-calculate AVcc in mV
  return result;
}

//Inner temperature
long readTemp() {
  long result;
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);   // Read temperature sensor against 1.1V reference
  delay(2);                                      // Wait for Vref to settle
  ADCSRA |= _BV(ADSC);                           // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = (result - 125) * 1075;                // Back-calculate temp in ºCx1000
  return result;
}

//  Stops the sleep process
void Awake(){
  abortSleep = true;
}

//  Shows the device status by a blinking led
void Checking(){
  for (byte i=0; i<3; i++){                      // Blink the led 3 times
    digitalWrite(TestLed, HIGH);   
    delay(500);
    digitalWrite(TestLed, LOW);
    delay(500);
  }
  for (byte i=0; i < e; i++){
    digitalWrite(TestLed, HIGH);                 // Red LED indicates higher error type
    delay(200);
    digitalWrite(TestLed, LOW);
    delay(200);
  }
  delay(500);
}

// Error control
void error() {
  for (byte i=0; i = e; i++){                   // Red LED indicates error
    digitalWrite(TestLed, HIGH);
    delay(200);
    digitalWrite(TestLed, LOW);
    delay(200);
  }
  delay(1000);
  while(1);                                     // Freeze the program because of the error
}

Now, post the code correctly. Use the Additional Options link (below the post text entry field) to attach your code.

//  Analogue pins definition
const int Battery = 0;                           // Battery voltage - Analog pin 0
const int SolarCell = 1;                         // Solar cell voltage - Analog pin 1
const int ThermalFlux1 = 3;                      // Geothermal Flux device - Analog pin 2
const int ThermalFlux2 = 2;                      // Geothermal Flux sensor - Analog pin 3

It's better to have Pin somewhere in the name of variables that hold pin numbers, to distinguish them from variables that hold values read from the sensors connected to the pins.

When you put unnecessary information in the comment, you look silly when the information doesn't match the code.

OneWire oneWire1(AirTemp);                       // Configure library to read air temperature sensors
DallasTemperature sensors1(&oneWire1);
OneWire oneWire2(SnowTemp);                      // Configure library to read snow temperature sensors
DallasTemperature sensors2(&oneWire2);
OneWire oneWire3(SurfaceTemp);                   // Configure library to read surface temperature sensors
DallasTemperature sensors3(&oneWire3);
OneWire oneWire4(GroundTemp);                    // Configure library to read ground temperature sensors
DallasTemperature sensors4(&oneWire4);

sensors1, sensors2, sensors3, and sensors4? Did you get tired of think up meaningful names? Later, you need to come back here to remember what sensors3 means. You would not have to to determine what surfaceSensors means.

You'll perhaps have noticed that the Arduino functions use a noun and a verb in the name, like analogRead(), digitalWrite(), etc. The names clearly define what the function does. Measurements() and Checking() do not. Is Measurements() performing some action, or is it recording some data to an SD card? Or is it doing something completely different? Clear up the ambiguity by using decent names.

  detachInterrupt(0);                            // Disable test button

No, it doesn't. It detaches the interrupt handler that wakes the Arduino up. If you are going to have comments, they should be correct. And, yes, you should have comments.

  RTC.now();                                     // Check the present time to calculate sleeping time (in ms)

Why call a function that returns a value, when you discard the value?

  sleepTime = (3600000UL - (((now.minute()*60UL) + now.second())*1000UL));

This is based on the time that the interrupt was detached, not on the time after the measurements were somehow dealt with or the checking was somehow performed.

Thanks PaulS for your comments.

You are right about some comments and names of pins, variables and functions... i used the examples and codes to test each sensor and procedure, and when putting all together i forgot to made the necessary modifications. Thanks for call my attention about it. Be sure i will modify it!

About the RTC.now(),
i must use it, because without it, the next calculation of the sleetime does not work. So, this code read the time from the RTC, and then i use the minutes and seconds to made the calculation. Without it, it simply does not work.

Cheers,

To save power when not needed, i added a physical interrupt to disconnect the led.

It's not clear what this means.

You are right. I mean a switch to cut the led circuit. In this way, although the code try to turn on the led by a digital pin, the circuit is cut and the led remains off to save power.
Then, when the user want to check the devide (once per year in the better case), it should turn on the switch and then use the test button to check if it works ok and, in case, the higher type of error detected during device working