I can read all the sensors, including the thermistor on A2, no problem. They all read OK and they all display OK on the LCD and on the Serial display.
If I compile the code so that it does not periodically measure A2, then everything works fine--I can open a log file on the SD card and write to it, no problem. I can set analogReference( EXTERNAL), set the pin to input, and read it once, also without problem.
On the other hand, if I compile the code with a regular polling of the analog pin, then I get a very bad behavior. When I try to access the SD card, the whole Arduino resets, and goes back, for sure into the setup() routine. This will happen continuously as long as I try to access the card.
I have no plausible explanation. The only one I can think of is that I burned the Atmega. If this happened, the mechanism was because I hooked the 3V source from the data logger shield to AREF and then set the analogReference( ) wrong.
Any ideas what I can do? Any help appreciated!
-Park
Schematic and code listing attached.
Code: Select all
/* File: RIMU_1.ino
* Date: December 31, 2011
*
* Description: This Arduino sketch is intended to drive a
* multi-sensor data logger based on an Arduino and a bunch
* of accessory cards. Please see the design document for
* the RIMU.1, which was stored in a file "ArduDataLogger".
*/
#include "Wire.h"
// These definitions control what content is included. Since sensors may be
// added and removed easily (especially during development). The initial set
// is just the DISPLAY and the SERIAL
#define SERIAL
#define RTC_ATTACHED
//#define BMP085_ATTACHED
//#define SENSIRON_ATTACHED
//#define THRMCPL_ATTACHED
//#define TSL2561_ATTACHED // Luminosity/Lux sensor
#define THERMISTOR_ATTACHED
#define DISPLAY_ATTACHED
//#define DHT_ATTACHED
#ifdef RTC_ATTACHED
#include <SD.h>
const int chipSelect = 10;
String dataString = "";
File dataFile;
const char *headerline="date.time,tcpl.c,thrmstr.c,thrmstr.r,bmp085.c,bmp085.p,ir,vis,dht.c,dht.h";
#include <RTClib.h>
RTC_DS1307 RTC;
DateTime timestamp;
#endif // RTC_ATTACHED
#ifdef BMP085_ATTACHED
#include "Adafruit_BMP085.h"
Adafruit_BMP085 bmp;
float bmp_temp_c_f = 0.0;
int32_t bmp_press_Pa_i32 = 0;
#endif // BMP085_ATTACHED
#ifdef DHT_ATTACHED
#include "DHT.h"
const unsigned char dhtpin = 6;
float dht_temp_c;
float dht_hum_pct;
#define DHTTYPE DHT22
#define DHT22_PIN 2
#endif // DHT_ATTACHED
#ifdef SENSIRON_ATTACHED
#endif // SENSIRON_ATTACHED
#ifdef TSL2561_ATTACHED // Luminosity/Lux sensor
#include <TSL2561.h>
// The address will be different depending on whether you let
// the ADDR pin float (addr 0x39), or tie it to ground or vcc. In those cases
// use TSL2561_ADDR_LOW (0x29) or TSL2561_ADDR_HIGH (0x49) respectively
TSL2561 tsl( TSL2561_ADDR_FLOAT);
uint16_t tsl2561_vis = 0;
uint16_t tsl2561_ir = 0;
uint32_t tsl2561_lum = 0;
#endif // TSL2561_ATTACHED
#ifdef THRMCPL_ATTACHED
#include <max6675.h>
const byte thrmcpl_D0 = 7; // D7
const byte thrmcpl_CS = 8; // D8
const byte thrmcpl_CLK = 9; // D9
MAX6675 thermocouple( thrmcpl_CLK, thrmcpl_CS, thrmcpl_D0);
float thrmcpl_temp_c_f = 0.0;
#endif
#ifdef THERMISTOR_ATTACHED
const uint16_t thrmstr_series_resistor = 10000; // measured to be 10.00 kOhm 2012-1-6
const byte thrmstr_pin = A2;
float thrmstr_reading;
float thrmstr_resistance_ohm;
float thrmstr_steinhart_temp_c;
const float thrmstr_res_nominal = 10000;
const float thrmstr_temp_nominal_c = 25;
const float thrmstr_b_coef = 3950;
const int thrmstr_num_samples = 1;
#endif // THERMISTOR_ATTACHED
#ifdef DISPLAY_ATTACHED
#include <LiquidCrystal.h>
int nWrite = 16;
// The address of mine is 0
LiquidCrystal lcd( 0);
/* From: http://www.quinapalus.com/hd44780udg.html
The degree symbol:
In decimal: 12,18,18,12,0,0,0
In hex: 0xc,0x12,0x12,0xc,0x0,0x0,0x0
In binary: %1100,%10010,%10010,%1100,%0,%0,%0
*/
unsigned char degree[8] = {0x0c,0x12,0x12,0x0c,0x00,0x00,0x00};
unsigned char ell_logoff[8] = {0x12,0x15,0x15,0x12,0x10,0x10,0x1f};
unsigned char ell_logon[8] = {0x12,0x12,0x12,0x12,0x10,0x10,0x1f};
#endif // DISPLAY_ATTACHED
// Pin assignments
const int buttonDisplayPin = 3; // D3, Display on/off and state toggle
const int logSwitchPin = 2; // D2, Logging enable/disable toggle switch
const int debounceDelay_ms = 50;
char timeStr[] = "00/00 00:00:00";
/* A note on update interval variables
* an unsigned integer's range is 0 to 65,535 = (2^16) - 1. This
* is only a little more than 1 minute for millisecond counters.
* For display and button debounce, this is more than adequate, but
* I have used unsigned long values, which are good to 49.7 days. */
// Sensor control variables
unsigned long sensorsLastUpdateTime_ms = 0;
const unsigned int sensorsUpdateIntvl_ms = 1000;
// Logger control variables
boolean logEnabled = false;
byte logSwitchState = LOW;
byte logSwitchStateLast = LOW;
const unsigned long logUpdateIntvl_ms = 10000; //60000;
unsigned long logSwitchCheckTime_ms = 0;
unsigned long logLastUpdateTime_ms = 0;
// Display control variables
byte dispState;
boolean dispEnabled = false;
byte dispButtonState = LOW;
byte dispButtonStateLast = LOW;
unsigned long dispButtonCheckTime_ms = 0;
unsigned long dispButtonTime_ms = 0;
unsigned long dispLastUpdateTime_ms = 0;
const unsigned int dispUpdateIntvl_ms = 1000;
const unsigned int dispOnDuration_ms = 20000;
enum {S_TCPL_OR_HUM, S_LUM_IR, S_LUM_VIS, S_BAROM, S_TMIST, S_DHT, S_NUMSENS};
unsigned long timeSince_ms( unsigned long tcomp){
// This function deal with wrap-around on the millis() clock. It can
// It can only handle a single wrap, of course
unsigned long tnow = millis();
if( tnow < tcomp)
return( tnow + 4294967295 - tcomp);
return( tnow - tcomp);
}
int tenthsPlace(float x){
// ToDo: update this to support rounding
return int( x*10) - int( x)*10;
}
#ifdef DHT_ATTACHED
DHT dht( dhtpin, DHTTYPE);
#endif
#ifdef DISPLAY_ATTACHED
void dumplcd( int nWrite){ // Writes nWrite blank spaces to the LCD
while( nWrite > 0) nWrite -= lcd.print( " ");
}
#endif
/////////////////////////////////////////////////////////////////////////
///// setup
/////////////////////////////////////////////////////////////////////////
void setup(){
delay( 200);
pinMode( buttonDisplayPin, INPUT);
pinMode( logSwitchPin, INPUT);
Wire.begin();
#ifdef SERIAL
Serial.begin( 9600);
#endif // SERIAL
#ifdef RTC_ATTACHED
RTC.begin();
// following line sets the RTC to the date & time this sketch was compiled
if( ! RTC.isrunning()){
RTC.adjust( DateTime( __DATE__, __TIME__));
}
pinMode( SS, OUTPUT);
pinMode( chipSelect, OUTPUT);
delay( 20);
if( !SD.begin( chipSelect)){
#ifdef SERIAL
Serial.println("Card failed, or not present");
#endif // SERIAL
return; // abort!
}
#endif // RTC_ATTACHED
#ifdef BMP085_ATTACHED
bmp.begin();
#endif // BMP085_ATTACHED
#ifdef SENSIRON_ATTACHED
#endif // SENSIRON_ATTACHED
#ifdef TSL2561_ATTACHED // Luminosity/Lux sensor
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
//tsl.setGain(TSL2561_GAIN_0X); // set no gain (for bright situtations)
tsl.setGain(TSL2561_GAIN_16X); // set 16x gain (for dim situations)
// Changing the integration time gives you a longer time over which to sense light
// longer timelines are slower, but are good in very low light situtations!
tsl.setTiming( TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright light)
//tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium light)
//tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim light)
#endif // TSL2561_ATTACHED
#ifdef THRMCPL_ATTACHED
// No actions required, possibly except delay(500)
#endif // THRMCPL_ATTACHED
#ifdef THERMISTOR_ATTACHED
// Assumming you follow the adafruit tutorial for the 3.3 V hookup, and reduced noise
analogReference( EXTERNAL);
pinMode( thrmstr_pin, INPUT);
#endif // THERMISTOR_ATTACHED
//analogReference( EXTERNAL);
//pinMode( A2, INPUT);
#ifdef DHT_ATTACHED
dht.begin();
#endif
#ifdef DISPLAY_ATTACHED
lcd.createChar( 0, degree); // access the character with lcd.write(0)
lcd.createChar( 1, ell_logon);
lcd.createChar( 2, ell_logoff);
// set up the LCD's number of rows and columns:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(0,0);
nWrite = 16;
nWrite -= lcd.print("RIMU.1");
dumplcd( nWrite);
lcd.setCursor(0,1);
nWrite = 16;
nWrite -= lcd.print("Park Hays");
dumplcd( nWrite);
#endif // DISPLAY_ATTACHED
#ifdef SENSIRON_ATTACHED
#endif // SENSIRON_ATTACHED
}
/////////////////////////////////////////////////////////////////////////
///// loop
/////////////////////////////////////////////////////////////////////////
void loop(){
/**********************************************************************************************/
// Read the Clock and Sensors, if enough time has elapsed for it
// ToDo: Decide if anything has changed (display or log, and the sensor read timer has fired
// and only update if there is some reason to do so. This might be laggy on the display,
// and would only be sensible if the system is in a power saving mode.
if( timeSince_ms( sensorsLastUpdateTime_ms) > sensorsUpdateIntvl_ms){
// read all the sensors, starting with the clock
#ifdef RTC_ATTACHED
timestamp = RTC.now();
timeStr[0] = timestamp.month()/10 + '0';
timeStr[1] = timestamp.month()%10 + '0';
timeStr[3] = timestamp.day()/10 + '0';
timeStr[4] = timestamp.day()%10 + '0';
timeStr[6] = timestamp.hour()/10 + '0';
timeStr[7] = timestamp.hour()%10 + '0';
timeStr[9] = timestamp.minute()/10 + '0';
timeStr[10]= timestamp.minute()%10 + '0';
timeStr[12]= timestamp.second()/10 + '0';
timeStr[13]= timestamp.second()%10 + '0';
#ifdef SERIAL
Serial.println( timeStr);
#endif // SERIAL
#endif // RTC_ATTACHED
#ifdef BMP085_ATTACHED
bmp_temp_c_f = bmp.readTemperature(); // returns temp in C
bmp_press_Pa_i32 = bmp.readPressure(); // returns pressure in Pa
#ifdef SERIAL
/*Serial.print("BMP085 Data: ");
Serial.print(bmp_temp_c_f, DEC);
Serial.print(" C, ");
Serial.print(bmp_press_Pa_i32, DEC);
Serial.println(" Pa");*/
#endif // SERIAL
#endif // BMP085_ATTACHED
#ifdef SENSIRON_ATTACHED
#endif // SENSIRON_ATTACHED
#ifdef TSL2561_ATTACHED // Luminosity/Lux sensor
// Simple data read example. Just read the infrared, fullspecrtrum diode
// or 'visible' (difference between the two) channels.
// This can take 13-402 milliseconds! Uncomment whichever of the following you want to read
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16
// bits full spectrum. That way you can do whatever math and comparions you want!
// ToDo: Put this in a loop to increase integration time until the result is appropriate
tsl2561_lum = tsl.getFullLuminosity();
tsl2561_vis = tsl2561_lum & 0xFFFF;
tsl2561_ir = tsl2561_lum >> 16;
#ifdef SERIAL
/*Serial.print("TSL2561 (Luminosity) Data: ");
Serial.print(tsl2561_vis, DEC);
Serial.print(" lx Vis, ");
Serial.print(tsl2561_ir, DEC);
Serial.println(" lx IR");*/
#endif // SERIAL
#endif // TSL2561_ATTACHED
#ifdef THRMCPL_ATTACHED
thrmcpl_temp_c_f = thermocouple.readCelsius();
#ifdef SERIAL
/*Serial.print("Thermocouple (MAX6671) Data: ");
Serial.print(thrmcpl_temp_c_f, DEC);
Serial.println(" C");*/
#endif // SERIAL
#endif // THRMCPL_ATTACHED
#ifdef THERMISTOR_ATTACHED
thrmstr_reading = 0.;
//thrmstr_reading += analogRead( thrmstr_pin);
for( int i = 0; i < thrmstr_num_samples; i++){
thrmstr_reading += (float)analogRead( thrmstr_pin);
delay( 10);
}
thrmstr_reading /= (float)thrmstr_num_samples;
thrmstr_resistance_ohm = (1023./thrmstr_reading) - 1;
thrmstr_resistance_ohm = thrmstr_series_resistor / thrmstr_resistance_ohm;
thrmstr_steinhart_temp_c = thrmstr_resistance_ohm / thrmstr_res_nominal;// (R/Ro)
thrmstr_steinhart_temp_c = log(thrmstr_steinhart_temp_c); // ln(R/Ro)
thrmstr_steinhart_temp_c /= thrmstr_b_coef; // 1/B * ln(R/Ro)
thrmstr_steinhart_temp_c += 1.0 / (thrmstr_temp_nominal_c + 273.15); // + (1/To)
thrmstr_steinhart_temp_c = 1.0 / thrmstr_steinhart_temp_c ; // Invert
thrmstr_steinhart_temp_c -= 273.15; // convert to C
#ifdef SERIAL
Serial.print("Thermistor analog reading ");
Serial.println( thrmstr_reading, DEC);
Serial.print("Thermistor Data: ");
Serial.print(thrmstr_steinhart_temp_c, DEC);
Serial.println(" C");
#endif // SERIAL
#endif // THERMISTOR_ATTACHED
#ifdef DHT_ATTACHED
dht_hum_pct = dht.readHumidity();
dht_temp_c = dht.readTemperature();
dht.begin();
#ifdef SERIAL
Serial.print("DHT Humidity ");
Serial.println( dht_hum_pct, DEC);
Serial.print("DHT Temperature ");
Serial.print(dht_temp_c, DEC);
Serial.println(" C");
#endif // SERIAL
#endif // DHT_ATTACHED
#ifdef SENSIRON_ATTACHED
#endif // SENSIRON_ATTACHED
// capture the time
sensorsLastUpdateTime_ms = millis();
}
/**********************************************************************************************/
// Handle the display control button
if( timeSince_ms( dispButtonCheckTime_ms) > debounceDelay_ms){
dispButtonState = digitalRead( buttonDisplayPin);
dispButtonCheckTime_ms = millis();
// someone pushed the button
if( (dispButtonState == LOW) && (dispButtonStateLast == HIGH)){
// reset the start time
dispButtonTime_ms = millis();
#ifdef SERIAL
Serial.println("Someone pushed the DISPLAY button");
if( dispEnabled){
Serial.println("The display is ENABLED");
Serial.print("Current display state: ");
Serial.println(dispState);
}else{
Serial.println("The display is DISABLED");
}
#endif // SERIAL
#ifdef DISPLAY_ATTACHED
// increment the display state
if( dispEnabled){
lcd.display();
dispState ++;
dispState %= S_NUMSENS;
}
else{
dispEnabled = true;
// hack should cause the display processing to update on the first try,
// no matter what the old data contained
lcd.display();
dispLastUpdateTime_ms = millis();
}
#endif // DISPLAY_ATTACHED
}
dispButtonStateLast = dispButtonState;
}
/**********************************************************************************************/
// Display Handling
// test for timeout, should I shut off the display?
if( dispEnabled & (timeSince_ms( dispButtonTime_ms) > dispOnDuration_ms)){
// Turn off the LED
// lcd.noDisplay();
// Change the state
dispEnabled = false;
}
// Update the display if enough time has passed or if the input has changed
else if( timeSince_ms( dispLastUpdateTime_ms) > dispUpdateIntvl_ms){
#ifdef SERIAL
//Serial.println("Updating Display");
#endif // SERIAL
#ifdef DISPLAY_ATTACHED
lcd.display();
lcd.setCursor(0,0);
nWrite = 16;
#ifdef RTC_ATTACHED
// Update the clock (first line of display)
nWrite -= lcd.print(timeStr);
dumplcd( nWrite -1);
if( logEnabled){
lcd.write( (uint8_t)1);
}else{
lcd.write( (uint8_t)2);
}
#else
nWrite -= lcd.print("RTC Not Attached");
dumplcd( nWrite);
#endif // RTC_ATTACHED
// Update the sensor output (line 2)
lcd.setCursor(0,1);
nWrite = 16;
// Gather & format error codes, if any
switch(dispState){
case S_TCPL_OR_HUM:
#ifdef SENSIRON_ATTACHED
nWrite -= lcd.print( "Sensiron Not Impl");
dumplcd( nWrite);
#endif // SENSIRON_ATTACHED
#ifdef THRMCPL_ATTACHED
nWrite -= lcd.print( thrmcpl_temp_c_f);
nWrite -= lcd.write( (uint8_t)0);
nWrite -= lcd.print( 'C T-CPL');
dumplcd( nWrite);
#else // no sensor attached
nWrite -= lcd.print( "No Humid/T-CPL");
dumplcd( nWrite);
#endif // THRMCPL_ATTACHED
break;
case S_LUM_IR:
#ifdef TSL2561_ATTACHED
nWrite -= lcd.print( tsl2561_ir, DEC);
nWrite -= lcd.print(" lx IR");
dumplcd( nWrite);
#else
nWrite -= lcd.print("No IR Sensor");
dumplcd( nWrite);
#endif // TSL2561_ATTACHED
break;
case S_LUM_VIS:
#ifdef TSL2561_ATTACHED
nWrite -= lcd.print(tsl2561_vis, DEC);
nWrite -= lcd.print(" lx vis");
dumplcd( nWrite);
#else
nWrite -= lcd.print("No Vis Sensor");
dumplcd( nWrite);
#endif // TSL2561_ATTACHED
break;
case S_BAROM:
#ifdef BMP085_ATTACHED
nWrite -= lcd.print( int(bmp_temp_c_f), DEC);
nWrite -= lcd.print(".");
nWrite -= lcd.print( tenthsPlace( bmp_temp_c_f), DEC); //)int( bmp_temp_c_f*10) - int( bmp_temp_c_f)*10, DEC); // won't get a 0
nWrite -= lcd.write((uint8_t)0); // write the degree symbol (custom char 0)
nWrite -= lcd.print("C ");
nWrite -= lcd.print( bmp_press_Pa_i32/100, DEC);
nWrite -= lcd.print( ".");
nWrite -= lcd.print( tenthsPlace(float(bmp_press_Pa_i32)/100));
nWrite -= lcd.print( " mb");
dumplcd( nWrite);
#else
nWrite -= lcd.print("No Press Sensor");
dumplcd( nWrite);
#endif // BMP085_ATTACHED
break;
case S_TMIST:
#ifdef THERMISTOR_ATTACHED
nWrite -= lcd.print( thrmstr_steinhart_temp_c);
nWrite -= lcd.write((uint8_t)0);
nWrite -= lcd.print("C t-mist");
dumplcd( nWrite);
#else
nWrite -= lcd.print("No Thermistor");
dumplcd( nWrite);
#endif // THERMISTOR_ATTACHED
break;
case S_DHT:
#ifdef DHT_ATTACHED
#ifdef SERIAL
Serial.println( "S_DHT");
#endif
// check if returns are valid, if they are NaN (not a number) then something went wrong!
nWrite -= lcd.print( "Hum ");
nWrite -= lcd.print( dht_hum_pct, 1);
nWrite -= lcd.print( "% ");
nWrite -= lcd.print( dht_temp_c*9./5 + 32., 1);
nWrite -= lcd.print( "F");
dumplcd( nWrite);
#endif // DHT_ATTACHED
break;
}
#endif // DISPLAY_ATTACHED
dispLastUpdateTime_ms = millis();
}
/**********************************************************************************************/
// Log switch handling
if( timeSince_ms( logSwitchCheckTime_ms) > debounceDelay_ms){
logSwitchStateLast = logSwitchState;
logSwitchState = digitalRead( logSwitchPin);
//Serial.print( "Current log switch state: ");
//Serial.println( logSwitchState);
}
/**********************************************************************************************/
// Log handling
if( logEnabled == false && logSwitchState == HIGH){ // log start
#ifdef SERIAL
Serial.println( "Log: opening log file and starting log");
delay( 100);
#endif // SERIAL
// Find a fresh filename and open it
char filename[] = "RIMU_00.CSV";
for( uint8_t i = 0; i < 100; i++){
filename[5] = i/10 + '0';
filename[6] = i%10 + '0';
Serial.print("testing existence of file ");
Serial.println( filename);
delay( 50);
if( ! SD.exists( filename )){
#ifdef SERIAL
Serial.print("Opening file: ");
Serial.println( filename);
#endif // SERIAL
dataFile = SD.open( filename, FILE_WRITE);
break;
}
}
if( dataFile){
// write a header
dataFile.println( headerline );
#ifdef SERIAL
Serial.print("ToFile: ");
Serial.println( headerline);
#endif // SERIAL
}
// force the last state change, so we don't end up in here next loop
logEnabled = true;
logLastUpdateTime_ms = millis();
}
else if( logEnabled && (logSwitchState == HIGH)){ // log continue
if( timeSince_ms( logLastUpdateTime_ms) > logUpdateIntvl_ms){
#ifdef SERIAL
Serial.println( "Log: Appending record to log");
#endif // SERIAL
// write a record
if( dataFile){
// "date.time,tcpl.c,thrmstr.c,thrmstr.r,bmp085.c,bmp085.p,ir,vis"
dataFile.print( timestamp.year());
dataFile.print( '/');
dataFile.print( timeStr);
dataFile.print( ',');
//dataFile.print( thrmcpl_temp_c_f);
dataFile.print( ',');
// thermistor temperature and resistance estimate
#ifdef THERMISTOR_ATTACHED
dataFile.print( thrmstr_steinhart_temp_c);
dataFile.print( ',');
dataFile.print( thrmstr_resistance_ohm);
dataFile.print( ',');
#endif // THERMISTOR_ATTACHED
// bmp085 temperature
#ifdef BMP085_ATTACHED
dataFile.print( bmp_temp_c_f);
dataFile.print( ',');
dataFile.print( bmp_press_Pa_i32);
dataFile.print( ',');
#endif // BMP085_ATTACHED
// luminosity data
#ifdef TSL2561_ATTACHED
dataFile.print(tsl2561_ir);
dataFile.print( ',');
dataFile.print(tsl2561_vis);
#endif // TSL25561_ATTACHED
// DHT data
#ifdef DHT_ATTACHED
dataFile.print( dht_temp_c);
dataFile.print( ',');
dataFile.println( dht_hum_pct);
#endif // DHT_ATTACHED
}
// capture the time
logLastUpdateTime_ms = millis();
}
}
else if( (logEnabled == true) && (logSwitchState == LOW)){ // log end
#ifdef SERIAL
Serial.println( "Log: Closing log file");
#endif // SERIAL
if( dataFile){
// write end-of-logging by switch record
dataFile.println( "# Log closed");
// close file
dataFile.close();
}
logEnabled = false;
}
}