So I have been working all day interfacing the MAX6675 Mixed-signal and digital signal processing ICs | Analog Devices Thermocouple to Digital Converter. It took me a bit to learn some basic SPI, but I think I have it down now for this chip. This chip is great and seems to work ok right now. It to me awhile to get all the conversions right, but things are looking good now.
The only thing I am still having problems with is the Open Thermocouple detection on Bit 2. It always seems to return 0 Please let me know if you have any idea what is going on.
I hope to get this polished and up on the playground and my own site soon. Maybe make a library? Please give me your feedback!
/*
Temperature Reading from a MAX6675
Ryan McLaughlin <ryanjmclaughlin@gmail.com>
*/
#define SO 12 // MISO
#define SCK 13 // Serial Clock
#define TC_0 11 // CS Pin of MAX6607
int TC_0_calib = 0; // Calibration compensation value in digital counts (.25[ch730]C)
void setup() {
pinMode(SO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(TC_0, OUTPUT);
digitalWrite(TC_0,HIGH); // Disable device
Serial.begin(9600);
}
/* Create a function read_temp that returns an unsigned int
with the temp from the specified pin (if multiple MAX6675). The
function will return 9999 if the TC is open.
Usage: read_temp(int pin, int type, int error)
pin: the CS pin of the MAX6675
type: 0 for [ch730]F, 1 for [ch730]C
error: error compensation in digital counts
samples: number of measurement samples (max:10)
*/
unsigned int read_temp(int pin, int type, int error, int samples) {
unsigned int value = 0;
int error_tc;
float temp;
unsigned int temp_out;
for (int i=samples; i>0; i--){
digitalWrite(pin,LOW); // Enable device
/* Cycle the clock for dummy bit 15 */
digitalWrite(SCK,HIGH);
digitalWrite(SCK,LOW);
/* Read bits 14-3 from MAX6675 for the Temp
Loop for each bit reading the value and
storing the final value in 'temp'
*/
for (int i=11; i>=0; i--){
digitalWrite(SCK,HIGH); // Set Clock to HIGH
value += digitalRead(SO) << i; // Read data and add it to our variable
digitalWrite(SCK,LOW); // Set Clock to LOW
}
/* Read the TC Input inp to check for TC Errors */
digitalWrite(SCK,HIGH); // Set Clock to HIGH
error_tc = digitalRead(SO); // Read data
digitalWrite(SCK,LOW); // Set Clock to LOW
digitalWrite(pin, HIGH); //Disable Device
}
value = value/samples; // Divide the value by the number of samples to get the average
/*
Keep in mind that the temp that was just read is on the digital scale
from 0[ch730]C to 1023.75[ch730]C at a resolution of 2^12. We now need to convert
to an actual readable temperature (this drove me nuts until I figured
this out!). Now multiply by 0.25. I tried to avoid float math but
it is tough to do a good conversion to [ch730]F. THe final value is converted
to an int and returned at x10 power.
*/
value = value + error; // Insert the calibration error value
if(type == 0) { // Request temp in [ch730]F
temp = ((value*0.25) * (9.0/5.0)) + 32.0; // Convert value to [ch730]F (ensure proper floats!)
} else if(type == 1) { // Request temp in [ch730]C
temp = (value*0.25); // Multiply the value by 25 to get temp in [ch730]C
}
temp_out = temp*10; // Send the float to an int (X10) for ease of printing.
/* Output 9999 if there is a TC error, otherwise return 'temp' */
if(error_tc != 0) { return 9999; } else { return temp_out; }
}
void loop() {
// Read the temperature and print it to serial
Serial.print("Temp F: ");
Serial.print(read_temp(TC_0,0,TC_0_calib,10));
Serial.print("\tTemp C: ");
Serial.println(read_temp(TC_0,1,TC_0_calib,10));
delay(250);
}
This is great! I think a library would be excellent.
I'm curious what you're planning to use the temperature measurement for? Also what kind of accuracy are you seeing from the MAX6675?
I've been using an AD595CQ with a thermocouple to make a general purpose kitchen appliance controller, using a relay. It makes it easy to set the temperature of a water bath for various types of cooking, or control a hot pad for dough proofing, etc. I'm interested in the MAX because it's both cheaper and promises higher accuracy, which I could actually use for some more finicky stuff.
Glad you can use it, I will post when I refine the Code a bit more. I am going to be using it for a temp control ( search ac dimming for the power side of it ).
I was getting fairly good accuracy, within a degree or so out of the box without adding any calibration, however I have not checked it over the full range.
It is very nice that is is cheaper, I plan to have 4 on a board and I can do it without a multiplexer cause there cheap. (6.60ea for 25)
In file included from /Applications/arduino-0012/hardware/cores/arduino/WProgram.h:4,
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:80: error: expected unqualified-id before 'int'
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:80: error: expected `)' before 'int'
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:80: error: expected `)' before 'int'
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:111: error: expected unqualified-id before 'int'
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:111: error: expected `)' before 'int'
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:111: error: expected `)' before 'int'
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:144: error: expected identifier before '(' token
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:144: error: expected `)' before '(' token
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:144: error: expected ',' or '...' before '(' token
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:144: error: expected initializer before ')' token
/Applications/arduino-0012/hardware/tools/avr/bin/../lib/gcc/avr/4.3.0/../../../../avr/include/stdlib.h:176: error: '__compar_fn_t' has not been declared
In file included from /Applications/arduino-0012/hardware/cores/arduino/WProgram.h:6,
Ryanjmclaughlin, I looked on Maxim Direct and it says $15.00. But on Sparkfun it's only $12. Can you please give me the link where you got it from? Thanks
It seems like they have raised their prices since the last time I got them. Most recently I bought some larger quantities from Newark.
Sparkfun is the cheapest for single quantities. I really love those guys!
You can also pick them up on my site http://ryanjmclaughlin.com/shop/max6675-thermocouple-to-digital-chip/ I have also created some breakout boards for the chip that are for sale as well. Check it out ryanjmclaughlin.com. Use "NewCustomer" at checkout for 10% off an order through the end of the month.
// if bit 3 is high thermocouple is unconnected
if (lowByte & (1<<2)) { Serial.print("Not connected "); Serial.print(highByte, HEX); Serial.print(" "); Serial.println(lowByte, HEX);
}
else {
// temperature value is in bits 6-0 of highByte and 7-2 of lowByte
ivalue = ( highByte << 5 | lowByte >> 3 );
tempF = ivalue * 0.25 * 1.8 + 32.0; Serial.println( tempF );
}
}
The only problem I've run into is the self-heating of the MAX6675, on the order of 10C or more at room temperature. Connecting the t/c leads at a point that matches the chip temperature is going to be a challenge.
Thanks JimG. That seems to work great. I just wrote my own at the time because I wanted a smaller footprint for the library than having to use the SPI library.
I'd just like to add my thanks to this thread: I've been looking for a high-temperature-capable method of getting temps into the Arduino, and this is perfect [smiley=thumbsup.gif]
As I don't need the Fahrenheit conversion nor part-degree accuracy, I'd planned to bit-shift the result 2-bits to the left, which I guess should be faster than doing a f.p. multiply by 0.25? I could also simply ignore the final 2 bits of data when reading the port...
Anyway, the electronic bits are due here Monday, hopefully I'll have something cobbled together shortly afterwards
FYI I now have breakout boards for this chip to a thermocouple connector on my site. http://ryanjmclaughlin.com
Yeah, I saw those, they look neat. What's the postage cost to the UK?
At the moment, I'm only going to be using one thermocouple, as I experiment, but in the future, I may look at getting one of your multi-chip boards... I like the idea of being able to read 6 or so sensors using just 3 Arduino pins...
I had wondered about using a shift register to drive the appropriate CS. As a minimum, I think I would need:
1 pin for the clock (SR & MAX would all use this clock)
1 pin for SR latch
1 pin for SR serial out
1 pin for MAX serial in.
The sequence would be:
1 Write the appropriate 8-bit value into the SR (e.g. 00010000 to pick the 5th chip) using SR & clock
2 Pulse LATCH to activate the CS.
3 Read 16 bits from the MAX using the clock.
4 Pick another number, and goto step 1
With 1 SR, that's up to 8 MAXs with 4 pins. I'm not sure if each MAX chip output would need to be buffered?
The thermocouple & MAX chip arrived this morning, so, once I'd spent a frustrating and delicate 1/2 hour attaching the MAX chip to a DIP socket, it was time to quickly breadboard up a simple circuit:
Guess what? It works perfectly! So, thank you Ryan for working out how to do it & for sharing
This evening, I will try it out as it's supposed to be used.... in the exhaust stream of an engine...
Hi!
I've been trying to reproduce the design here, but something isn't right.
I can get indication of thermocouple error OK when it's not connected, but when i try to get the readings it shows 0.00 celsius degrees on ambient temperature. If I get the thermocouple very hot then there is some reading different from 0. I've even switched the max6675 with another one, brand new, and the same happened. (both were samples from maxim).
The strangest thing happens when I try to measure the voltage across the pins with a multimeter. With the test leads on ground and pin 11 (SO) the display reads somthing other than 0.00, but always under the room temperature.
Any ideas? Do I need a pull-down resistor on SO?
Couldn't find any reference on the internet about a similar behavior.
I'm using an Arduino Mega.