Interfacing a MS8607 sensor with Python using the bus pirate
A couple of days ago, I’ve read about Scott Harden’s interesting approach of interfacing a twi temperature sensor by using Python and Hack-a-day’s bus pirate. Quite accidentally, I had an similar problem. For some experiments I need a good knowledge about my environmental sizes (e.g. ambient pressure, temperature and humidity). I decided to use a MS8607 sensor produced by “Measurement Specialities / TE Connectivity” and is distributed for example by AMSYS. I’ve got some modules and started reading the datasheet. Due a permanent lack of time I was searching for a good and simple way for testing the sensor interface without the whole prototype circus (e.g. design and build some interface cards, testing the code by using debug interfaces and so on). Scott’s solution was simple and I had all tools already available, so I started to adapt his code for my needs.
1 Calculations
Difference between actual and reference temperature : $$\Delta T = D_2 - C_5 \cdot 2^8 $$ Offset for temperature compensated pressure : $$OFF = C_2 \cdot 2^{17} + \frac{C_4 \cdot \Delta T} {2^6}$$ Sensivity for actual temperature : $$SENS = C_1 \cdot 2^{16} + \frac{C_3 \cdot \Delta T}{2^7}$$
Temperature (in 0.01 °C resolution) : $$T = 2000 + \Delta T \cdot \frac{C_6}{2^{23}}$$ Pressure (in 0.01 mbar resolution): $$P = \frac{\dfrac{D_1 \cdot SENS}{2^{21}} - OFF}{2^{15}}$$ Relative humidity (in %) : $$RH = -6 + 125 \cdot \frac{S_{RH}}{2^{16}}$$
import serial
import math
import matplotlib.pyplot as plt
import numpy as np
import time
BUSPIRATE_PORT = 'com5' #customize this! Find it in device manager.
def sendPirate(ser,cmd,silent=True):
"""
send the command and listen to the response.
returns a list of the returned lines.
The first item is always the command sent.
"""
ser.write(str(cmd+'\n').encode('ascii')) # send our command
lines=[]
for line in ser.readlines(): # while there's a response
lines.append(line.decode('utf-8').strip())
if not silent:
print("\n".join(lines))
print('-'*60)
return lines
def sendSensor( ser, register, addrwrite=0xEC, addrread=0xED, silent=True):
"""
Sending data to sensor by using the bus priate device
"""
sendPirate (ser,'[%s %s]' % (addrwrite, register), silent=silent) # read two bytes
def readSensor (ser, noBytes, register=0x00, addrwrite=0xEC, addrread=0xED, readonly=False, silent=True):
"""
Reading data from sensor by using the bus priate device.
"""
if not readonly:
lines=sendPirate(ser,'[%s %s [ %s r:%d]' % (addrwrite, register, addrread, noBytes ) ,silent=silent) # read three bytes from adc
else:
lines=sendPirate(ser,'[%s r:%d]' % ( addrread, noBytes ) ,silent=silent) # read three bytes from adc
for line in lines:
if line.startswith("READ:"):
line=line.split(" ",1)[1].replace("ACK",'')
while " " in line:
line=" "+line.strip().replace(" "," ")
word = 0
validx = 1
line=" "+line.strip().replace("0x"," ")
vals = line.split(" ")
vals=' '.join(vals).split()
nVals = len(vals)
for iVal in vals:
cVal = int(iVal, 16)
word += cVal * math.pow ( 2 , 8 * (nVals - validx ) )
validx +=1
return int(word)
def getPressure( ser, addrwrite=0xEC, register=0x4A, addrread=0xED, silent=False):
"""
get ambient pressure
"""
sendSensor ( ser, register, silent=silent )
time.sleep ( 0.5 )
word = readSensor ( ser, 3, 0x00, addrwrite, addrread, readonly=False, silent=silent )
return int(word)
def getTemperature( ser, addrwrite=0xEC, register=0x5A, addrread=0xED, silent=False):
sendSensor ( ser, register, silent=silent)
time.sleep (0.5)
word = readSensor ( ser, 3, 0x00, addrwrite, addrread, readonly=False, silent=silent )
return int(word)
def getHumidity( ser, addrwrite=0x80, register=0xA0, addrread=0x81, silent=False):
# start humidity conversion
# 0xF5 no hold master
# 0xE5 hold master
sendSensor ( ser, 0xF5, addrwrite=addrwrite, addrread=addrread, silent=silent )
time.sleep(0.5)
word = readSensor ( ser, 2, register, addrwrite, addrread, readonly=True, silent=silent )
return int(word)
def getCalibrationWord( ser, register, addrwrite=0xEC, addrread=0xED, silent=False):
word = readSensor ( ser, 2, register, addrwrite, addrread, readonly=False, silent=silent )
return int(word)
def initpirate(ser, silent=False):
# have a clean starting point
sendPirate(ser,'#',silent=silent) # reset bus pirate (slow, maybe not needed)
#sendPirate(ser,'v') # show current voltages
# set mode to I2C
sendPirate(ser,'m',silent=silent) # change mode (goal is to get away from HiZ)
sendPirate(ser,'4',silent=silent) # mode 4 is I2C
sendPirate(ser,'3',silent=silent) # 100KHz
sendPirate(ser,'W',silent=silent) # turn power supply to ON. Lowercase w for OFF.
sendPirate(ser,'P',silent=silent) # enable pull-up resistors
sendPirate(ser,'(1)',silent=silent) # scan I2C devices. Returns "0x90(0x48 W) 0x91(0x48 R)"
def initSensor ( ser, silent=False):
sendSensor ( ser, 0x1E,silent=silent )
time.sleep ( 0.5 )
# reset humidity sensor
sendSensor ( ser, 0xFE , addrwrite=0x80, addrread=0x81, silent=silent )
time.sleep (0.3)
PTCal = getPTCalibrationData ( ser, silent=silent )
return PTCal
def getPTCalibrationData(ser, silent=False ):
PTCalibration=[]
for i in range(0,6):
PTCalibration.append (getCalibrationWord( ser, register=(0xA2 + 2*i),silent=silent) )
if not silent:
print ( "register 0x%X => 0x%X" % ( int(0xA2 + 2*i) , PTCalibration[i] ))
return PTCalibration
ser=serial.Serial(BUSPIRATE_PORT, 115200, timeout=.1)
# init buspirate
initpirate(ser,silent=True)
# reset PT sensor
PTCal= initSensor(ser, silent=True )
# start pressure conversion
D1 = getPressure ( ser, silent=True )
# start temperature conversion
D2 = getTemperature ( ser , silent=True)
dT = D2 - PTCal[4] * 256
Temp = 2000 + dT * PTCal[5] / 8388608
OFF = PTCal[1] * 131072 + (PTCal[3] * dT) / 64
SENS = PTCal[0] * 65536 + (PTCal[2] * dT ) / 128
if Temp >= 2000 :
Ti = 5 * (dT * dT) / 274877906944
OFFi = 0
SENSi= 0
elif Temp < 2000 :
Ti = 3 * (dT * dT) / 8589934592
OFFi = 61 * ((Temp - 2000) * (Temp - 2000)) / 16
SENSi= 29 * ((Temp - 2000) * (Temp - 2000)) / 16
if Temp < -1500:
OFFi = OFFi + 17 * ((Temp + 1500) * (Temp + 1500))
SENSi= SENSi + 9 * ((Temp + 1500) * (Temp +1500))
OFF2 = OFF - OFFi
SENS2 = SENS - SENSi
cTemp = (Temp - Ti) / 100.0
fTemp = cTemp * 1.8 + 32
pressure= ((((D1 * SENS2) / 2097152) - OFF2) / 32768.0) / 100.0
D3 = getHumidity ( ser, silent=True )
humidity= (-6.0 + (125.0 * (D3 / 65536.0)))
print ( "Temperature %2.2f °C / Pressure %3.2f mbar / Humidity %3.1f %%" % ( cTemp , pressure, humidity ))