Feed on
Posts
Comments

Welcome to Part 2, here we’ll test our implemented code out on the Arduino for a proof of concept. As you’ll recall the Standalone Temperature Logger’s function is to record temperature every x minutes defined by the user and log this to the EEPROM.

The code is fairly simple and will be explained in this post. What hasn’t been coded is my implementation of a simpler 2 Wire protocol as this actually requires an ATtiny85, so I’d like to make sure the code is functional before continuing.

You can download this test on the Arduino here: Standalone Temperature Logger Test on Arduino

Let’s begin.

#include <math.h>
#include <EEPROM.h>

int ledPin = 13;
int thermistorPin = 0;
int buttonPin = 2;

int functionSelect = 0;
int dataCount = 1;
int delayTime = -1;

void setup() {
 pinMode(ledPin, OUTPUT);
 pinMode(buttonPin, INPUT);
}

We have the usual setup here, functionSelect is used to select whether the device is logging the temperature, changing the logging delay, reading the EEPROM data (to be implemented) or idle.

dataCount points to start of the EEPROM address when logging starts, this begins with 1 because address 0 is used to store the delayTime variable.

delayTime tells us what delay there will be between each temperature recording and only goes up to 10. For 0, the delay would be 1 minute, 1 would be 5 minutes and so on:
0 = 1min, 1 = 5mins, 2 = 10mins, 3 = 15mins, 4 = 30mins, 5 = 1hr, 6 = 2hr, 7 = 4hr, 8 = 8 hr, 9 = 12hr, 10 = 24hr

void loop() {

 // Wait for input
 if (functionSelect == 0) {

 // Read delay time
 if (delayTime == -1) {
   delayTime = EEPROM.read(0);
   if (delayTime > 10) { // Not a normal value
     delayTime = 0;
   }
 }

We begin the loop, we go straight to the idle mode where we read the delayTime from the EEPROM and we know it’s always going to be at address 0. If this is the first time the program on the microcontroller then we don’t know what could be on the EEPROM, so if it’s more than 10 just make the delay 0.

    // Check button press, if still pressed after 500ms, check again
    // after 1500ms, if still pressed go to configuration
    int buttonState = digitalRead(buttonPin);
    if (buttonState == HIGH) {
      delay(500);
      buttonState = digitalRead(buttonPin);
      if (buttonState == true) {
        delay(1500);
        buttonState = digitalRead(buttonPin);
        if (buttonState == HIGH) {
          functionSelect = 2;
          delayTime = -1;
          digitalWrite(ledPin, HIGH);
          delay(2000);
          digitalWrite(ledPin, LOW);
        }
      }
      else {
        functionSelect = 1;
        for (int x = 0; x < 3; x++) {
          digitalWrite(ledPin, HIGH);
          delay(500);
          digitalWrite(ledPin, LOW);
          delay(500);
        }
      }
    }
  }

We are still in our idle mode, we check for button presses and button holding. Once the button is pressed or held, we wait 500ms and check the button status again, this gives us enough time to determine where the user just pressed the button or they are still holding it. If it’s not pressed we jump directed to the else condition.

We do one last check after 1500ms sleep, if the button is pressed we go to re-setting of logging delay time, set delayTime to -1 (because 0 is a valid value) and then light the LED for 2 seconds to confirm we are entering this mode. If the button was just pressed, we enter the temperature data logging mode and confirm this with 3 short LED blinks.

  // Log Temperature
  if (functionSelect == 1) {
    int tempValue = int(Thermistor(analogRead(thermistorPin)));

    // Calculations to store -40C to 125C int to a single byte
    byte tempStore = tempValue + 130;
    if (tempValue <= -41) { // Temp is over min temp accepted
      tempStore = 90;
    }
    if (tempValue >= 126) { // Temp is over max temp accepted
      tempStore = 255;
    }

    // Write to EEPROM
    if (dataCount < 512) {
      EEPROM.write(dataCount, tempStore);
      dataCount++;
      if (dataCount < 512) {
        EEPROM.write(dataCount, 0); // So we know where to stop when extracting data
      }
    }
 }

We begin the logging temperature function which we just simply read an analog pin using the Thermistor function which is on the Arduino website. Now we calculate the actual byte to store in the EEPROM, you may remember this from Part 1, basically just add 130 to what ever the result from Thermistor() was.

Next we write to the EEPROM only if we haven’t reached the end address of 512. We increment the address but then also write the value 0 to the next address, this way we know when reading the EEPROM when to actually stop reading.

    // Calculate the delay time
    if (delayTime == 0) {
      delay(60000);
    }
    if (delayTime >= 1 && delayTime < 4) {
      delay((delayTime * 5) * 60000);
    }
    if (delayTime >= 4 && delayTime < 6) {
      delay(((delayTime-3) * 30) * 60000);
    }
    if (delayTime >= 6 && delayTime < 8) {
      delay(((delayTime-5) * 120) * 60000);
    }
    if (delayTime == 8) {
      delay(8 * 60 * 60000);
    }
    if (delayTime == 9) {
      delay(12 * 60 * 60000);
    }
    if (delayTime == 10) {
      delay(24 * 60 * 60000);
    }
  }

It’s time to sleep a certain amount of time, all just if conditions here so nothing exciting to see, then it loops back to another log of temperature.

  // Configure the delay time
  if (functionSelect == 2) {
    int buttonState = digitalRead(buttonPin);
    if (buttonState == HIGH) {
      delay(500);
      int buttonPressed = false;
      buttonState = digitalRead(buttonPin);
      if (buttonState == HIGH && delayTime >= 0) {
        delay(1500);
        buttonState = digitalRead(buttonPin);
        if (buttonState == HIGH) {
          functionSelect = 0;
          EEPROM.write(0, delayTime);
          for (int x = 0; x < 3; x++) {
            digitalWrite(ledPin, HIGH);
            delay(500);
            digitalWrite(ledPin, LOW);
            delay(500);
          }
        }
        else {
          buttonPressed = true;
        }
      }
      if (buttonState == LOW || buttonPressed == true) {
        delayTime++;
        digitalWrite(ledPin, HIGH);
        delay(500);
        digitalWrite(ledPin, LOW);

        if (delayTime > 10) { // Too many presses
          delayTime = -1;
          digitalWrite(ledPin, HIGH);
          delay(1500);
          digitalWrite(ledPin, LOW);
        }
      }
    }
  }
}

Here is the function to define the delay time, basically we just wait for the user to press the button a certain amount of times and that corresponds to the delayTime being incremented. We do what we did before, we check if the button was pressed, wait 500ms then check again after 1500ms only if the button has been pressed at least once before and if the button is still being held.

If neither condition is meet, then just incremeent the delayTime and blink the LED once. If there has been too many presses of the button over 10, then reset it back to -1 and hold the LED on for 1.5 seconds to show the user their value of delayTime wasn’t stored.

If the button is held after 1500ms, then write delayTime value to the EEPROM, blink the LED 3 times to confirm and go back to idle mode.

// Taken from http://www.arduino.cc/playground/ComponentLib/Thermistor2
double Thermistor(int RawADC) {
 double Temp;
 Temp = log(((10240000/RawADC) - 10000));
 Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
 Temp = Temp - 273.15;            // Convert Kelvin to Celcius
 return Temp;
}

And just for completeness here is the Thermistor function.

I set my Arduino up, configured it to log every minute, ran for a few minutes and here are the results I got once I read the EEPROM.
0    0
1    155
2    155
3    155
4    155
5    155
6    155
7    155
8    155
9    155
10    155
11    155
12    155
13    155
14    155
15    155
16    0

The first line shows the delayTime = 0 which is every minute logging, then we see the temperature value 155. We minus 130 from 155 to give us 25C. On address 16 we see a 0 which tells us this is the end of the temperature monitoring.

So it looks like it’s all working well :). In the next part we’ll hook up the ATtiny85, program it and hopefully also have my simple 2 wire connection implemented between the Arduino and ATtiny.

6 Responses to “Building a Standalone Temperature Logger: Part 2”

  1. Ed says:

    Extremely good project. Just one question though: How did you get the Steinhart parameters for yr NTC, i didnt think the Vishay website mentioned them 🙂

    • Alex says:

      Hi Ed,

      I found the equation at http://www.arduino.cc/playground/ComponentLib/Thermistor2 where it give the parameters for a 10K thermistor.

      Edit: I also found this calculator that can calculate the temperature or resistance based on 4 coefficients: http://www.daycounter.com/Calculators/Steinhart-Hart-Thermistor-Calculator.phtml

      There are 4 (K positive) coefficients for calculating resistance from temperature and 4 (K negative) coefficients for calculating temperature from resistance which can be found on page 4 of the Vishay Thermistor PDF: http://www.vishay.com/docs/29049/ntcle100.pdf

      Edit 2: Wikipedia says that the “C*ln(R/Rt)2” part of the equation is often left out: “because it is typically much smaller than the other coefficients”.

      So for a 10K thermistor from Vishay we should really use:
      Temp = 1 / (0.003354016 + (0.0002569850 * Temp) + (0.00000006383091 * Temp * Temp * Temp));

      However this will give weird results using the original Thermistor function because of how it finds the resistance, the 0.001129148 original coefficient being used actually divides our end result by 10,000 (which is the Resistance at ambient temperature Rt) and this gives us a correct result (try using 0.001129148 in the calculator and it gives weird results, however if you change the Rt value say from 10,000 to 1, then it gives good results).

      So really we should really use:
      double ThermisterReal(int RawADC) {
      double Temp;
      Temp = log(((10240000/RawADC) – 10000) / 10000); // Notice we divide by 10,000 too
      Temp = 1 / (0.003354016 + (0.0002569850 * Temp) + (0.00000006383091 * Temp * Temp * Temp));
      Temp = Temp – 273.15; // Convert Kelvin to Celcius
      return Temp;
      }

      The difference between the original Thermistor function and our is about 0.1 – 0.3C degrees difference between them depending on how far away you get from 25C degrees.

      I think this is worth doing a write up on, you’ve asked a good question 🙂

      Alex.

      Edit 2: Write up complete with a newer formula to use: http://www.insidegadgets.com/2011/12/18/verifying-the-thermistor-function-for-temperature-reading/
      Turns out the existing function was more than adequate.

  2. ashwin says:

    cool,but i dont have math.h library,can u mail it?

  3. Matt M says:

    Would you mind posting a schematic of you wiring setup for the arduino? I am having a hard time seeing the picture you posted with enough detail.

    Thanks,
    Matt

Leave a Reply