rocketnumbernine

Andrew's Project Blog: Hardware, Software, Stuff I find Interesting

MAX6675 on Breakout BoardI've been asked for the code used to read the MAX6675 Thermocouple-to-Digital Converter used to measure the temperature in my ongoing SMD Reflow Oven project. The following is based on an Arduino (with a home built SPI helper library) but is fairly generic and should be applicable to most platforms.

Maxim's MAX6675 8-pin SOIC chip is a compact and simple to use solution for converting the output of a type K thermocouple to a digital temperature value read over SPI. It provides Digital to Analogue conversion of the voltage produced by the thermocouple, cold-junction compensation, noise reduction and processing of the result into a binary temperature value at a precision of 0.25°C.

SO - MISO (Arduino D12), SCK (Arduino D13), CS (Arduino D8)

SO - MISO (Arduino D12), SCK (Arduino D13), CS (Arduino D8)

Circuit used (from the datasheet sheet) is shown to the right. I used a breadboard for the circuit but created a breakout board for the (SMD) MAX6675 chip and decoupling capacitor with BatchPCB.

The thermocouple is connected to pins 2 and 3 - if connected the wrong way around the temperature output from the MAX6675 will go down as the end of the thermocouple is heated. Connecting the MAX6675 to the Arduino is straightforward - just power and the SPI MISO and SCK (clock) and chip select line (^CS). Pin D8 was used to select the device.

SPI Setup

From the datasheet we see that the MAX6675 transmits the temperature in 2 bytes - most significant bit first. The clock is expected to be idle low and data can be read when it is falling (SPI mode 1). The MAX6675 can take a maximum SPI clock rate of 4.3MHz - as the Arduino was running at 16MHz a SPI data rate of Clock/8 (2MHz) was specified so the device was operating well within its tolerances. The following sets up up the MAX6675 chip select pin (Arduino Pin D8) control pin, SPI and the Arduino Serial line:

1
2
3
4
5
6
7
8
9
10
11
#define MAX6675_SELECT_PIN 8
#define DESELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, HIGH)
#define SELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, LOW)

void setup()
{
  pinMode(MAX6675_SELECT_PIN, OUTPUT);
  DESELECT_MAX6675;
  setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8);
  Serial.begin(19200);
}

Reading the Temperature

Reading the temperature value is equally straightforward. Select the device, wait atleast 100ns (this is close to the time that it will take the AVR to start sending data on the SPI bus anyway but I put in a microsecond delay to be certain), read the two bytes from SPI, and deselect the device.
1
2
3
4
5
SELECT_MAX6675;
 delayMicroseconds(1);
 unsigned char highByte = send_spi(0);
 unsigned char lowByte = send_spi(0);
 DESELECT_MAX6675;

The 16-bits read from the device in two bytes need to be processed slightly: MAX6675 Bitfield

Bit 2 in the 2nd byte will be high if the device cannot detect an attached thermocouple, otherwise the 12 temperature value bits spread across the 2 bytes (6-0 of the hight byte, and 7-3 of the low byte) need to be shifted into a single numeric value (highByte << 5 | lowByte>>3).

The program simply prints the bytes received on an error and the temperature (divided by 4 to get the value in degrees) if it has been read successfully.

1
2
3
4
5
6
7
8
9
if (lowByte & (1<<2)) {
   Serial.print("Not connected ");
   Serial.print(highByte, HEX); Serial.print(" ");
   Serial.println(lowByte, HEX);
 } else {
   short value = (highByte << 5 | lowByte>>3);
   Serial.print(value/4); Serial.print(".");
   Serial.println(value%4 *25);
 }

The MAX6675 has a maximum conversion time of 0.22 seconds. If the device is sampled faster than this it will continue to output the temperature that was first read without any indication that it is being read too fast - I found a delay of atleast 250ms between readings the device worked well.

The complete sampling code is shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <spi.h>

// MAX6675 connected to pin D9
#define MAX6675_SELECT_PIN 8
#define DESELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, HIGH)
#define SELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, LOW)

void setup()
{
 pinMode(MAX6675_SELECT_PIN, OUTPUT);
 DESELECT_MAX6675;
 setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8);
 Serial.begin(19200);
}

void loop()
{
 delay(500);

 // select the device, wait > 100nS, read two bytes, deselect
 SELECT_MAX6675;
 delayMicroseconds(1);
 unsigned char highByte = send_spi(0);
 unsigned char lowByte = send_spi(0);
 DESELECT_MAX6675;

 // 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
   short value = (highByte << 5 | lowByte>>3);
   // 1 bit is 0.25 degree 'divide' by 4 to show degrees
   Serial.print(value/4); Serial.print("."); Serial.println(value%4 *25);
 }
}

Conclusions

Compared with manual reading and conversion of the thermocouple voltage to temperature the MAX6675 is a delight to use. Although it is not a cheap device it is comparable to other thermocouple processing devices (for example the AC1226 and LTK001) but is fairly unique in having a digital/SPI output rather than a cleaned up voltage per Centigrade value that also requires a D/A converter.

References/Resources

  1. AVR SPI Helper Library
  2. MAX6675 Spec sheet
  3. Break out board PCB

It looks like your browser doesn't support javascript so comments won't work

Tags/Categories: arduino, AVR, SPI, MAX6675, Thermocouple, howto