Arduino Logger Sketch

Definitions and Declarations

/*

  SD card datalogger "logger_mon.cpp"

 Hardware: Duemilaove withAT238, Adafruit logger shield 

 and Arduino proto-shield with LCD shift register

 Four analog inputs on DA9S pins 1 - 4 to A0-A3

 RTC with I2C on A4 and A5

 Serial 20x4 LCD using D2,D3,D4    

 Two switches on D5 & D6, which also has a LED

 External digital I/O on DA9S pins 7,8,9, with LEDs using D7,D8 & D9

 SD SPI interface using D10,D11,D12 & D13

 The SD card has year and month directiries pre-made

 There is one CSV file created per day

John Saunders 7/25/2012

The analog reference is 3.072 V to ger 3mv/count from the Duemilanove 3.3V

 */

#define DS1307_I2C_ADDRESS 0x68

#define leftSW 5

#define rightSW 6



#include <avr/pgmspace.h>

#include <SerialLCD.h>

#include <Wire.h>

#include <SD.h>


const int chipSelect = 10;

SerialLCD lcd(2);


// The order of DS1397 values is: secs,mins,hours,weekday(not used),date,month,year(2 digit)

const byte aPin[] = {0,1,2,3};   // the analog pin to be measured

const byte D9pin[] = {1,2,3,4};  // the D9 pin to which it is connected

const byte dPin[] = {7,8,9};

const char LCDColAddr[] = {0,10,0,10}; // for analog LCD placing

const char LCDRowAddr[] = {2,2,3,3};

// for each range 3V - 24 V by 3 there are specific calculations, per the range,Index for the input 0- 7

const int mult[]   = {9,6,9,6,6,9,10,12}; 

const int divide[] = {3,1,1,5,4,5,5,5};

PROGMEM const char header[] = {"Date,Time,Pin 1,Pin2,Pin 3,Pin4,Pin7,Pin8,Pin9"};

PROGMEM const byte recFileIndex[] = {99,99,99,98,8,3,0};  //These are DS1307 addresses or 99=skip

PROGMEM const byte recDateIndex[] = {99,99,99,98,3,0,8};

PROGMEM const byte recTimeIndex[] = {6,3,0,98,99,99,99};  //98 is a flag for midnight

const char intTimeIndex[] = {6,4,3};  //RTC addresses for options for recording interval

const char* settingStrings[] = \

{"minutes","hours","Pin 1 range","Pin 2 range","Pin 3 range","Pin 4 range","Finished"};

const char* intervalStrings[] = {"10 sec","1 min","10 min"};

PROGMEM const byte adjustAddr[] = {0x01,0x02,0x08,0x09,0x0A,0x0B};  //For adjusting &  saving setup parametyers

PROGMEM const byte adjustLimit[] = {59,23,7,7,7,7};

PROGMEM const char msg0[] = {"Initializing SD card"};

PROGMEM const char msg1[] = {"Press left switch"};

PROGMEM const char msg2[] = {"for setup options"};

PROGMEM const char msg3[] = {"Entering setting mode"};

PROGMEM const char msg4[] = {"to select this"};

PROGMEM const char msg5[] = {"Stopped to remove SD"};

PROGMEM const char msg6[] = {"Re-boot after"};

PROGMEM const char msg7[] = {"replacing the SD"};



char oldDay = 8;         // To find midnight to write the header

char newDay;

char interval = '0';    // the previous value of the selected element of recTime

byte intIndex;          // Index into intIndex, stored in DS1307 at address 0x0C

byte rangeIndex[4];     // Index into mult and divide, stored in DS1307 at addresses 0x08-0x0x0B

char D8prev = 1;        // State of left button

boolean cardOK = true;

boolean initCount = true;

// These are templates to be populated from the RTC. Put here to help stability

char recDate[] = {"mm/dd/20yy, "};

char recTime[] = {"hh:mm:ss "};

char analogString[4][7];  // Index in AnalogString to put string, the number to be displayed, decimals

char dateFilename[] = {"yy/mm/ARdd.CSV"};


boolean adjustments(byte);

boolean recordHeaders(char *);

boolean recordData(char *);

void    makeTimings();

int     makeAnalog(int,int,byte dploc = 3);

// int     availableMemory();

//void    displaySRAM();

int get_free_memory();

Setup and Loop

void setup()

{

   lcd.begin();

   Wire.begin();

   byte countdown;

   analogReference(EXTERNAL);   // set by potentiometer to 3.072 volts (3 mv/count)

   pinMode(leftSW,INPUT_PULLUP);

   pinMode(rightSW,INPUT_PULLUP);

   pinMode(7,INPUT_PULLUP);

   pinMode(8,INPUT_PULLUP);

   pinMode(9,INPUT_PULLUP);

   

    

   while(digitalRead(leftSW) == 0 || digitalRead(rightSW) == 0)  {

     lcd.clear();

     lcd.print("Release switches!");

     delay(100);


     }

   lcd.printPgm(msg0,1);  //msg0

   lcd.setCursor(0,2);

 // see if the card is present and can be initialized:


   if( !SD.begin(chipSelect)) {

     lcd.print("No valid card");

   // don't do anything more

     cardOK=false;                // Inhibits ecording, permits monitoring visually

      }

  else {

    lcd.print("Card initialized");

    cardOK=true;

    }


  delay(1000); //Setting mode

  for (countdown=0; countdown < 10; countdown++) {

     lcd.printPgm(msg1,0,0);      //msg1

     lcd.printPgm(msg2,2);  //msg2

     lcd.setCursor(0,3);

     lcd.print(10-countdown);

     if(digitalRead(leftSW) == 0) {

       break;

       }

     delay(300);

     }

  if (countdown < 10) {

    lcd.printPgm(msg3,0,0); //msg3

    byte selection = 0;

    while(digitalRead(leftSW) == 0) {

         delay(100);

         }

    while(true) {

           lcd.clear();

           lcd.print("Adjust ");

           lcd.printStr(settingStrings[selection]);

           lcd.printPgm(msg1,2);

           lcd.printPgm(msg4,3); //msg4

           delay(1500);

           if(digitalRead(leftSW) == 0) {

            if(selection == 6) {

                  break;

                 }

             else {

               D8prev = 0;

               adjustments(selection);

             }

           }

           selection++;

           if (selection > 6) {

                selection = 0;

                }

       }

    }          //End of setting mode

  

 // retrieve and display the range and interval settings from the RTC RAM

    lcd.clear();

    lcd.print("Range settings:");

    lcd.setCursor(0,2);

    Wire.beginTransmission(DS1307_I2C_ADDRESS);   

    Wire.write(0x08);

    Wire.endTransmission();

    Wire.requestFrom(DS1307_I2C_ADDRESS,5);

    for(char i=0;i<4;i++) {

      rangeIndex[i] = Wire.read();

      if(rangeIndex[i]>7) {

          rangeIndex[i] = 0;

          }

      if(i==2) {

          lcd.setCursor(0,3);

        }

      lcd.print("Pin");

      lcd.print(D9pin[i]);

      lcd.print('=');

      lcd.print(3*(rangeIndex[i]+1));

      lcd.print("V ");

      }

   intIndex=Wire.read();

   Wire.endTransmission();

   lcd.setCursor(0,4);

   lcd.print("Press left switch ");

   do {

      delay(300);

   }

   while(digitalRead(leftSW)==1);

   D8prev=0;

 //  displaySRAM();

}


void loop()

{

    int analogReading[4]; 

    byte analogCount[4];


  if(digitalRead(rightSW)==0) {  //This permits safe SD removal

      lcd.printPgm(msg5,0,0);  //msg5

      lcd.printPgm(msg6,2);  //msg6

      lcd.printPgm(msg7,3); //msg7

      delay(300);

      cardOK = false;

      return;

    }

makeTimings();// Generate the filename and date and time strings


if ( initCount == true) {

for(byte i=0;i< 4;i++) {

analogReading[i]=0;

analogCount[i]=0;

analogIn[i]=0;

interval=recTime[intTimeIndex[intIndex]];

}

initCount=false;

}

// Display th  date,time,analog values and selected interval

lcd.clear();

lcd.print(recDate);

lcd.print(recTime);


// read four analog pIns and display their values

for (int i = 0; i < 4; i++) {

byte range = rangeIndex[i];

byte dpLoc = 2;

if(range < 3) {

dpLoc++;

}

analogReading[i]+=analogRead(aPin[i]);

analogCount[i]++;

lcd.setCursor(LCDColAddr[i],LCDRowAddr[i]);

lcd.print('P');

lcd.print(D9pin[i]);

lcd.print('=');

if(analogCount[i] >= mult[range]) {

analogIn[i]=analogReading[i]/divide[range];

analogCount[i]=0;

analogReading[i]=0;

}

makeAnalog(i,analogIn[i],dpLoc);

lcd.printStr(analogString[i]);

}


lcd.setCursor(0,4); // bottom line

lcd.print("Rec. Int. = ");

lcd.printStr(intervalStrings[intIndex]);


char D8now = digitalRead(leftSW);


// open the file. note that only one file can be open at a time,

// so you have to close this one before opening another.


// Write header s at midnight anf when booted  

if (newDay != oldDay && cardOK == true) {

if(!recordHeaders(dateFilename)) {

lcd.clear();

lcd.print("Header record fail");

delay(1000);

}

else {

lcd.clear();

lcd.print("Header recorded");

delay(1000);

}

}


oldDay=newDay;

if (interval != recTime[intTimeIndex[intIndex]] && cardOK==true \

&&analogIn[0]>=0&&analogIn[1]>=0&&analogIn[2]>=0&&analogIn[3]>=0){

// Write the date and time to the file at selected interval

if(!recordData(dateFilename)) {

lcd.clear();

lcd.print("Data record fail");

delay(1000);

}

}//End of recording


// Run-time change of recording interval

if((D8now == 0) && (D8prev == 1)) {

intIndex++;

if(intIndex >= 4) {

intIndex=0;

}

// store this value into the DS1307 at address 0x0C

Wire.beginTransmission(DS1307_I2C_ADDRESS);

Wire.write(0x0C);

Wire.write(intIndex);

Wire.endTransmission();

}

interval=recTime[intTimeIndex[intIndex]];

D8prev=D8now;

delay(70);   

}

Functions

boolean adjustments(byte adrInx) {

  byte adjustValue;

  byte adjustBCD;

  char D8now;

  lcd.clear();

  lcd.print("Adj. ");

  lcd.printStr(settingStrings[adrInx]);

  lcd.print('=');

  Wire.beginTransmission(DS1307_I2C_ADDRESS);   

  Wire.write(pgm_read_byte(&adjustAddr[adrInx]));

  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS,1);

  adjustBCD = Wire.read();

  Wire.endTransmission();

  adjustValue = (adjustBCD & 0x0F) + (10*(adjustBCD>>4));

  lcd.printStr("Left SW: adjust",2);

  lcd.printStr("Right SW: done",3);

  while(digitalRead(rightSW) == 1) {

    lcd.setCursor(17,0);

    if(adrInx>1) {

      lcd.print(3*(adjustValue + 1));

      lcd.print(' ');

      }

    else {

        lcd.print(adjustValue); 

    }

    lcd.print(' ');

    D8now = digitalRead(leftSW);

    if((D8now == 0) && (D8prev == 1)) {

      adjustValue++;

      if(adjustValue > pgm_read_byte(&adjustLimit[adrInx])) {

         adjustValue = 0;

        }

      }

   D8prev = D8now;

  }

  adjustBCD=(adjustValue % 10) + (adjustValue/10*16);

  Wire.beginTransmission(DS1307_I2C_ADDRESS);   

  Wire.write(pgm_read_byte(&adjustAddr[adrInx]));

  Wire.write(adjustBCD);

  Wire.endTransmission();

  return true;

}


void makeTimings() {

    char timeValue;

    char LSDigit;

    char MSDigit;


    // Read the time values and assign to the template strings

    Wire.beginTransmission(DS1307_I2C_ADDRESS);   

    Wire.write(0);

    Wire.endTransmission();

    Wire.requestFrom(DS1307_I2C_ADDRESS,7);

    for(char i=0;i<7;i++) {

      timeValue = Wire.read();

      LSDigit = (timeValue & 0x0F) + '0';

      MSDigit = ((timeValue >> 4) & 0x07) +'0';

      if(recFileIndex[i] < 98) {

         dateFilename[pgm_read_byte(&recFileIndex[i])] =  MSDigit;

         dateFilename[pgm_read_byte(&recFileIndex[i]) + 1] =  LSDigit;

        }

      if(recDateIndex[i] < 98) {

         recDate[pgm_read_byte(&recDateIndex[i])] =  MSDigit;

         recDate[pgm_read_byte(&recDateIndex[i]) + 1] =  LSDigit;

        }

       if(recTimeIndex[i] < 98) {

         recTime[pgm_read_byte(&recTimeIndex[i])] =  MSDigit;

         recTime[pgm_read_byte(&recTimeIndex[i]) + 1] =  LSDigit;

        }  

        if(i == 3) {

         newDay =  timeValue;

        }

     }

    Wire.endTransmission();

  

  return;

}


boolean recordHeaders(char *recFilename) {

    File recFile = SD.open(recFilename, FILE_WRITE); // Open the file

    if(recFile) {

      int i=0;

      char c;

      do {

        c = pgm_read_byte(header+i++);

        recFile.print(c);

        } 

      while(c != 0);

      recFile.println();

      recFile.print(",,");

      for(int i = 0;i<4;i++) {

         recFile.print(3*(rangeIndex[i]+1));

         recFile.print('V');

         if(i<3) {

            recFile.print(',');

            }

         }

     recFile.println();

     recFile.close();

    return true;

     }

  return false;

}


boolean recordData(char *recFilename) {

    File recFile = SD.open(recFilename, FILE_WRITE); // Open the file

    if(recFile) {

     // Write the analogIn values to the file

       recFile.print(recDate);

       recFile.print(recTime);

       for (byte i = 0; i < 4; i++) {

         if (i < 4) {

            recFile.print(',');

            }

         recFile.print(analogString[i]);

         }

       for(byte i = 7;i < 10;i++) {

           recFile.print(',');

           recFile.print(digitalRead(i));

           }

       recFile.println();

       recFile.close();

       return true;

    }

   return false;

}


int makeAnalog(int j,int  k,byte dploc) {

    int div;

    int rem;

    int mod = 10000; 

    byte leading = 0; 

    byte i = 4;

    byte pos = 0;

    dploc=constrain(dploc,0,3);

    if(k < 0) {

    analogString[j][pos++] = '-';

    k = -k;

    }

     while(mod >= 1) {

     div = k/mod; 

        rem = k % mod; 

    if(leading == 1 || div > 0) {

        analogString[j][pos++] = div + '0';

        leading = 1;

            }

    if(leading == 0 && div == 0 && i <= dploc) {

         analogString[j][pos++] = div + '0';

        }

    if(dploc > 0 && i == dploc) {

        analogString[j][pos++] = '.';

        }

    k = rem;

    mod = mod/10;

    i--;

    }

    analogString[j][pos] = NULL;

    return pos;

}

/*

int availableMemory() {

  int size = 2048;

  byte *buf;

  while((buf= (byte *)malloc(--size)) == NULL);

  free(buf);

  return size;

}


void displaySRAM() {

  while(digitalRead(5) == 0) { delay(50);}

  lcd.clear();

  lcd.print("free memory=");

  lcd.print(availableMemory());

  lcd.printStr("memory used=",2);

  lcd.print(2048-availableMemory());

  while(digitalRead(5) == 1) { delay(50);}

  return;

}

*/


int get_free_memory()

{

  int free_memory;

  extern int __bss_end;

  extern int* __brkval;

  if((int)__brkval == 0)

    free_memory = ((int)&free_memory) - ((int)&__bss_end);

  else

    free_memory = ((int)&free_memory) - ((int)__brkval);


  return free_memory;

}