forked from engineertype/Controleo3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Controleo3MAX31856.cpp
executable file
·286 lines (218 loc) · 9.35 KB
/
Controleo3MAX31856.cpp
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// Written by Peter Easton
// Released under CC BY-NC-SA 3.0 license
// Build a reflow oven: http://whizoo.com
//
// This is a library for the Maxim MAX31856 thermocouple IC
// http://datasheets.maximintegrated.com/en/ds/MAX31856.pdf
//
// Library Implementation Details
// ==============================
// DRDY and FAULT lines are not used in this driver. DRDY is useful for low-power mode so samples are only taken when
// needed; this driver assumes power isn't an issue. The FAULT line can be used to generate an interrupt in the host
// processor when a fault occurs. This library reads the fault register every time a reading is taken, and will
// return a fault error if there is one. The MAX31856 has sophisticated usage scenarios involving FAULT. For
// example, low and high temperature limits can be set, and the FAULT line triggers when these temperatures are
// breached. This is beyond the scope of this sample library. The assumption is that most applications will be
// polling for temperature readings - but it is good to know these features are supported by the hardware.
//
// The MAX31856 differs from earlier thermocouple IC's in that it has registers that must be configured before
// readings can be taken. This makes it very flexible and powerful, but one concern is power loss to the IC. The IC
// should be as close to the cold junction as possible, which might mean there is a cable connecting the breakout
// board to the host processor. If this cable is disconnected and reconnected (MAX31856 loses power) then the
// registers must be reinitialized. This library detects this condition and will automatically reconfigure the
// registers. This simplifies the software running on the host.
//
// A lot of configuration options appear in the .H file. Of particular note is the line frequency filtering, which
// defaults to 60Hz (USA and others). If your line voltage is 50Hz you should set CR0_NOISE_FILTER_50HZ.
//
// This library handles the full range of temperatures, including negative temperatures.
#include "Controleo3MAX31856.h"
// Define which pins are connected to the MAX31856. The DRDY and FAULT outputs
// from the MAX31856 are not used in this library.
void Controleo3MAX31856::begin(void)
{
// Initialize all the data pins
pinMode(THERMOCOUPLE_SDI, OUTPUT);
pinMode(THERMOCOUPLE_CS, OUTPUT);
pinMode(THERMOCOUPLE_CLK, OUTPUT);
// Use a pullup on the data line to be able to detect "no communication"
pinMode(THERMOCOUPLE_SDO, INPUT_PULLUP);
// Default output pins state
digitalWrite(THERMOCOUPLE_CS, HIGH);
digitalWrite(THERMOCOUPLE_CLK, HIGH);
// Set up the shadow registers with the default values
byte reg[NUM_REGISTERS] = {0x00,0x03,0xff,0x7f,0xc0,0x7f,0xff,0x80,0,0,0,0};
for (int i=0; i<NUM_REGISTERS; i++)
_registers[i] = reg[i];
}
// Write the given data to the MAX31856 register
void Controleo3MAX31856::writeRegister(byte registerNum, byte data)
{
// Sanity check on the register number
if (registerNum >= NUM_REGISTERS)
return;
// Select the MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, LOW);
// Write the register number, with the MSB set to indicate a write
writeByte(WRITE_OPERATION(registerNum));
// Write the register value
writeByte(data);
// Deselect MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, HIGH);
// Save the register value, in case the registers need to be restored
_registers[registerNum] = data;
}
// Read the thermocouple temperature either in Degree Celsius or Fahrenheit. Internally,
// the conversion takes place in the background within 155 ms, or longer depending on the
// number of samples in each reading (see CR1).
// Returns the temperature, or an error (FAULT_OPEN, FAULT_VOLTAGE or NO_MAX31856)
double Controleo3MAX31856::readThermocouple(byte unit)
{
double temperature;
long data;
// Select the MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, LOW);
// Read data starting with register 0x0c
writeByte(READ_OPERATION(0x0c));
// Read 4 registers
data = readData();
// Deselect MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, HIGH);
// If there is no communication from the IC then data will be all 1's because
// of the internal pullup on the data line (INPUT_PULLUP)
if (data == (long) 0xFFFFFFFF)
return NO_MAX31856;
// If the value is zero then the temperature could be exactly 0.000 (rare), or
// the IC's registers are uninitialized.
if (data == 0 && verifyMAX31856() == NO_MAX31856)
return NO_MAX31856;
// Was there an error?
if (data & SR_FAULT_OPEN)
temperature = FAULT_OPEN;
else if (data & SR_FAULT_UNDER_OVER_VOLTAGE)
temperature = FAULT_VOLTAGE;
else {
// Strip the unused bits and the Fault Status Register
data = data >> 13;
// Negative temperatures have been automagically handled by the shift above :-)
// Convert to Celsius
temperature = (double) data * 0.0078125;
// Convert to Fahrenheit if desired
if (unit == FAHRENHEIT)
temperature = (temperature * 9.0/5.0)+ 32;
}
// Return the temperature
return (temperature);
}
// Read the junction (IC) temperature either in Degree Celsius or Fahrenheit.
// This routine also makes sure that communication with the MAX31856 is working and
// will return NO_MAX31856 if not.
double Controleo3MAX31856::readJunction(byte unit)
{
double temperature;
long data, temperatureOffset;
// Select the MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, LOW);
// Read data starting with register 8
writeByte(READ_OPERATION(8));
// Read 4 registers
data = readData();
// Deselect MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, HIGH);
// If there is no communication from the IC then data will be all 1's because
// of the internal pullup on the data line (INPUT_PULLUP)
if (data == (long) 0xFFFFFFFF)
return NO_MAX31856;
// If the value is zero then the temperature could be exactly 0.000 (rare), or
// the IC's registers are uninitialized.
if (data == 0 && verifyMAX31856() == NO_MAX31856)
return NO_MAX31856;
// Register 9 is the temperature offset
temperatureOffset = (data & 0x00FF0000) >> 16;
// Is this a negative number?
if (temperatureOffset & 0x80)
temperatureOffset |= 0xFFFFFF00;
// Strip registers 8 and 9, taking care of negative numbers
if (data & 0x8000)
data |= 0xFFFF0000;
else
data &= 0x0000FFFF;
// Remove the 2 LSB's - they aren't used
data = data >> 2;
// Add the temperature offset to the temperature
temperature = data + temperatureOffset;
// Convert to Celsius
temperature *= 0.015625;
// Convert to Fahrenheit if desired
if (unit == FAHRENHEIT)
temperature = (temperature * 9.0/5.0)+ 32;
// Return the temperature
return (temperature);
}
// When the MAX31856 is uninitialzed and either the junction or thermocouple temperature is read it will return 0.
// This is a valid temperature, but could indicate that the registers need to be initialized.
double Controleo3MAX31856::verifyMAX31856()
{
long data, reg;
// Select the MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, LOW);
// Read data starting with register 0
writeByte(READ_OPERATION(0));
// Read 4 registers
data = readData();
// Deselect MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, HIGH);
// If there is no communication from the IC then data will be all 1's because
// of the internal pullup on the data line (INPUT_PULLUP)
if (data == (long) 0xFFFFFFFF)
return NO_MAX31856;
// Are the registers set to their correct values?
reg = ((long)_registers[0]<<24) + ((long)_registers[1]<<16) + ((long)_registers[2]<<8) + _registers[3];
if (reg == data)
return 0;
// Communication to the IC is working, but the register values are not correct
// Select the MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, LOW);
// Start writing from register 0
writeByte(WRITE_OPERATION(0));
// Write the register values
for (int i=0; i< NUM_REGISTERS; i++)
writeByte(_registers[i]);
// Deselect MAX31856 chip
digitalWrite(THERMOCOUPLE_CS, HIGH);
// For now, return an error but soon valid temperatures will be returned
return NO_MAX31856;
}
// Read in 32 bits of data from MAX31856 chip. Minimum clock pulse width is 100 ns
// so no delay is required between signal toggles.
long Controleo3MAX31856::readData()
{
long data = 0;
unsigned long bitMask = 0x80000000;
// Shift in 32 bits of data
while (bitMask)
{
digitalWrite(THERMOCOUPLE_CLK, LOW);
// Store the data bit
if (digitalRead(THERMOCOUPLE_SDO))
data += bitMask;
digitalWrite(THERMOCOUPLE_CLK, HIGH);
bitMask >>= 1;
}
return(data);
}
// Write out 8 bits of data to the MAX31856 chip. Minimum clock pulse width is 100 ns
// so no delay is required between signal toggles.
void Controleo3MAX31856::writeByte(byte data)
{
byte bitMask = 0x80;
// Shift out 8 bits of data
while (bitMask)
{
// Write out the data bit. Has to be held for 35ns, so no delay required
digitalWrite(THERMOCOUPLE_SDI, data & bitMask? HIGH: LOW);
digitalWrite(THERMOCOUPLE_CLK, LOW);
digitalWrite(THERMOCOUPLE_CLK, HIGH);
bitMask >>= 1;
}
}