Pages: [1]   Go Down
Author Topic: THMOD-I2C thermocouple reader module  (Read 1451 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I figured out how to get a temperature reading from a THMOD-I2C I2C thermocouple reader.

It was more complicated than I expected, with two interpolated lookup tables with numbers gleaned from the datasheet. Anyway I'm there now, so I thought I'd share my efforts with the class. Hope it's of use to someone.

It works by polling the cold junction temperature reading from a thermistor next to the terminals on the THMOD board, and using that to look up a correction factor for the thermocouple voltage reading. Then it looks up the corrected thermocouple voltage from another lookup table, and interpolates from that to find the hot junction temperature.

The lookup tables are stored in program memory at the beginning. There are 3 models of THMOD, each with different temperature ranges and different lookup tables. You'll need to uncomment the one that suits your THMOD.

Enjoy!

Code:
#include <Wire.h>

// Pins: Standard: SDA:A4  SCL:A5
//       Mega:     SDA:D20 SCL:D21

// Lookup tables for THMOD conversion
const int DigitTable[] PROGMEM = {512, 3072, 5632, 8192, 10752, 13312, 15872, 18432, 20992, 23552, 26112, 28672, 31232}; // 300, 800, 1360
//const int CorrectionTable[] PROGMEM = {-1156, -778, -392, 0, 397, 798, 1203, 1612, 2023, 2436, 2851, 3267, 3682}; // 300
//const int CorrectionTable[] PROGMEM = {-578, -389, -196, 0, 199, 399, 602, 806, 1012, 1218, 1426, 1634, 1841}; // 800
const int CorrectionTable[] PROGMEM = {-385, -259, -131, 0, 132, 266, 401, 537, 674, 812, 950, 1089, 1227}; // 1360
//const int TemperatureTable[] PROGMEM = {-150, -100, -50, 0, 50, 100, 200, 300, 400}; // 300
//const int ThermoVoltageTable[] PROGMEM = {6609, 8946, 10611, 12500, 14523, 16596, 20638, 24709, 28897}; // 300
//const int TemperatureTable[] PROGMEM = {-150, -100, -50, 0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300}; // 800
//const int ThermoVoltageTable[] PROGMEM = {3305, 4473, 5309, 6250, 7262, 8298, 10319, 12355, 14449, 16572, 18703, 20815, 22888, 24913, 26888, 28810, 30669, 32455}; // 800
const int TemperatureTable[] PROGMEM = {-150, -100, -50, 0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1370}; // 1360
const int ThermoVoltageTable[] PROGMEM = {2203, 2982, 3537, 4167, 4841, 5532, 6879, 8236, 9632, 11048, 12468, 13876, 15258, 16609, 17925, 19206, 20446, 21637, 22440}; // 1360

void setup()
{
  Serial.begin(9600);
  Serial.println("Setup...");
  Wire.begin(); // join i2c bus (address optional for master)
  PORTC = (1 << PORTC4) | (1 << PORTC5);   //enable I2C pullups
}

void loop()
{
  float TCTemperature = ThermocoupleRead(0x78);
  Serial.print("Temp: ");
  Serial.println(TCTemperature);
 
  delay(200);
}

float ThermocoupleRead(char TCAddress)
{
  int XHi;
  int XLo;
  int YHi;
  int YLo;
  byte a;

  // Read thermocouple voltages
  Wire.requestFrom(TCAddress, 4);
 
  int ThermoVoltage = Wire.read() * 256;
  ThermoVoltage = (ThermoVoltage + Wire.read());
 
  int ColdJunction = Wire.read() * 256;
  ColdJunction = (ColdJunction + Wire.read());
 
  Wire.endTransmission();
 
  // Use lookup table for cold junction compensation
  XHi = 0;
  a = 0;
  while (XHi < ColdJunction)
  {
    XLo = XHi;
    YLo = YHi;
    XHi = pgm_read_word_near(DigitTable + a);
    YHi = pgm_read_word_near(CorrectionTable + a);
    a++;
  }
  ThermoVoltage = ThermoVoltage + ((long)(YHi - YLo) * (long)(ColdJunction - XLo) / (XHi - XLo)) + YLo;
 
  // Use lookup table for thermocouple temperature
  XHi = 0;
  a = 0;
  while (XHi < ThermoVoltage)
  {
    XLo = XHi;
    YLo = YHi;
    XHi = pgm_read_word_near(ThermoVoltageTable + a);
    YHi = pgm_read_word_near(TemperatureTable + a);
    a++;
  }
 
  // Return temperature
  return ((float)(YHi - YLo) / (float)(XHi - XLo)) * (ThermoVoltage - XLo) + YLo;
}

Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Have a look at - http://arduino.cc/playground/Main/MultiMap - might be usefull ....
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, that looks pretty helpful. I thought something like that must exist but I couldn't find it, so I did it myself.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Paul

I have a Hygrosens THMOD thermocouple module. I try to use your code to let it communicate with Arduino Ethernet.
Not yet succesfull, but I am busy with your code.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It works forgot the pullup resistors
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


if wire.read() returns 0, ColdJunction will be 0 ==> there will be a divide by zero error. modified the code to catch this..

Code:
float ThermocoupleRead(char TCAddress)
{
  int XHi = 0;
  int XLo = 0;
  int YHi = 0;
  int YLo = 0;
  byte a = 0;

  // Read thermocouple voltages
  Wire.requestFrom(TCAddress, 4);
 
  int ThermoVoltage = Wire.read() * 256;
  ThermoVoltage += Wire.read();
 
  int ColdJunction = Wire.read() * 256;
  ColdJunction += Wire.read();
 
  Wire.endTransmission();
 
  // Use lookup table for cold junction compensation
  ColdJunction = constrain(ColdJunction, 1, 31232);     // be sure it is within array DigitTable - prevents possible divide by zero  XHi == XLo if COldJunction == 0
  while (XHi < ColdJunction)
  {
    XLo = XHi;
    YLo = YHi;
    XHi = pgm_read_word_near(DigitTable + a);
    YHi = pgm_read_word_near(CorrectionTable + a);
    a++;
  }

  ThermoVoltage = ThermoVoltage + ((long)(YHi - YLo) * (long)(ColdJunction - XLo) / (XHi - XLo)) + YLo;   // <<<<<< HERE <<<<

  // Use lookup table for thermocouple temperature
  XHi = 0;
  a = 0;
  while (XHi < ThermoVoltage)
  {
    XLo = XHi;
    YLo = YHi;
    XHi = pgm_read_word_near(ThermoVoltageTable + a);
    YHi = pgm_read_word_near(TemperatureTable + a);
    a++;
  }
 
  // Return temperature
  return ((float)(YHi - YLo) / (float)(XHi - XLo)) * (ThermoVoltage - XLo) + YLo;
}

the lookup can be sped up by first looking up the index and then fetch the 4 values
Code:
  while (XHi < ColdJunction)
  {
    XLo = XHi;
    YLo = YHi;
    XHi = pgm_read_word_near(DigitTable + a);
    YHi = pgm_read_word_near(CorrectionTable + a);
    a++;
  }

==>
Code:
 
  a = 0;
  while (pgm_read_word_near(DigitTable + a) < ColdJunction) a++;  // search right index first
  XHi = pgm_read_word_near(DigitTable + a);
  XLo = pgm_read_word_near(DigitTable + a-1);
  YLo = pgm_read_word_near(CorrectionTable + a-1);
  YHi = pgm_read_word_near(CorrectionTable + a);

Be aware you must make a 0 entry in the lookup tables to let this work properly.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1]   Go Up
Jump to: