/* Logger with SD card and realtime clock Date Comments 2014-07-08 Logging, get back to working */ #define VERSIONID "1.0" #include #include #include #include #include #include "RTClib.h" // A simple data logger for the Arduino (for temperature); also, using DS18B20 sensors // how many milliseconds between grabbing data and logging it. 1000 ms is once a second #define LOG_INTERVAL 1000 // mills between entries (reduce to take more/faster data) // how many milliseconds before writing the logged data permanently to disk // set it to the LOG_INTERVAL to write each time (safest) // set it to 10*LOG_INTERVAL to write all data every 10 datareads, you could lose up to // the last 10 reads if power is lost but it uses less power and is much faster! #define SYNC_INTERVAL 10000 // mills between calls to flush() - to write data to the card uint32_t syncTime = 0; // time of last sync() #define ANALOG_READ_DELAY 10 // 10 ms delay #define ECHO_TO_SERIAL 1 // echo data to serial port #define WAIT_TO_START 0 // Wait for serial input in setup();0=no wait, 1=wait // the digital pins that connect to the LEDs #define redLEDpin 2 #define greenLEDpin 3 #define yellowLEDpin 7 #define ONEWIREpin 5 #define N_THERMISTORS 4 int Thermistor_Pin[N_THERMISTORS]; RTC_DS1307 RTC; // define the Real Time Clock object // for the data logging shield, we use digital pin 10 for the SD cs line const int chipSelect = 10; // the logging file File logfile; // DS18S20 Temperature chip i/o OneWire ds(ONEWIREpin); int nSensorCount; byte addr_list [4][8]; // up to 4 sensors, 8 bytes per address void error(char *str) ///////////////////////////////////////////////////////////////////////////////////////// { Serial.print("error: "); Serial.println(str); // red LED indicates error digitalWrite(redLEDpin, HIGH); // endless loop here... while(1); } void setup(void) ///////////////////////////////////////////////////////////////////////////////////////// { Serial.begin(9600); Serial.println(); int i_thermistor; // use debugging LEDs pinMode(redLEDpin, OUTPUT); pinMode(greenLEDpin, OUTPUT); pinMode(yellowLEDpin, OUTPUT); Get_DS18B20_Addresses(); Thermistor_Pin[0]=A0; Thermistor_Pin[1]=A1; Thermistor_Pin[2]=A2; Thermistor_Pin[3]=A3; // thermistor pin (analog input) for calibration for(i_thermistor=0;i_thermistor<=N_THERMISTORS-1;i_thermistor++) { pinMode(Thermistor_Pin[i_thermistor], INPUT); } Serial.print("Memory free = "); Serial.println(freeRam()); #if WAIT_TO_START Serial.println("Type any character to start"); while (!Serial.available()); #endif //WAIT_TO_START // initialize the SD card 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)) { error("Card failed, or not present"); } Serial.println("card initialized."); // create a new file // every time the system starts, it logs to a SINGLE file // starting with LOGGER00.CSV, then LOGGER01.CSV, etc. // char filename[] = "LOGGER00.CSV"; for (uint8_t ifile = 0; ifile < 100; ifile++) { filename[6] = ifile/10 + '0'; filename[7] = ifile%10 + '0'; if (! SD.exists(filename)) { // only open a new file if it doesn't exist logfile = SD.open(filename, FILE_WRITE); break; // leave the loop! } } if (! logfile) { error("couldnt create file"); } Printout("logger_temperature"); Printout(" Version: "); Printout(VERSIONID); Printout(" Logging to: "); Printout(filename); Printout("\n"); // note some details for performance // Printout("millis,stamp,datetime,therm1,therm2,therm3,therm4,ds18b20_1,ds18b20_2"); /* /* Printout(",ANALOG_READ_DELAY = "); Printout(String(ANALOG_READ_DELAY)); Printout(",SYNC_INTERVAL = "); Printout(String(SYNC_INTERVAL)); Printout(",LOG_INTERVAL = "); Printout(String(LOG_INTERVAL)); Printout(",ECHO_TO_SERIAL = "); Printout(String(ECHO_TO_SERIAL)); Printout("\n"); */ // connect to RTC Wire.begin(); if (!RTC.begin()) { Serial.print("RTC failed"); } if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); } } void loop(void) ///////////////////////////////////////////////////////////////////////////////////////// { DateTime now; int sensorValue; int i; float voltage; float temperature_thermistor[N_THERMISTORS]; digitalWrite(yellowLEDpin, HIGH); // delay for the amount of time we want between readings delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL)); digitalWrite(yellowLEDpin, LOW); digitalWrite(greenLEDpin, HIGH); // log milliseconds since starting uint32_t m = millis(); Printout(String(m)); Printout(", "); // fetch the time now = RTC.now(); Printout(String(now.unixtime())); // seconds since 1/1/1970 Printout(","); // no space after comma! //Printout(String('"')); Printout(String(now.year(), DEC)); Printout("/"); Printout(String(now.month(), DEC)); Printout("/"); Printout(String(now.day(), DEC)); Printout(" "); Printout(String(now.hour(), DEC)); Printout(":"); Printout(String(now.minute(), DEC)); Printout(":"); Printout(String(now.second(), DEC)); //Printout(String('"')); Printout(", "); for(i=0;i<=N_THERMISTORS-1;i++) { // get temperature via Vishay thermistor delay(ANALOG_READ_DELAY); sensorValue = analogRead(Thermistor_Pin[i]); voltage=5.0*sensorValue/1023.0; temperature_thermistor[i] = CalculateTemperatureThermistor(voltage); char buffer[10]; // Serial.print(temperature_thermistor[i],DEC)); dtostrf(temperature_thermistor[i], 6, 2, buffer); Printout(buffer); Printout(","); } char buffer[10]; dtostrf(DS18B20_TemperatureSpecific(0), 6, 2, buffer); Printout(buffer); Printout(","); dtostrf(DS18B20_TemperatureSpecific(1), 6, 2, buffer); Printout(buffer); Printout(","); //Printout(" MemFree = "); Printout(String(freeRam())); Printout("\n"); digitalWrite(greenLEDpin, LOW); // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card // which uses a bunch of power and takes time if ((millis() - syncTime) < SYNC_INTERVAL) return; syncTime = millis(); // blink LED to show we are syncing data to the card & updating FAT! digitalWrite(redLEDpin, HIGH); logfile.flush(); digitalWrite(redLEDpin, LOW); } void Printout(String sValue) ///////////////////////////////////////////////////////////////////////////////////////// { logfile.print(sValue); #if ECHO_TO_SERIAL Serial.print(sValue); #endif // ECHO_TO_SERIAL } float CalculateTemperatureThermistor(float RawVoltage) ///////////////////////////////////////////////////////////////////////////////////////// { // connection is: // 5V ---- resistor -- X -- thermistor ----- GND // X is connection to analog input // Vishay NTCLE100E3103JB0 thermistor float lvalue; float dk; float vRatio; vRatio = RawVoltage / 5; float rValue; float thermResistance; float thermRefResistance; rValue = 9090; // resistance in ohms in series thermRefResistance = 10000; thermResistance = vRatio * rValue / (1 - vRatio); lvalue = log(thermResistance / thermRefResistance); dk = 1 / (0.003354016 + 0.000256985 * lvalue + 0.000002620131 * lvalue * lvalue + 0.00000006383091 * lvalue * lvalue * lvalue); return(dk - 273.15); // if(TempFlag==0) // { // // return temperature in C // return(dk - 273.15); // } // else // { // // return temperature in F // return(((dk - 273.15)*(9.0/5.0))+32.0); // } } ///////////////////////////////////////////////////////////////////////////////////////// int freeRam () { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } void Get_DS18B20_Addresses() // DS18B20 ///////////////////////////////////////////////////////////////////////////////////////// // Looking from bottom, flat at top // (used ascgen2 to create this picture!) // // ::::::i:::::i::r // @@::i:::i:i:i:::FB // U@ 2B // :B BO // B @ // @ pin1 pin2 pin3 XP // ,B Y@ // @ Bi // GB ,@ // BF .@ // B@ k@. // 7@Mr :NBq // :v77:iiLv7 // // pin1=GND, pin2=OUT, pin3=VCC; 4.7K resistor between pin 2 and pin 3 // Can run in 2 wire mode, but slower // { byte ic; byte present = 0; byte data[12]; byte addr[8]; Serial.print("ADDRESSES SEARCH :\n"); ds.reset_search(); nSensorCount=0; while (ds.search(addr)) { Serial.print("Sensor "); Serial.print(nSensorCount,0); Serial.print(" "); Serial.print("Address/CRC R="); for( ic = 0; ic < 8; ic++) { Serial.print(ic); Serial.print(":"); Serial.print(addr[ic], HEX); Serial.print(" "); } if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.print("ERROR\n"); Serial.print("CRC is not valid!\n"); return; } if ( addr[0] == 0x10) { // Serial.print("Device is a DS18S20 family device.\n"); } else if ( addr[0] == 0x28) { // Serial.print("Device is a DS18B20 family device.\n"); } else { Serial.print("ERROR\n"); Serial.print("Device family is not recognized: 0x"); Serial.println(addr[0],HEX); return; } // store the address StoreAddress(nSensorCount,addr); // increment number of sensors nSensorCount=nSensorCount+1; Serial.print("\n"); } Serial.print("No more addresses.\n"); ds.reset_search(); return; } /////////////////////////////////////////////////////// float DS18B20_TemperatureSpecific(int SensorNumber) { String cString=""; int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract; byte ic; byte present = 0; byte data[12]; byte addr[8]; // Get the address of the sensor ReturnAddress(SensorNumber,addr); ds.reset(); ds.select(addr); ds.write(0x44,1); // start conversion, with parasite power on at the end // do not need delay for 3 wire powered // 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); ds.write(0xBE); // Read Scratchpad // CRC //Serial.print("P="); //Serial.print(present,HEX); //Serial.print(" "); for ( ic = 0; ic < 9; ic++) { // we need 9 bytes data[ic] = ds.read(); // Serial.print(data[i], HEX); // Serial.print(" "); } //Serial.print(" CRC="); //Serial.print( OneWire::crc8( data, 8), HEX); //Serial.println(); // TEMP OUTPUT 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 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25 Whole = Tc_100 / 100; // separate off the whole and fractional portions Fract = Tc_100 % 100; if (SignBit) // If its negative { // Serial.print("-"); cString=cString+="-"; } //Serial.print(Whole); cString=cString+=Whole; //Serial.print("."); cString=cString+="."; if (Fract < 10) { //Serial.print("0"); cString=cString+="0"; } //Serial.print(Fract); cString=cString+=Fract; char str[10]; float tempval; cString.toCharArray(str, 10); tempval=atof(str); return tempval; } /////////////////////////////////////////////////////// void StoreAddress(int nSensor, byte found_address[]) { int i; // copy to area for( i = 0; i < 8; i++) { addr_list[nSensor][i]=found_address[i]; } } /////////////////////////////////////////////////////// void ReturnAddress(int nSensor, byte returned_address[]) { int i; for( i = 0; i < 8; i++) { returned_address[i]=addr_list[nSensor][i]; } }