At the moment I am running a python script to get the temperature from a PT1000 sensor via MAX31865 with my Raspberry Pi 3B+. With the python code everything works fine:
#!/usr/bin/python
import time, math
import RPi.GPIO as GPIO
class Max31865():
def initPt1000_2WireSensor(self, iCsPin, isTestMode=False):
self.csPin = iCsPin
# Pt1000 (2-wire)
self.registerCode = 0xA2
self.setupGPIO()
self.writeOutputs = isTestMode # Im Testmodus werden Infos zum Max31865 in der Konsole ausgegeben
def initPt100_3WireSensor(self, iCsPin, isTestMode=False):
self.csPin = iCsPin
# Pt100 (3-wire)
#self.registerCode = 0xB2
self.registerCode = 0xB2
self.setupGPIO()
self.writeOutputs = isTestMode # Im Testmodus werden Infos zum Max31865 in der Konsole ausgegeben
def setupGPIO(self):
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
print( "\n\n")
print ("CS: " + str(self.csPin));
print ("MISO: " + str(self.misoPin));
print ("MOSI: " + str(self.mosiPin));
print ("CLK: " + str(self.clkPin));
GPIO.setup(self.csPin, GPIO.OUT)
GPIO.setup(self.misoPin, GPIO.IN)
GPIO.setup(self.mosiPin, GPIO.OUT)
GPIO.setup(self.clkPin, GPIO.OUT)
GPIO.output(self.csPin, GPIO.HIGH)
GPIO.output(self.clkPin, GPIO.LOW)
GPIO.output(self.mosiPin, GPIO.LOW)
def getCurrentTemp(self):
# b10000000 = 0x80
# 0x8x to specify 'write register value'
# 0xx0 to specify 'configuration register'
#
# 0b10110010 = 0xB2
# Config Register - https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
# ---------------
# bit 7: Vbias -> 1 (ON)
# bit 6: Conversion Mode -> 0 (MANUAL)
# bit 5: 1-shot ->1 (ON)
# bit 4: 3-wire select -> 1 (3 wire config) (0 for 2-/4-wire)
# bit 3-2: fault detection cycle -> 0 (none)
# bit 1: fault status clear -> 1 (clear any fault)
# bit 0: 50/60 Hz filter select -> 0 (60Hz)
#
# 0b11010010 or 0xD2 for continuous auto conversion
# at 60Hz (faster conversion)
# one shot
self.writeRegister(0, self.registerCode)
# conversion time is less than 100 ms
time.sleep(.1) # give it 100ms for conversion
# read all registers
out = self.readRegisters(0, 8)
#print(str(out))
conf_reg = out[0]
#print("Config register byte: %x" % conf_reg)
[rtd_msb, rtd_lsb] = [out[1], out[2]]
rtd_ADC_Code = ((rtd_msb << 8) | rtd_lsb) >> 1
temp = self.calcTemperature(rtd_ADC_Code)
"""
# High fault threshold
[hft_msb, hft_lsb] = [out[3], out[4]]
hft = ((hft_msb << 8) | hft_lsb) >> 1
# Low fault threshold
[lft_msb, lft_lsb] = [out[5], out[6]]
lft = ((lft_msb << 8) | lft_lsb) >> 1
print ("High fault threshold: ", hft , " --- Low fault threshold: " , lft)
"""
status = out[7]
# 10 Mohm resistor is on breakout board to help
# detect cable faults
# bit 7: RTD High Threshold / cable fault open
# bit 6: RTD Low Threshold / cable fault short
# bit 5: REFIN- > 0.85 x VBias -> must be requested
# bit 4: REFIN- < 0.85 x VBias (FORCE- open) -> must be requested
# bit 3: RTDIN- < 0.85 x VBias (FORCE- open) -> must be requested
# bit 2: Overvoltage / undervoltage fault
# bits 1,0 don't care
# print "Status byte: %x" % status
if ((status & 0x80) == 1):
raise FaultError("High threshold limit (Cable fault/open)")
if ((status & 0x40) == 1):
raise FaultError("Low threshold limit (Cable fault/short)")
if ((status & 0x04) == 1):
raise FaultError("Overvoltage or Undervoltage Error")
return temp
def writeRegister(self, regNum, dataByte):
GPIO.output(self.csPin, GPIO.LOW)
# 0x8x to specify 'write register value'
addressByte = 0x80 | regNum;
# first byte is address byte
#print("Cs-Pin: ", self.csPin, "Addresse: ", addressByte)
self.sendByte(addressByte)
# the rest are data bytes
self.sendByte(dataByte)
GPIO.output(self.csPin, GPIO.HIGH)
def readRegisters(self, regNumStart, numRegisters):
out = []
GPIO.output(self.csPin, GPIO.LOW)
# 0x to specify 'read register value'
self.sendByte(regNumStart)
for byte in range(numRegisters):
data = self.recvByte()
out.append(data)
GPIO.output(self.csPin, GPIO.HIGH)
return out
def sendByte(self, byte):
print("Byte: " + str(byte))
for bit in range(8):
GPIO.output(self.clkPin, GPIO.HIGH)
print("Ja")
if (byte & 0x80):
print("Evtl")
GPIO.output(self.mosiPin, GPIO.HIGH)
else:
GPIO.output(self.mosiPin, GPIO.LOW)
byte <<= 1
GPIO.output(self.clkPin, GPIO.LOW)
def recvByte(self):
byte = 0x00
for bit in range(8):
GPIO.output(self.clkPin, GPIO.HIGH)
byte <<= 1
if GPIO.input(self.misoPin):
byte |= 0x1
GPIO.output(self.clkPin, GPIO.LOW)
return byte
def calcTemperature(self, RTD_ADC_Code):
global temp
R_REF = 0.0 # Reference Resistor
Res0 = 0.0; # Resistance at 0 degC for 400ohm R_Ref
a = 0.0
b = 0.0
c = 0.0
if (self.registerCode == 0xA2):
############# PT1000 #############
R_REF = 4300.0 # Reference Resistor
Res0 = 1000.0; # Resistance at 0 degC for 430ohm R_Ref
a = .00381
b = -.000000602
# c = -4.18301e-12 # for -200 <= T <= 0 (degC)
c = -0.000000000006
# c = 0 # for 0 <= T <= 850 (degC)
else:
############# PT100 #############
R_REF = 430.0 # Reference Resistor
Res0 = 100.0; # Resistance at 0 degC for 430ohm R_Ref
a = .00390830
b = -.000000577500
# c = -4.18301e-12 # for -200 <= T <= 0 (degC)
c = -0.00000000000418301
# c = 0 # for 0 <= T <= 850 (degC)
Res_RTD = (RTD_ADC_Code * R_REF) / 32768.0 # PT1000 Resistance
# if(self.writeOutputs):
# print("CS-Pin: " , self.csPin, " --- ADC-Value: ", RTD_ADC_Code , " --- Resistance: ", round(Res_RTD, 2) , " Ohms")
# Callendar-Van Dusen equation
# Res_RTD = Res0 * (1 + a*T + b*T**2 + c*(T-100)*T**3)
# Res_RTD = Res0 + a*Res0*T + b*Res0*T**2 # c = 0
# (c*Res0)T**4 - (c*Res0)*100*T**3
# + (b*Res0)*T**2 + (a*Res0)*T + (Res0 - Res_RTD) = 0
#
# quadratic formula:
# for 0 <= T <= 850 (degC)
temp = -(a * Res0) + math.sqrt(a * a * Res0 * Res0 - 4 * (b * Res0) * (Res0 - Res_RTD))
temp = round(temp / (2 * (b * Res0)), 2)
temp_line = round((RTD_ADC_Code / 32.0) - 256.0, 2)
# removing numpy.roots will greatly speed things up
# temp_C_numpy = numpy.roots([c*Res0, -c*Res0*100, b*Res0, a*Res0, (Res0 - Res_RTD)])
# temp_C_numpy = abs(temp_C_numpy[-1])
# if(self.writeOutputs):
# print ("CS-Pin: " , self.csPin, " --- Straight Line Approx. Temp: ", temp_line , " --- Callendar-Van Dusen Temp: " , temp)
# print "Solving Full Callendar-Van Dusen using numpy: %f" % temp_C_numpy
if (temp < 0): # use straight line approximation if less than 0
# Can also use python lib numpy to solve cubic
# Should never get here in this application
temp = (RTD_ADC_Code / 32) - 256
if(self.writeOutputs):
print ("CSPin " , self.csPin, " - ADC: ", RTD_ADC_Code , " - Resistance: ", round(Res_RTD, 2) , " Ohms - Temp: " , temp)
return temp
##############################################################################################################################
# Program start #
###############################################################################################################################
csPin = 24
misoPin = 21
mosiPin = 19
clkPin = 23
registerCode = 0
# BOARD:21,19,23
# BCM: 9,10,11
class FaultError(Exception):
pass
Now I tried to do the same logic just with Java code. The Problem is that the temperature is always -256 degrees. The reason for this is that the GPIO PIN 21 ("MISO") is never in state "HIGH"/1 (line 207 is never true):
import com.pi4j.io.gpio.*;
import java.nio.ByteBuffer;
public class Max31865 {
private static GpioController gpio;
private int registerCode;
private GpioPinDigitalOutput csPin;
private GpioPinDigitalInput misoPin;
private GpioPinDigitalOutput mosiPin;
private GpioPinDigitalOutput clkPin;
private String name;
public Max31865(String name, Pin clk, Pin miso, Pin mosi, Pin cs, boolean pt1000_2wire) {
this.name = name;
// logger.info("Init MAX31865 (" + name + ")");
gpio = GpioFactory.getInstance();
if (pt1000_2wire) {
// 2 Wire PT1000
this.registerCode = 0xA2;
} else {
// 3 Wire PT100
this.registerCode = 0xB2;
}
setupGPIO(cs, miso, mosi, clk);
}
private void setupGPIO(Pin cs, Pin miso, Pin mosi, Pin clk) {
System.out.println("CS: " + cs.getAddress());
System.out.println("MISO: " + miso.getAddress());
System.out.println("MOSI: " + mosi.getAddress());
System.out.println("CLK: " + clk.getAddress());
this.csPin = gpio.provisionDigitalOutputPin(cs);
this.misoPin = gpio.provisionDigitalInputPin(miso);
this.mosiPin = gpio.provisionDigitalOutputPin(mosi);
this.clkPin = gpio.provisionDigitalOutputPin(clk);
// this.csPin.setShutdownOptions(true, PinState.LOW);
// this.misoPin.setShutdownOptions(true, PinState.LOW,
// PinPullResistance.OFF);
// this.mosiPin.setShutdownOptions(true, PinState.LOW);
// this.clkPin.setShutdownOptions(true, PinState.LOW);
this.csPin.high();
this.clkPin.low();
this.mosiPin.low();
}
public double getCurrentTemp() {
writeRegister(0, registerCode);
try {
// COnversion time is less than 100 ms
Thread.sleep(100);
} catch (InterruptedException ex) {
System.out.print(ex.toString());
}
byte[] bArray = readRegister(0, 8);
// System.out.print("bArray: " + bArray);
// int conf_reg = bArray[0];
int conf_reg = 0;
if (bArray[0] < 0) {
conf_reg = 256 + bArray[0];
} else {
conf_reg = bArray[0];
}
// System.out.println(String.valueOf(bArray[0]));
int rtd_msb = 0;
if (bArray[1] < 0) {
rtd_msb = 256 + bArray[1];
} else {
rtd_msb = bArray[1];
}
int rtd_lsb = 0;
if (bArray[2] < 0) {
rtd_lsb = 256 + bArray[2];
} else {
rtd_lsb = bArray[2];
}
// System.out.print("rtd_msb: " + rtd_msb);
// System.out.print("rtd_lsb: " + rtd_lsb);
int rtd_ADC_Code = ((rtd_msb << 8) | rtd_lsb) >> 1;
byte status = bArray[7];
if ((status & 0x80) == 1) {
// logger.warn("High threshold limit (Cable fault/open)");
System.out.println("High threshold limit (Cable fault/open)");
}
if ((status & 0x40) == 1) {
// logger.warn("Low threshold limit (Cable fault/short)");
System.out.println("Low threshold limit (Cable fault/short)");
}
if ((status & 0x04) == 1) {
// logger.warn("Overvoltage or Undervoltage Error");
System.out.println("Overvoltage or Undervoltage Error");
}
return calcTemperature(rtd_ADC_Code);
}
private double calcTemperature(int rtd_ADC_Code) {
double R_REF = 0.0; // Reference Resistor
double Res0 = 0.0; // Resistance at 0 degC for 400ohm R_Ref
double a = 0.0;
double b = 0.0;
double c = 0.0;
if (registerCode == 0xA2) {
// ############# PT1000 #############
R_REF = 4300.0; // Reference Resistor
Res0 = 1000.0; // Resistance at 0 degC for 4300ohm R_Ref
a = .00381;
b = -.000000602;
// c = -4.18301e-12 # for -200 <= T <= 0 (degC)
c = -0.000000000006;
// c = 0 # for 0 <= T <= 850 (degC)
} else {
// ############# PT100 #############
R_REF = 430.0; // Reference Resistor
Res0 = 100.0; // Resistance at 0 degC for 430ohm R_Ref
a = .00390830;
b = -.000000577500;
// # c = -4.18301e-12; # for -200 <= T <= 0 (degC)
c = -0.00000000000418301;
// # c = 0 # for 0 <= T <= 850 (degC)
}
double Res_RTD = (rtd_ADC_Code * R_REF) / 32768.0; // PT1000 Resistance
double temp, temp_line;
temp = -(a * Res0) + Math.sqrt(a * a * Res0 * Res0 - 4 * (b * Res0) * (Res0 - Res_RTD));
temp = round(temp / (2 * (b * Res0)), 2);
temp_line = round((rtd_ADC_Code / 32.0) - 256.0, 2);
if (temp < 0) { // use straight line approximation if less than 0
temp = (rtd_ADC_Code / 32) - 256;
}
return temp;
}
private void writeRegister(int regNum, int dataByte) {
csPin.low();
// 0x8x to specify 'write register value'
int addressByte = 0x80 | regNum;
// first byte is address byte
sendByte(addressByte);
// the rest are data bytes
sendByte(dataByte);
csPin.high();
}
private byte[] readRegister(int regNumStart, int numRegisters) {
ByteBuffer out = ByteBuffer.allocate(1024);
csPin.low();
sendByte(regNumStart);
for (int i = 0; i < numRegisters; i++) {
int bInt = recvByte();
out.put(i, (byte) bInt);
}
csPin.high();
return out.array();
}
private void sendByte(int byteToSend) {
String bString = Integer.toBinaryString(byteToSend);
if (bString.length() < 8) {
bString = String.format("%08d", Integer.parseInt(bString));
} else if (bString.length() > 8) {
// logger.warn("Wrong byte:" + bString);
System.out.println("Wrong byte:" + bString);
}
for (int i = 0; i < bString.length(); i++) {
clkPin.high();
boolean v = (Integer.parseInt(bString.substring(i, i + 1)) != 0);
if (v) {
mosiPin.high();
} else {
mosiPin.low();
}
clkPin.low();
}
}
private int recvByte() {
int byt = 0x00;
for (int i = 0; i < 8; i++) {
clkPin.high();
byt <<= 1;
if (misoPin.isHigh()) {
byt |= 0x1;
}
clkPin.low();
}
return byt;
}
private double round(double zahl, int stellen) {
return (double) ((int) zahl
+ (Math.round(Math.pow(10, stellen) * (zahl - (int) zahl))) / (Math.pow(10, stellen)));
}
public static final byte[] intToByteArray(int value) {
return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value };
}
public static void main(String[] args) throws InterruptedException {
Max31865 temp = new Max31865("Test", RaspiPin.GPIO_23, RaspiPin.GPIO_21, RaspiPin.GPIO_19, RaspiPin.GPIO_24,
true);
int cnt = 3;
while (cnt > 0) {
System.out.println("Temp: " + temp.getCurrentTemp());
Thread.sleep(1000);
cnt--;
}
}
}
On my Raspberry java-11-openjdk-armhf is installed.
Any ideas or experiences with similar behavior?
Udpate: After several reboots, the MISO is always LOW or always HIGH after a reboot. Debugging as well as using "!pin.IsLow()" instead of "pin.isHigh()" also do not work :(