Skip to content
This repository was archived by the owner on Feb 28, 2024. It is now read-only.

Commit b655bd2

Browse files
authored
Merge pull request #90 from pnndra/master
added support for linearization and more precise temperature measurements
2 parents a8f1623 + 5b1dfc2 commit b655bd2

File tree

2 files changed

+175
-10
lines changed

2 files changed

+175
-10
lines changed

src/utility/THERMOCOUPLE/MAX31855.cpp

+123-10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@
1919

2020
#include "MAX31855.h"
2121

22+
const double MAX31855Class::Jm210_760[] ;
23+
const double MAX31855Class::J760_1200[] ;
24+
const double MAX31855Class::Km270_0[] ;
25+
const double MAX31855Class::K0_1372[] ;
26+
27+
const double MAX31855Class::InvJ_neg[] ;
28+
const double MAX31855Class::InvJ0_760[] ;
29+
const double MAX31855Class::InvJ760_1200[] ;
30+
31+
const double MAX31855Class::InvK_neg[] ;
32+
const double MAX31855Class::InvK0_500[] ;
33+
const double MAX31855Class::InvK500_1372[] ;
34+
35+
const MAX31855Class::coefftable MAX31855Class::CoeffJ[];
36+
const MAX31855Class::coefftable MAX31855Class::CoeffK[];
37+
38+
const MAX31855Class::coefftable MAX31855Class::InvCoeffJ[];
39+
const MAX31855Class::coefftable MAX31855Class::InvCoeffK[];
40+
2241
MAX31855Class::MAX31855Class(int cs, SPIClass& spi) :
2342
_cs(cs),
2443
_spi(&spi),
@@ -72,34 +91,128 @@ uint32_t MAX31855Class::readSensor()
7291
return read;
7392
}
7493

94+
double MAX31855Class::polynomial(double value, int tableEntries, coefftable const (*table) )
95+
{
96+
double output = 0;
97+
double valuePower = 1;
98+
for (int i=0;i<tableEntries;i++) {
99+
if (value < table[i].max) {
100+
if (table[i].size ==0) {
101+
return NAN;
102+
}
103+
else
104+
{
105+
output = 0;
106+
for (int j = 0; j<table[i].size;j++) {
107+
output += valuePower*table[i].coeffs[j];
108+
valuePower *=value;
109+
}
110+
return output;
111+
}
112+
}
113+
}
114+
return NAN;
115+
}
116+
117+
double MAX31855Class::coldTempTomv(int type, double temp) {
118+
coefftable const (*table);
119+
int tableEntries;
120+
double voltage;
121+
122+
switch (type) {
123+
case PROBE_J:
124+
table = CoeffJ;
125+
tableEntries = sizeof(CoeffJ)/sizeof(coefftable);
126+
break;
127+
case PROBE_K:
128+
table = CoeffK;
129+
tableEntries = sizeof(CoeffJ)/sizeof(coefftable);
130+
break;
131+
}
132+
voltage = polynomial(temp, tableEntries, table);
133+
// special case... for K probes in temperature range 0-1372 we need
134+
// to add an extra term
135+
if (type==PROBE_K && temp>0) {
136+
voltage += 0.118597600000E+00 * exp( -0.118343200000E-03 * pow(temp-0.126968600000E+03, 2));
137+
}
138+
return voltage;
139+
}
140+
141+
double MAX31855Class::mvtoTemp(int type, double voltage) {
142+
coefftable const (*table);
143+
int tableEntries;
144+
145+
switch (type) {
146+
case PROBE_J:
147+
table = InvCoeffJ;
148+
tableEntries = sizeof(InvCoeffJ)/sizeof(coefftable);
149+
break;
150+
case PROBE_K:
151+
table = InvCoeffK;
152+
tableEntries = sizeof(InvCoeffJ)/sizeof(coefftable);
153+
break;
154+
}
155+
return polynomial(voltage, tableEntries, table);
156+
}
157+
75158
float MAX31855Class::readTemperature(int type)
76159
{
77160
uint32_t rawword;
78-
float celsius;
161+
int32_t measuredTempInt;
162+
int32_t measuredColdInt;
163+
double measuredTemp;
164+
double measuredCold;
165+
double measuredVolt;
79166

80167
rawword = readSensor();
81168

82169
// Check for reading error
83170
if (rawword & 0x7) {
84171
return NAN;
85172
}
86-
// The temperature is stored in the last 14 word's bits
173+
// The cold junction temperature is stored in the last 14 word's bits
174+
// whereas the ttermocouple temperature (non linearized) is in the topmost 18 bits
87175
// sent by the Thermocouple-to-Digital Converter
176+
177+
// sign extend thermocouple value
88178
if (rawword & 0x80000000) {
89179
// Negative value, drop the lower 18 bits and explicitly extend sign bits.
90-
rawword = 0xFFFFC000 | ((rawword >> 18) & 0x00003FFFF);
180+
measuredTempInt = 0xFFFC0000 | ((rawword >> 18) & 0x00003FFFF);
91181
} else {
92182
// Positive value, just drop the lower 18 bits.
93-
rawword >>= 18;
183+
measuredTempInt = rawword>>18;
94184
}
95185

96-
// multiply for the LSB value
97-
celsius = rawword * 0.25f;
98-
if (type == PROBE_J) {
99-
// conversion factor from K type to J type
100-
celsius = celsius * 4/5;
186+
// convert it to degrees
187+
measuredTemp = measuredTempInt * 0.25f;
188+
189+
// sign extend cold junction temperature
190+
measuredColdInt = (rawword>>4)&0xfff;
191+
if (measuredColdInt&0x800) {
192+
// Negative value, sign extend
193+
measuredColdInt |= 0xfffff000;
101194
}
102-
return celsius;
195+
196+
// convert it to degrees
197+
measuredCold = measuredColdInt/16.0f;
198+
199+
// now the tricky part... since MAX31855K is considering a linear response
200+
// and is trimemd for K thermocouples, we have to convert the reading back
201+
// to mV and then use NIST polynomial approximation to determine temperature
202+
// we know that reading from chip is calculated as:
203+
// temp = chip_temperature + thermocouple_voltage/0.041276f
204+
//
205+
// convert temperature to mV is accomplished converting the chip temperature
206+
// to mV using NIST polynomial and then by adding the measured voltage
207+
// calculated inverting the function above
208+
// this way we calculate the voltage we would have measured if cold junction
209+
// was at 0 degrees celsius
210+
211+
measuredVolt = coldTempTomv(type, measuredCold)+(measuredTemp-measuredCold) * 0.041276f;
212+
213+
// finally from the cold junction compensated voltage we calculate the temperature
214+
// using NIST polynomial approximation for the thermocouple type we are using
215+
return mvtoTemp(type,measuredVolt);
103216
}
104217

105218
float MAX31855Class::readReferenceTemperature(int type)

src/utility/THERMOCOUPLE/MAX31855.h

+52
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,58 @@ class MAX31855Class {
4343
int _cs;
4444
SPIClass* _spi;
4545
SPISettings _spiSettings;
46+
47+
// NIST coefficient tables
48+
static constexpr double Jm210_760[] = { 0.000000000000E+00, 0.503811878150E-01, 0.304758369300E-04,-0.856810657200E-07, 0.132281952950E-09,-0.170529583370E-12, 0.209480906970E-15,-0.125383953360E-18, 0.156317256970E-22 };
49+
static constexpr double J760_1200[] = { 0.296456256810E+03,-0.149761277860E+01, 0.317871039240E-02,-0.318476867010E-05, 0.157208190040E-08,-0.306913690560E-12 };
50+
51+
static constexpr double Km270_0[] = { 0.000000000000E+00, 0.394501280250E-01, 0.236223735980E-04,-0.328589067840E-06,-0.499048287770E-08,-0.675090591730E-10,-0.574103274280E-12,-0.310888728940E-14,-0.104516093650E-16,-0.198892668780E-19,-0.163226974860E-22 };
52+
static constexpr double K0_1372[] = { -0.176004136860E-01, 0.389212049750E-01, 0.185587700320E-04,-0.994575928740E-07, 0.318409457190E-09,-0.560728448890E-12, 0.560750590590E-15,-0.320207200030E-18, 0.971511471520E-22,-0.121047212750E-25 };
53+
54+
static constexpr double InvJ_neg[] = { 0.0000000E+00, 1.9528268E+01, -1.2286185E+00, -1.0752178E+00, -5.9086933E-01, -1.7256713E-01, -2.8131513E-02,-2.3963370E-03,-8.3823321E-05};
55+
static constexpr double InvJ0_760[] = { 0.000000E+00, 1.978425E+01, -2.001204E-01, 1.036969E-02, -2.549687E-04, 3.585153E-06, -5.344285E-08, 5.099890E-10 };
56+
static constexpr double InvJ760_1200[] = { -3.11358187E+03, 3.00543684E+02, -9.94773230E+00, 1.70276630E-01, -1.43033468E-03, 4.73886084E-06 };
57+
58+
static constexpr double InvK_neg[] = { 0.0000000E+00, 2.5173462E+01, 1.1662878E+00, 1.0833638E+00, 8.9773540E-01, 3.7342377E-01, 8.6632643E-02, 1.0450598E-02, 5.1920577E-04 };
59+
static constexpr double InvK0_500[] = { 0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08 };
60+
static constexpr double InvK500_1372[] = { -1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08 };
61+
62+
typedef struct {
63+
int size;
64+
double max;
65+
const double *coeffs;
66+
} coefftable;
67+
68+
static constexpr coefftable CoeffJ []= {
69+
{0,-210, NULL},
70+
{sizeof(Jm210_760) / sizeof(double), 760.0f, &Jm210_760[0]},
71+
{sizeof(J760_1200) / sizeof(double), 1200.0f, &J760_1200[0]}
72+
};
73+
74+
static constexpr coefftable CoeffK []= {
75+
{0,-270, NULL},
76+
{sizeof(Jm210_760) / sizeof(double), 0.0f, &Km270_0[0]},
77+
{sizeof(K0_1372) / sizeof(double), 1200.0f, &K0_1372[0]}
78+
};
79+
80+
static constexpr coefftable InvCoeffJ []= {
81+
{0,-0.895, NULL},
82+
{sizeof(InvJ_neg) / sizeof(double), 0.0f, &InvJ_neg[0]},
83+
{sizeof(InvJ0_760) / sizeof(double), 42.919f, &InvJ0_760[0]},
84+
{sizeof(InvJ760_1200) / sizeof(double), 69.533f, &InvJ760_1200[0]}
85+
};
86+
87+
static constexpr coefftable InvCoeffK []= {
88+
{0,-5.891, NULL},
89+
{sizeof(InvK_neg) / sizeof(double), 0.0f, &InvK_neg[0]},
90+
{sizeof(InvK0_500) / sizeof(double), 20.644f, &InvK0_500[0]},
91+
{sizeof(InvK500_1372) / sizeof(double), 54.886f, &InvK500_1372[0]},
92+
};
93+
94+
double mvtoTemp(int type, double voltage);
95+
double coldTempTomv(int type, double temp);
96+
double polynomial(double value, int tableEntries, coefftable const (*table) );
97+
4698
};
4799

48100
extern MAX31855Class THERM;

0 commit comments

Comments
 (0)