Temperature Sensor Thermocouple API for MCU like Arduino

 Temperature Sensor Thermocouple API for MCU like Arduino


This library added a few API for Arduino and similar MCU to easily work on a common temperature sensor - thermocouple. K type in this library but can be easily add support for other type like JType thermocouple.
In this test, I use the KType thermocouple from a multimeter, which seems works well on a few different brands of multiple.


Theory of operation

Thermocouple produce a tiny voltage when it has temperature different than the environment or cold end, the tiny voltage can not be detected by arduino ADC directly, we must add a opAmp to amplify it a hundred times, so arduino ADC can correctly read it. Any opamp works, I am using MCP6002 here. (The popular and cheapest LM358 works too, however need to pay attention LM358 doesn't work well in 3.3V system. )



D3 is optional, to limit the input.

Software and Algorithm:

There are a few ways to work on the opAmp output voltage.
  • The easiest but not accurate:  using voltage per C 0.04mV.

According to the Ktype thermocouple datasheet  https://www.thermocoupleinfo.com/type-k-thermocouple.htm and https://assets.omega.com/pdf/tables_and_graphs/thermocouple-type-k-celsius.pdf , we can say it's roughly it's 0.04mV per C degree. So when we have the TC side voltage we can divide 0.04mV to get the temperature. 

However it's not accurate enough, we can see when at 5C, it's 0.03960mV per C ( 0.198mV at 5C ,  0.198 / 5 = 0.03960 ), and when it's 120C, it's 0.04100mV per  C ( 4.920mV / 120C = 0.04100mV ).

  • Accurate and complicated: voltage and temperature lookup table.

    Using a lookup table to store all voltage VS temperature, it's accurate because all voltage is very close to the datasheet. however the table could be large, and it takes too much memory from the poor arduino, which doesn't have much RAM. While it's running out of memory, the app crashes in a strange way and arduino reset which it's extremely difficult to debug.

    A work around could be, do not store all voltage / temperate data from 0 to 400C, we only store 0, 10, 20, 30 to 400C etc, or 0, 5, 10, 15 to 400C.  this can save a lot of space.

    Now here comes an opportunity for optimizing. Since arduino or other MCU's ADC always read from OpAmp output, which is the result of hundredes times larger than the original TC's tiny mV output, so each ADC read, arduino must do some calculation to convert a few things, it takes a few steps, as below:  
    • Convert ADC read integer to ADC read actual voltage (which is the output of opAmp)
    • Convert the ADC read voltage to opAmp input voltage, which is the thermocouple output voltage, by dividing 241 or other value, determined by the opAmp resisitors.
  • The above steps must be done each time we read the ADC, and we usually need to read the ADC to get temperature many many times per second...so this need to be optimized, which is, calculate once and use many times, but it require two tables, table 1 tc mv and temperature mapping; table2, adc read integer and temperature mapping. When system start, we convert data from table 1 to table2.
    so table2 has ADC integers, we don't need to calculate anything while reading from the ADC. only compare and done. Once the lookup is done, we have the closest index, then we can have the closest temperature to the input voltage.
    • Now there is another problem, since our table only store 0, 10, 20 degree's data, so when we have voltage of 15C, we can do a linear conversion using voltage and voltage of 10C and 20C as below, so we can get the closest temperature in the range of 10C and 20C as below:

    • finally the binary search. Use function   int KTypeThermalCoupleAdc::valueToLookupTableIndex(int value, int startindex, int endindex) for more detail. It's recursive function keeps calling itself until it getsthe result. It returns the closest index of the given ADC integer....multply by 10 (if the table is 0 10 20 30...or multiple by 5 if the table is 0, 5, 10, 15...)  we can have the temperature.

  • Voltage per C in different stages. Binary search and lookup table maybe an overkill here, it takes a lot ram and code storage  space from the poor arduino, ...There is another simpler way, do voltage per C in different stages, 0C to 50C, 51C to 100C, 101C to 150C, each stage has a different voltage per C value, so this is relatively simple and easy to implement and manage, also at same time it's precise enough. 

Environment Temperature

Thermocouple can only get the temperature difference of the cold junction T1, so it must have environment temperature T2, then final temperature = T1+T2. Let's say the thermocouple in room temperature, it returns 0mV, which means 0C, so we must add room temp 20C+0C=20C. How to get the environment temperature,...we can use NTC thermal resistor, or thermistor, it is another big topic. 

Testing the code

connect the KType thermocouple  to opAmp and arduino setup, to get our temperature reading, also connect it to the multimeter to get the reading from multiple as reference. Heatup the thermocouple to certain temperature and compare our reading and the multimeter.


Test Video
https://youtu.be/vJAUP0_tZ30   It's using MVPerC in different stages (the last option above). It seems the arduino temperature and multimeter is close enough, however not always exactly the same. There are a few reasons:
  • multimeter is not always absolutely correct, sometimes they need calibration, and some multimeter only use Voltage/mvPerC to calculate the temperature. Different multimeters give slightly different temperature reading from the same thermocouple input.
  • Arduino ADC is only 10bit, which is not very good.
  • Different resistors in opAmp circuit have slightly different value, so the X241gain could be a little different, for example some 1K resistors could be 995 Ohm, some other could be 1010 Ohm.

Source code:



                


 
                  


Comments

Popular posts from this blog

STM32 and U8G2 to draw on LCD12864 Using hardware SPI

Using STM32 DMA to speed up hardware SPI and U8G2 - Attempt 2 - buffered DMA

DIY Weller Solder Tweezers Controller