-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmax31855.py
executable file
·207 lines (179 loc) · 7.67 KB
/
max31855.py
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
#!/usr/bin/python
import RPi.GPIO as GPIO
from thermocouples_reference import thermocouples as tc_ref
class MAX31855(object):
'''Python driver for [MAX38155 Cold-Junction Compensated Thermocouple-to-Digital Converter](http://www.maximintegrated.com/datasheet/index.mvp/id/7273)
Requires:
- The [GPIO Library](https://code.google.com/p/raspberry-gpio-python/) (Already on most Raspberry Pi OS builds)
- A [Raspberry Pi](http://www.raspberrypi.org/)
Based on and downloaded from: https://github.com/Tuckie/max31855
'''
def __init__(self, cs_pin, clock_pin, data_pin, units = "c", board = GPIO.BCM, type = "K"):
'''Initialize Soft (Bitbang) SPI bus
Parameters:
- cs_pin: Chip Select (CS) / Slave Select (SS) pin (Any GPIO)
- clock_pin: Clock (SCLK / SCK) pin (Any GPIO)
- data_pin: Data input (SO / MOSI) pin (Any GPIO)
- units: (optional) unit of measurement to return. ("c" (default) | "k" | "f")
- board: (optional) pin numbering method as per RPi.GPIO library (GPIO.BCM (default) | GPIO.BOARD)
- type: (optional) thermocouple type. ("K" (default), or any other supported by the thermocouple library)
'''
self.cs_pin = cs_pin
self.clock_pin = clock_pin
self.data_pin = data_pin
self.units = units
self.data = None
self.board = board
self.type = type
# Initialize needed GPIO
GPIO.setmode(self.board)
GPIO.setup(self.cs_pin, GPIO.OUT)
GPIO.setup(self.clock_pin, GPIO.OUT)
GPIO.setup(self.data_pin, GPIO.IN)
# Pull chip select high to make chip inactive
GPIO.output(self.cs_pin, GPIO.HIGH)
def get(self):
'''Reads SPI bus and returns current value of thermocouple.'''
self.read()
self.checkErrors()
return getattr(self, "to_" + self.units)(self.data_to_tc_temperature())
def get_corrected(self):
'''Reads SPI bus and returns current temperature corrected for the nonlinearities of the thermocouple.
This also naturally handles conversion to other thermocouple types.
'''
self.read()
self.checkErrors()
celsius_raw = self.data_to_tc_temperature()
emf = self.to_emf_mVC(celsius_raw)
try:
celsius_corrected = tc_ref[self.type].inverse_CmV(emf, Tref=0.0)
except:
print emf
return None
return getattr(self, "to_" + self.units)(celsius_corrected)
def get_rj(self):
'''Reads SPI bus and returns current value of reference junction.'''
self.read()
return getattr(self, "to_" + self.units)(self.data_to_rj_temperature())
def get_sensor_and_rj(self, ignore_errors = False):
'''Reads SPI bus and return current values of sensor and reference junction.'''
self.read()
if ignore_errors == False:
self.checkErrors()
return {'sensor': getattr(self, "to_" + self.units)(self.data_to_tc_temperature()),
'rj' : getattr(self, "to_" + self.units)(self.data_to_rj_temperature())}
def read(self):
'''Reads 32 bits of the SPI bus & stores as an integer in self.data.'''
bytesin = 0
# Select the chip
GPIO.output(self.cs_pin, GPIO.LOW)
# Read in 32 bits
for i in range(32):
GPIO.output(self.clock_pin, GPIO.LOW)
bytesin = bytesin << 1
if (GPIO.input(self.data_pin)):
bytesin = bytesin | 1
GPIO.output(self.clock_pin, GPIO.HIGH)
# Unselect the chip
GPIO.output(self.cs_pin, GPIO.HIGH)
# Save data
self.data = bytesin
def checkErrors(self, data_32 = None):
'''Checks error bits to see if there are any SCV, SCG, or OC faults'''
if data_32 is None:
data_32 = self.data
anyErrors = (data_32 & 0x10000) != 0 # Fault bit, D16
noConnection = (data_32 & 1) != 0 # OC bit, D0
shortToGround = (data_32 & 2) != 0 # SCG bit, D1
shortToVCC = (data_32 & 4) != 0 # SCV bit, D2
if anyErrors:
if noConnection:
raise MAX31855Error("No Connection")
elif shortToGround:
raise MAX31855Error("Thermocouple short to ground")
elif shortToVCC:
raise MAX31855Error("Thermocouple short to VCC")
else:
# Perhaps another SPI device is trying to send data?
# Did you remember to initialize all other SPI devices?
raise MAX31855Error("Unknown Error")
def data_to_tc_temperature(self, data_32 = None):
'''Takes an integer and returns a thermocouple temperature in celsius.'''
if data_32 is None:
data_32 = self.data
tc_data = ((data_32 >> 18) & 0x3FFF)
return self.convert_tc_data(tc_data)
def data_to_rj_temperature(self, data_32 = None):
'''Takes an integer and returns a reference junction temperature in celsius.'''
if data_32 is None:
data_32 = self.data
rj_data = ((data_32 >> 4) & 0xFFF)
return self.convert_rj_data(rj_data)
def convert_tc_data(self, tc_data):
'''Convert thermocouple data to a useful number (celsius).'''
if tc_data & 0x2000:
# two's compliment
without_resolution = ~tc_data & 0x1FFF
without_resolution += 1
without_resolution *= -1
else:
without_resolution = tc_data & 0x1FFF
return without_resolution * 0.25
def convert_rj_data(self, rj_data):
'''Convert reference junction data to a useful number (celsius).'''
if rj_data & 0x800:
without_resolution = ~rj_data & 0x7FF
without_resolution += 1
without_resolution *= -1
else:
without_resolution = rj_data & 0x7FF
return without_resolution * 0.0625
def to_c(self, celsius):
'''Celsius passthrough for generic to_* method.'''
return celsius
def to_k(self, celsius):
'''Convert celsius to kelvin.'''
return celsius + 273.15
def to_f(self, celsius):
'''Convert celsius to fahrenheit.'''
return celsius * 9.0/5.0 + 32
def to_emf_mVC(self, celsius):
'''Convert back from celsius to emv (in mV) with respect to 0 deg celsius.
This is assuming that the MAX31855 is using a linear 41.276 uV/degC relation
'''
return celsius * 0.041276
def cleanup(self):
'''Selective GPIO cleanup'''
GPIO.setup(self.cs_pin, GPIO.IN)
GPIO.setup(self.clock_pin, GPIO.IN)
class MAX31855Error(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
if __name__ == "__main__":
# Multi-chip example
import time
cs_pins = [7, 8, 25, 24, 23, 18, 17, 5, 12, 13]
clock_pin = 22
data_pin = 27
units = "c"
thermocouples = []
for cs_pin in cs_pins:
thermocouples.append(MAX31855(cs_pin, clock_pin, data_pin, units, type = "K"))
running = True
while(running):
try:
print "--- reading ---"
for thermocouple in thermocouples[:]:
try:
tc = thermocouple.get_sensor_and_rj(True)
print("tc: {:7.2f} and rj: {:7.2f}\traw data: {:032b})".format(tc['sensor'], tc['rj'], thermocouple.data))
except MAX31855Error as e:
print "Error: "+ e.value
#running = False
time.sleep(1)
except KeyboardInterrupt:
running = False
for thermocouple in thermocouples:
thermocouple.cleanup()