Hello gals and guys… holidays are over and I must sadly return to my hobby : welding and programming stuff. Pity me. What are you gaining out of this today ? A sweet MAX6675 driver for the ESP8266.
What’s a MAX6675 you ask ? Well, it’s a thermocouple interface for microcontrollers. What’s a thermocouple you ask ? It’s a couple of thermoes, of course ! Nah, just kidding, it’s only one of the most amazing temperature sensors ever invented.
Simply put, if you take two pieces of different metals and weld them together, you get a battery. And if you choose your metals carefully, that battery’s EMF (its open-circuit voltage) will be proportional to how hot it is. Hence the name. You can find thermocouples in countless industrial applications because of their simplicity and inherent reliability. There are other reasons too : even the cheapest and most common can measure from -270°C to +1260°C. Meaning you can measure the temperature of liquid helium (around 3 degrees above absolute zero) and the temperature of molten iron with the same sensor technology.
By the time you’ve gone through this article, you’ll be able to interface this wonder sensor to your ESP8266 and read temperature from it. I hope you’re excited.
Unfortunately, you can’t just put a voltmeter to your thermocouple and get a thermometer. You need to amplify, calibrate and compensate along the way. Fortunately, you don’t need to do that yourself, you can leave it to the paid professionals of semiconductor manufacturers such as Maxim, maker of the MAX6675.
This cheap integrated circuit is essentially a 12-bit ADC with an input stage tailored for K-type thermocouples. On the digital side it is a simplistic SPI slave that has just one read-only 16-bit register. It can measure temperatures in the 0 to 1024°C range.
For your convenience, China makes a simple breakout board (you could hardly call it a module) that features standard thermocouple headers on one end and five maker-friendly pins for power and SPI on the other. You even get a nice silk-screen, a mounting hole in the middle and a decoupling capacitor. Here’s what it looks like :
One can easily find this set of one thermocouple and one MAX6675 breakout for 5 dollars or less online. This is what I mean by “cheap”. In case you’re wondering, the thermocouple alone is worth two dollars or less.
A thermocouple is just two wires soldered end-to-end, so you can imagine it’s both fragile and impractical. You typically need Kapton tape to stick it to whatever you want to measure the temperature of, and that’s neither pretty nor reliable. For something more permanent or if you can’t match Godzilla’s dexterity, you’re better off getting a model similar to the one I just showed you.
That particular thermocouple is sealed inside a small metric bolt and its cable is sheathed in steel mesh, which allows you to mount it safely and easily. You could perfectly use this particular format inside the engine compartment of a car to keep an eye on engine temperature, for example. If bolts aren’t your thing there are lots of variants to choose from. I prefer mine encased in a washer, those are perfect for measuring the temperature of components bolted to a heat sink : thread the washer between bolt head and component and you get both reliable mounting and excellent thermal coupling.
A word of warning : that steel sheath is, obviously, a very good conductor of electricity. You know what that means for your safety and that of your electronics. If you don’t, ask a grown-up. As usual, I accept no responsibility if you hurt yourself and/or destroy anything. Or as Jennifer Lopez puts it, I ain’t your mama.
Keep in mind that a thermocouple works because of the specific metals it’s made of, and those are the same metals its cable is made of. Do not use copper cables to make an extension cord. If you need more reach, you have only two sensible options :
- Order a thermocouple of the appropriate length (well duh !)
- Extend the cables on the digital side of the MAX6675
As usual, you will find it in my ESP8266 repository on GitHub. Clone it or update your clone if necessary : you should then see a MAX6675 branch. Checkout that branch to get a version of my ESP8266 project template that features example code. If you have no idea what “GitHub” or a “branch” are, do yourself a huge favor and read this article series from the start. You’ll thank me later.
The example code in “user_main.c” simply uses a FreeRTOS task to read temperature from a MAX6675 and display it on an ILI9341 LCD module (you can read up on how to wire one to your ESP8266 in this awesome article). I mean, the code will run even without and LCD… but it’d be rather pointless.
I’ve placed today’s library, quite obviously, under the libraries/MAX6675 folder. If you’re a loyal reader, and of course you are, you know where its documentation is (or will be, depending on how quickly you read this article once I publish it). If you’re not loyal… well I hope you’ll remedy that in short order.
Connecting the MAX6675 to your ESP8266
The MAX6675 module has five pins, silk-screened on top for your convenience. My example code expects you to connect them like so :
- VCC goes to a 3.3V supply rail
- GND goes to GND, as ever
- SO goes to GPIO4 or D2 (WeMos / NodeMCU naming scheme)
- CS goes to GPIO0, a.k.a. D3
- SCK goes to GPIO2, a.k.a D4
SO, CS and SCK form a read-only SPI interface. Since my library relies on bit-banging (software emulation) you can modify it to use other pins. Just know that I chose D2 for SO because it has no pull-up on the WeMos D1 Mini. You get extra points if you can follow my reasoning.
Build, download and run
You know the drill by now : if necessary, edit the template project’s makefile to set the COM port to whatever you’re using. Connect your ESP8266 to your PC, then make the “flash” target.
If you have opposable thumbs and the gods of ESD haven’t fried any of your chips, you should now have a nice little thermometer. It should look like this :
The binary sequence is exactly what comes out of the MAX6675, MSB to LSB. The decimal value in tall font underneath it is the temperature in degrees Centigrade. Here I stuck my thermocouple to the back of a powerful LED to check that everything worked.
How the MAX6675 interface works
The MAX6675 is an SPI slave with a single 16-bit read-only register.
As with any SPI interface, a master (our ESP8266 in this case) pulls CS low to tell the slave that a transfer is about to start. When this happens, the MAX6675 outputs the most significant bit (MSB) of its register on the SO pin. The ESP8266 only needs to read it and pulse SCK (Serial ClocK) to get the next bit, sixteen times. It looks like this :
Those 16 bits carry the temperature reading (12 bits) and a few additional flags :
You can check the “Thermocouple Input” bit to detect a broken or unplugged thermocouple (if this is set, you have a problem).
When CS goes back up, the MAX6675 starts its ADC to make a new measurement, which can take up to 220 ms. If you try to read the chip before then, it’ll stop the ADC. So it’s a good idea to wait a little between measurements. Best practice is to dedicate a FreeRTOS task to temperature measurement; you can use see my example code as inspiration.
K-type thermocouples have an absolute accuracy of around 2°C, give or take. While the MAX6675’s ADC provides results with 0.25°C resolution, keep in mind that resolution is not the same thing as accuracy. If your application needs to be this accurate, you’ll need to design some sort of calibration process. That being said, I don’t know a lot of applications that require sub-degree accuracy over a thousand-degree range.
The ADC is very slow : it needs 170 to 220 milliseconds to sample the thermocouple, which translates to sampling rates between 4 and 5 Hz. Then again, I don’t know of many applications that require high-frequency temperature monitoring over a thousand degrees range. Besides, we’re working with about 5 dollars worth of sensor.
The MAX6675’s SPI supports SCK frequencies of up to 4.3 MHz. My simple bit-banging implementation uses zero delay and, running at 160 MHz, “only” reaches 1.2 MHz. So it clearly has room to breathe (and improve). As it stands, a single measurement takes about 14 µs. Take this into consideration if you’re writing a multitasking program.
Speaking of bit-banging, you might be wondering why I didn’t “simply” use the ESP8266’s HSPI. Quite simply, because it wouldn’t have been simple. Take a look at the MAX6675 library’s source code to convince yourself. It would have taken more code to use the HSPI in this case. Moreover, if one also uses the HSPI to control another slave, like the ILI9341 LCD controller, complexity further increases. Let us leave those complications for another time, when I’m not recovering from my summer vacation… and for a worthier peripheral.
I’ve got nothing planned for now, although there’s a laundry list of things that I could improve.
For starters, this library currently isn’t thread-safe : if you use more than one task, FreeRTOS may well interrupt the “max6675_read” function, leaving you with an erroneous result and no way to detect it. Of course you can use FreeRTOS critical section macros to guard against that.
Using a critical section is fine, but those need to be kept as short (in time) as possible so as not to mess-up the sequencing of your other tasks. This means I should make the “max6675_read” function faster. That’s more complicated since it is not a lot of code…
Another and possibly better solution may be to design a dedicated FreeRTOS task that would yield the CPU to other tasks between each GPIO operation. It would take longer to read the MAX6675 and it would also introduce jitter on SCK, but the MAX6675 is a good sort, it won’t mind.
This isn’t a high-priority project for me, so let me know what applications you have in mind and which solution would work best for you. I’m just back from vacation, I’m feeling helpfuller than usual.
So there you have it : you now know how to measure very high temperatures with your ESP8266 and do it for less than ten dollars… of course that’s assuming you don’t need the LCD module.
And you don’t need an LCD if you’re taking advantage of the ESP8266’s WiFi to send measurements to a Unity application running on your PC or your smartphone. That is something I intend to discuss you in an upcoming Unity article.
As for this series, when next we meet we’ll be looking at a driver for another useful sensor : the DHT22 temperature and humidity sensor. And it just happens to be available as a shield for the WeMos D1 Mini !
It’s only about 4 dollars online, let’s see if you can get one before I can show you how to use it, shall we ?