Max 31855 Reading High Temperatures

Breakout boards, sensors, Drawdio, Game of Life, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
jh421797
 
Posts: 7
Joined: Mon Jul 07, 2014 10:54 am

Re: Max 31855 Reading High Temperatures

Post by jh421797 »

I hooked up the cheap thermocouple:

Fluke 51 II : -78.0 degC
MAX31855 Std: -66.00 degC
MAX31855 Corr: -75.05 degC

That is interesting: ~3.0 degC difference btw Fluke & 31855 here and a ~0.5 degC difference with the better thermocouple above.

Is that about the difference you were getting with your cheapy?
- Jeff

User avatar
heypete
 
Posts: 32
Joined: Sat Jan 11, 2014 4:50 pm

Re: Max 31855 Reading High Temperatures

Post by heypete »

Interesting. Thanks for checking.

According to my wife my brain does garbage collection every few hours, so I have no detailed recollection of the values I measured last year when I compared the Fluke 51 II we had in the lab to the MAX31855. Your numbers sound reasonable.

User avatar
adafruit_support_bill
 
Posts: 84640
Joined: Sat Feb 07, 2009 10:11 am

Re: Max 31855 Reading High Temperatures

Post by adafruit_support_bill »


User avatar
heypete
 
Posts: 32
Joined: Sat Jan 11, 2014 4:50 pm

Re: Max 31855 Reading High Temperatures

Post by heypete »

adafruit_support_bill wrote:You folks are famous now :)
https://learn.adafruit.com/calibrating- ... earization
Woot!

Would it be possible to link to the calibration guide above from the MAX31855 tutorial page?

In regards to a previous message, I dug up my code where I originally implemented the corrections. It's a bit hackish, but overall very similar to Jeff's except for the following differences:

1. I take into account the possibility that the cold-junction temperature may be negative, as the chip may be located in a cold environment.
2. I store the NIST coefficients in arrays and iterate through them with loops.
3. It uses more flash and RAM. It's not remotely optimized and could be made more efficient.

Here's my code, sans the debug output from my earlier tests and with extra comments. My error handling is really bad, but the code works and produces the proper corrected output. It uses the BSD-licensed Adafruit library for the MAX31855. The code written by me is public domain.

Code: Select all

#include <SPI.h>
#include "Adafruit_MAX31855.h"

#define DO   12
#define CS   11
#define CLK  10
Adafruit_MAX31855 thermocouple(CLK, CS, DO);

void setup() {
	Serial.begin(9600);
	Serial.println("MAX31855 test");
	// wait for MAX chip to stabilize
	delay(500);
}
void loop() {
	// Initialize variables.
	int i = 0; // Counter for arrays
	double internalTemp = thermocouple.readInternal(); // Read the internal temperature of the MAX31855.
	double rawTemp = thermocouple.readCelsius(); // Read the temperature of the thermocouple. This temp is compensated for cold junction temperature.
	double thermocoupleVoltage= 0;
	double internalVoltage = 0;
	double correctedTemp = 0;

	 // Check to make sure thermocouple is working correctly.
	if (isnan(rawTemp)) {
    Serial.println("Something wrong with thermocouple!");
  }
	else {
		// Steps 1 & 2. Subtract cold junction temperature from the raw thermocouple temperature.
		thermocoupleVoltage = (rawTemp - internalTemp)*0.041276;  // C * mv/C = mV

		// Step 3. Calculate the cold junction equivalent thermocouple voltage.

		if (internalTemp >= 0) { // For positive temperatures use appropriate NIST coefficients
			// Coefficients and equations available from http://srdata.nist.gov/its90/download/type_k.tab

			double c[] = {-0.176004136860E-01,  0.389212049750E-01,  0.185587700320E-04, -0.994575928740E-07,  0.318409457190E-09, -0.560728448890E-12,  0.560750590590E-15, -0.320207200030E-18,  0.971511471520E-22, -0.121047212750E-25};

			// Count the the number of coefficients. There are 10 coefficients for positive temperatures (plus three exponential coefficients),
			// but there are 11 coefficients for negative temperatures.
			int cLength = sizeof(c) / sizeof(c[0]);

			// Exponential coefficients. Only used for positive temperatures.
			double a0 =  0.118597600000E+00;
			double a1 = -0.118343200000E-03;
			double a2 =  0.126968600000E+03;


			// From NIST: E = sum(i=0 to n) c_i t^i + a0 exp(a1 (t - a2)^2), where E is the thermocouple voltage in mV and t is the temperature in degrees C.
			// In this case, E is the cold junction equivalent thermocouple voltage.
			// Alternative form: C0 + C1*internalTemp + C2*internalTemp^2 + C3*internalTemp^3 + ... + C10*internaltemp^10 + A0*e^(A1*(internalTemp - A2)^2)
			// This loop sums up the c_i t^i components.
			for (i = 0; i < cLength; i++) {
				internalVoltage += c[i] * pow(internalTemp, i);
			}
				// This section adds the a0 exp(a1 (t - a2)^2) components.
				internalVoltage += a0 * exp(a1 * pow((internalTemp - a2), 2));
		}
		else if (internalTemp < 0) { // for negative temperatures
			double c[] = {0.000000000000E+00,  0.394501280250E-01,  0.236223735980E-04 - 0.328589067840E-06, -0.499048287770E-08, -0.675090591730E-10, -0.574103274280E-12, -0.310888728940E-14, -0.104516093650E-16, -0.198892668780E-19, -0.163226974860E-22};

			// Count the number of coefficients.
			int cLength = sizeof(c) / sizeof(c[0]);

			// Below 0 degrees Celsius, the NIST formula is simpler and has no exponential components: E = sum(i=0 to n) c_i t^i
			for (i = 0; i < cLength; i++) {
				internalVoltage += c[i] * pow(internalTemp, i) ;
			}
		}

		// Step 4. Add the cold junction equivalent thermocouple voltage calculated in step 3 to the thermocouple voltage calculated in step 2.
		double totalVoltage = thermocoupleVoltage + internalVoltage;

		// Step 5. Use the result of step 4 and the NIST voltage-to-temperature (inverse) coefficients to calculate the cold junction compensated, linearized temperature value.
		// The equation is in the form correctedTemp = d_0 + d_1*E + d_2*E^2 + ... + d_n*E^n, where E is the totalVoltage in mV and correctedTemp is in degrees C.
		// NIST uses different coefficients for different temperature subranges: (-200 to 0C), (0 to 500C) and (500 to 1372C).
		if (totalVoltage < 0) { // Temperature is between -200 and 0C.
			double d[] = {0.0000000E+00, 2.5173462E+01, -1.1662878E+00, -1.0833638E+00, -8.9773540E-01, -3.7342377E-01, -8.6632643E-02, -1.0450598E-02, -5.1920577E-04, 0.0000000E+00};

			int dLength = sizeof(d) / sizeof(d[0]);
			for (i = 0; i < dLength; i++) {
				correctedTemp += d[i] * pow(totalVoltage, i);
			}
		}
		else if (totalVoltage > 0 && totalVoltage < 20.644 ) { // Temperature is between 0C and 500C.
			double d[] = {0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08};
			int dLength = sizeof(d) / sizeof(d[0]);
			for (i = 0; i < dLength; i++) {
				correctedTemp += d[i] * pow(totalVoltage, i);
			}
		}
		else if (totalVoltage > 20.644 && totalVoltage < 54.886) { // Temperature is between 500C and 1372C.
			double d[] = {-1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08, 0.000000E+00, 0.000000E+00, 0.000000E+00};
			int dLength = sizeof(d) / sizeof(d[0]);
			for (i = 0; i < dLength; i++) {
				correctedTemp += d[i] * pow(totalVoltage, i);
			}
		} else { // NIST only has data for K-type thermocouples from -200C to +1372C. If the temperature is not in that range, set temp to impossible value.
			// Error handling should be improved.
			Serial.print("Temperature is out of range. This should never happen.");
			correctedTemp = NAN;
		}

		Serial.print("Corrected Temp = ");
		Serial.println(correctedTemp, 5);
		Serial.println("");

	}

	delay(1000);

}

User avatar
adafruit_support_bill
 
Posts: 84640
Joined: Sat Feb 07, 2009 10:11 am

Re: Max 31855 Reading High Temperatures

Post by adafruit_support_bill »

Sure, no problem. I had to wait for the tutorial to go live to post links to it. I added the links to the FAQ. I added your code to the last page of the calibration tutorial.

User avatar
heypete
 
Posts: 32
Joined: Sat Jan 11, 2014 4:50 pm

Re: Max 31855 Reading High Temperatures

Post by heypete »

adafruit_support_bill wrote:Sure, no problem. I had to wait for the tutorial to go live to post links to it. I added the links to the FAQ. I added your code to the last page of the calibration tutorial.
Fantastic, thanks!

User avatar
tonyhansen
 
Posts: 27
Joined: Fri Nov 29, 2013 12:37 am

Re: Max 31855 Reading High Temperatures

Post by tonyhansen »

The code on above by @heypete has a couple minor bugs in it. Specifically, what happens if the calculated value of totalVoltage came out as 0? Then each of the if/else-if statements would be ignored and the default at the end (with the print statement "This should never happen.") will be executed. (The same is true for the value 20.644, but that is less likely to occur because of floating point representations.) The fix is to change the >s to >=, or to remove the redundant tests entirely. That is, change the if/else-if tests to

if (totalVoltage < 0) {
} else if (totalVoltage < 20.644) {
} else if (totalVoltage < 54.886) {
} else {
}

User avatar
heypete
 
Posts: 32
Joined: Sat Jan 11, 2014 4:50 pm

Re: Max 31855 Reading High Temperatures

Post by heypete »

tonyhansen wrote:The code on above by @heypete has a couple minor bugs in it. Specifically, what happens if the calculated value of totalVoltage came out as 0? Then each of the if/else-if statements would be ignored and the default at the end (with the print statement "This should never happen.") will be executed. (The same is true for the value 20.644, but that is less likely to occur because of floating point representations.) The fix is to change the >s to >=, or to remove the redundant tests entirely. That is, change the if/else-if tests to

if (totalVoltage < 0) {
} else if (totalVoltage < 20.644) {
} else if (totalVoltage < 54.886) {
} else {
}
D'oh. You're right. I use >=s in the section for the internal temperature but erroneously use plain <s in the section for calculating the corrected temperature.

Removing the redundant checks also makes the code a teensy bit more efficient and saves a cycle or two on comparisons.

Good catch, and thank you.

User avatar
adafruit_support_bill
 
Posts: 84640
Joined: Sat Feb 07, 2009 10:11 am

Re: Max 31855 Reading High Temperatures

Post by adafruit_support_bill »

Hey heypete! If you post an update w/ the corrections, I'll see that it gets into the tutorial.

User avatar
heypete
 
Posts: 32
Joined: Sat Jan 11, 2014 4:50 pm

Re: Max 31855 Reading High Temperatures

Post by heypete »

adafruit_support_bill wrote:Hey heypete! If you post an update w/ the corrections, I'll see that it gets into the tutorial.
Here you go. I used tonyhansen's suggestion to remove the redundant comparisons.

Code: Select all

#include <SPI.h>
#include "Adafruit_MAX31855.h"

#define DO   12
#define CS   11
#define CLK  10
Adafruit_MAX31855 thermocouple(CLK, CS, DO);

void setup() {
   Serial.begin(9600);
   Serial.println("MAX31855 test");
   // wait for MAX chip to stabilize
   delay(500);
}
void loop() {
   // Initialize variables.
   int i = 0; // Counter for arrays
   double internalTemp = thermocouple.readInternal(); // Read the internal temperature of the MAX31855.
   double rawTemp = thermocouple.readCelsius(); // Read the temperature of the thermocouple. This temp is compensated for cold junction temperature.
   double thermocoupleVoltage= 0;
   double internalVoltage = 0;
   double correctedTemp = 0;

    // Check to make sure thermocouple is working correctly.
   if (isnan(rawTemp)) {
    Serial.println("Something wrong with thermocouple!");
  }
   else {
      // Steps 1 & 2. Subtract cold junction temperature from the raw thermocouple temperature.
      thermocoupleVoltage = (rawTemp - internalTemp)*0.041276;  // C * mv/C = mV

      // Step 3. Calculate the cold junction equivalent thermocouple voltage.

      if (internalTemp >= 0) { // For positive temperatures use appropriate NIST coefficients
         // Coefficients and equations available from http://srdata.nist.gov/its90/download/type_k.tab

         double c[] = {-0.176004136860E-01,  0.389212049750E-01,  0.185587700320E-04, -0.994575928740E-07,  0.318409457190E-09, -0.560728448890E-12,  0.560750590590E-15, -0.320207200030E-18,  0.971511471520E-22, -0.121047212750E-25};

         // Count the the number of coefficients. There are 10 coefficients for positive temperatures (plus three exponential coefficients),
         // but there are 11 coefficients for negative temperatures.
         int cLength = sizeof(c) / sizeof(c[0]);

         // Exponential coefficients. Only used for positive temperatures.
         double a0 =  0.118597600000E+00;
         double a1 = -0.118343200000E-03;
         double a2 =  0.126968600000E+03;


         // From NIST: E = sum(i=0 to n) c_i t^i + a0 exp(a1 (t - a2)^2), where E is the thermocouple voltage in mV and t is the temperature in degrees C.
         // In this case, E is the cold junction equivalent thermocouple voltage.
         // Alternative form: C0 + C1*internalTemp + C2*internalTemp^2 + C3*internalTemp^3 + ... + C10*internaltemp^10 + A0*e^(A1*(internalTemp - A2)^2)
         // This loop sums up the c_i t^i components.
         for (i = 0; i < cLength; i++) {
            internalVoltage += c[i] * pow(internalTemp, i);
         }
            // This section adds the a0 exp(a1 (t - a2)^2) components.
            internalVoltage += a0 * exp(a1 * pow((internalTemp - a2), 2));
      }
      else if (internalTemp < 0) { // for negative temperatures
         double c[] = {0.000000000000E+00,  0.394501280250E-01,  0.236223735980E-04 - 0.328589067840E-06, -0.499048287770E-08, -0.675090591730E-10, -0.574103274280E-12, -0.310888728940E-14, -0.104516093650E-16, -0.198892668780E-19, -0.163226974860E-22};

         // Count the number of coefficients.
         int cLength = sizeof(c) / sizeof(c[0]);

         // Below 0 degrees Celsius, the NIST formula is simpler and has no exponential components: E = sum(i=0 to n) c_i t^i
         for (i = 0; i < cLength; i++) {
            internalVoltage += c[i] * pow(internalTemp, i) ;
         }
      }

      // Step 4. Add the cold junction equivalent thermocouple voltage calculated in step 3 to the thermocouple voltage calculated in step 2.
      double totalVoltage = thermocoupleVoltage + internalVoltage;

      // Step 5. Use the result of step 4 and the NIST voltage-to-temperature (inverse) coefficients to calculate the cold junction compensated, linearized temperature value.
      // The equation is in the form correctedTemp = d_0 + d_1*E + d_2*E^2 + ... + d_n*E^n, where E is the totalVoltage in mV and correctedTemp is in degrees C.
      // NIST uses different coefficients for different temperature subranges: (-200 to 0C), (0 to 500C) and (500 to 1372C).
      if (totalVoltage < 0) { // Temperature is between -200 and 0C.
         double d[] = {0.0000000E+00, 2.5173462E+01, -1.1662878E+00, -1.0833638E+00, -8.9773540E-01, -3.7342377E-01, -8.6632643E-02, -1.0450598E-02, -5.1920577E-04, 0.0000000E+00};

         int dLength = sizeof(d) / sizeof(d[0]);
         for (i = 0; i < dLength; i++) {
            correctedTemp += d[i] * pow(totalVoltage, i);
         }
      }
      else if (totalVoltage < 20.644) { // Temperature is between 0C and 500C.
         double d[] = {0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08};
         int dLength = sizeof(d) / sizeof(d[0]);
         for (i = 0; i < dLength; i++) {
            correctedTemp += d[i] * pow(totalVoltage, i);
         }
      }
      else if (totalVoltage < 54.886 ) { // Temperature is between 500C and 1372C.
         double d[] = {-1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08, 0.000000E+00, 0.000000E+00, 0.000000E+00};
         int dLength = sizeof(d) / sizeof(d[0]);
         for (i = 0; i < dLength; i++) {
            correctedTemp += d[i] * pow(totalVoltage, i);
         }
      } else { // NIST only has data for K-type thermocouples from -200C to +1372C. If the temperature is not in that range, set temp to impossible value.
         // Error handling should be improved.
         Serial.print("Temperature is out of range. This should never happen.");
         correctedTemp = NAN;
      }

      Serial.print("Corrected Temp = ");
      Serial.println(correctedTemp, 5);
      Serial.println("");

   }

   delay(1000);

}

User avatar
adafruit_support_bill
 
Posts: 84640
Joined: Sat Feb 07, 2009 10:11 am

Re: Max 31855 Reading High Temperatures

Post by adafruit_support_bill »

Thanks! Updated.

User avatar
Declan
 
Posts: 11
Joined: Mon Aug 17, 2015 4:48 am

Re: Max 31855 Reading High Temperatures

Post by Declan »

Hi,
I have a Adafruit Thermocouple Amplifier MAX31855 breakout board.
As we only use J-Type thermocouples, I have replaced the MAX31855K with the MAX31855J.
Using the sketch provided, my temperature readings are approx +10 C higher that actual temperature being read.
I see from the MAX31855 datasheet that the Sensitivity of the K-Type is 41.276 (μV/°C) and the J-Type is 57.953 (μV/°C).
Where would I be able to change this in the sketch examples?
Is it possible to read the faults, if any, from the MAX31855?

User avatar
heypete
 
Posts: 32
Joined: Sat Jan 11, 2014 4:50 pm

Re: Max 31855 Reading High Temperatures

Post by heypete »

Declan wrote:Hi,
I have a Adafruit Thermocouple Amplifier MAX31855 breakout board.
As we only use J-Type thermocouples, I have replaced the MAX31855K with the MAX31855J.
Using the sketch provided, my temperature readings are approx +10 C higher that actual temperature being read.
I see from the MAX31855 datasheet that the Sensitivity of the K-Type is 41.276 (μV/°C) and the J-Type is 57.953 (μV/°C).
Where would I be able to change this in the sketch examples?
Is it possible to read the faults, if any, from the MAX31855?
In my sketch you'd need to change

Code: Select all

thermocoupleVoltage = (rawTemp - internalTemp)*0.041276;
to

Code: Select all

thermocoupleVoltage = (rawTemp - internalTemp)*0.057953;
Additionally, you would need to change several aspects of the calculations:
- The NIST formula for K-type thermocouples defines coefficients to calculate the expected thermocouple voltage for a given temperature for two temperature ranges -270C to 0C and 0C to +1372C. J-type thermocouples have ranges from -270C to +760C and +760C to 1200C. The number of and values of the coefficients differ for each type. See here for details.
- The NIST formula also has exponential terms for K-type but not for J-type. The exponential terms would need to be removed for computing results with J-type thermocouples.
- NIST also defines reverse coefficients (for converting mV to degrees) for both types. As above, the temperature ranges and coefficients differ.

If you have any issues, let me know. I'd be happy to edit the code so should work for J-type thermocouples, but I have no way of testing it since I don't have any thermocouples of that type. If you're willing to be the guinea pig and do some tests, that'd be cool. :)

User avatar
Declan
 
Posts: 11
Joined: Mon Aug 17, 2015 4:48 am

Re: Max 31855 Reading High Temperatures

Post by Declan »

heypete,
Thanks for your reply - I have looked at our code and it looks awesome.
However,

Code: Select all

Additionally, you would need to change several aspects of the calculations:
is way over my head...

I would be more than happy to be the guinea pig as I would learn loads and hopefully others would be able to benefit.

User avatar
Declan
 
Posts: 11
Joined: Mon Aug 17, 2015 4:48 am

Re: Max 31855 Reading High Temperatures

Post by Declan »

Sorry, I forgot to mention that I am only reading positive temperatures in the range 0 - 400 C

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”