269 lines
8.9 KiB
C++
269 lines
8.9 KiB
C++
/***************************************************
|
|
|
|
This is an example for how to use Adafruit_BusIO_RegisterBits from
|
|
Adafruit_BusIO library.
|
|
|
|
Designed specifically to work with the Adafruit RTD Sensor
|
|
----> https://www.adafruit.com/products/3328
|
|
uisng a MAX31865 RTD-to-Digital Converter
|
|
----> https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
|
|
|
|
This sensor uses SPI to communicate, 4 pins are required to
|
|
interface.
|
|
A fifth pin helps to detect when a new conversion is ready.
|
|
|
|
Adafruit invests time and resources providing this open source code,
|
|
please support Adafruit and open-source hardware by purchasing
|
|
products from Adafruit!
|
|
|
|
Example written (2020/3) by Andreas Hardtung/AnHard.
|
|
BSD license, all text above must be included in any redistribution
|
|
****************************************************/
|
|
|
|
#include <Adafruit_BusIO_Register.h>
|
|
#include <Adafruit_SPIDevice.h>
|
|
|
|
#define MAX31865_SPI_SPEED (5000000)
|
|
#define MAX31865_SPI_BITORDER (SPI_BITORDER_MSBFIRST)
|
|
#define MAX31865_SPI_MODE (SPI_MODE1)
|
|
|
|
#define MAX31865_SPI_CS (10)
|
|
#define MAX31865_READY_PIN (2)
|
|
|
|
Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(
|
|
MAX31865_SPI_CS, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER,
|
|
MAX31865_SPI_MODE, &SPI); // Hardware SPI
|
|
// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, 13, 12, 11,
|
|
// MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE); // Software
|
|
// SPI
|
|
|
|
// MAX31865 chip related
|
|
// *********************************************************************************************
|
|
Adafruit_BusIO_Register config_reg =
|
|
Adafruit_BusIO_Register(&spi_dev, 0x00, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
|
|
Adafruit_BusIO_RegisterBits bias_bit =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 1, 7);
|
|
Adafruit_BusIO_RegisterBits auto_bit =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 1, 6);
|
|
Adafruit_BusIO_RegisterBits oneS_bit =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 1, 5);
|
|
Adafruit_BusIO_RegisterBits wire_bit =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 1, 4);
|
|
Adafruit_BusIO_RegisterBits faultT_bits =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 2, 2);
|
|
Adafruit_BusIO_RegisterBits faultR_bit =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 1, 1);
|
|
Adafruit_BusIO_RegisterBits fi50hz_bit =
|
|
Adafruit_BusIO_RegisterBits(&config_reg, 1, 0);
|
|
|
|
Adafruit_BusIO_Register rRatio_reg =
|
|
Adafruit_BusIO_Register(&spi_dev, 0x01, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
|
|
Adafruit_BusIO_RegisterBits rRatio_bits =
|
|
Adafruit_BusIO_RegisterBits(&rRatio_reg, 15, 1);
|
|
Adafruit_BusIO_RegisterBits fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&rRatio_reg, 1, 0);
|
|
|
|
Adafruit_BusIO_Register maxRratio_reg =
|
|
Adafruit_BusIO_Register(&spi_dev, 0x03, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
|
|
Adafruit_BusIO_RegisterBits maxRratio_bits =
|
|
Adafruit_BusIO_RegisterBits(&maxRratio_reg, 15, 1);
|
|
|
|
Adafruit_BusIO_Register minRratio_reg =
|
|
Adafruit_BusIO_Register(&spi_dev, 0x05, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST);
|
|
Adafruit_BusIO_RegisterBits minRratio_bits =
|
|
Adafruit_BusIO_RegisterBits(&minRratio_reg, 15, 1);
|
|
|
|
Adafruit_BusIO_Register fault_reg =
|
|
Adafruit_BusIO_Register(&spi_dev, 0x07, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST);
|
|
Adafruit_BusIO_RegisterBits range_high_fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 7);
|
|
Adafruit_BusIO_RegisterBits range_low_fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 6);
|
|
Adafruit_BusIO_RegisterBits refin_high_fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 5);
|
|
Adafruit_BusIO_RegisterBits refin_low_fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 4);
|
|
Adafruit_BusIO_RegisterBits rtdin_low_fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 3);
|
|
Adafruit_BusIO_RegisterBits voltage_fault_bit =
|
|
Adafruit_BusIO_RegisterBits(&fault_reg, 1, 2);
|
|
|
|
// Print the details of the configuration register.
|
|
void printConfig(void) {
|
|
Serial.print("BIAS: ");
|
|
if (bias_bit.read())
|
|
Serial.print("ON");
|
|
else
|
|
Serial.print("OFF");
|
|
Serial.print(", AUTO: ");
|
|
if (auto_bit.read())
|
|
Serial.print("ON");
|
|
else
|
|
Serial.print("OFF");
|
|
Serial.print(", ONES: ");
|
|
if (oneS_bit.read())
|
|
Serial.print("ON");
|
|
else
|
|
Serial.print("OFF");
|
|
Serial.print(", WIRE: ");
|
|
if (wire_bit.read())
|
|
Serial.print("3");
|
|
else
|
|
Serial.print("2/4");
|
|
Serial.print(", FAULTCLEAR: ");
|
|
if (faultR_bit.read())
|
|
Serial.print("ON");
|
|
else
|
|
Serial.print("OFF");
|
|
Serial.print(", ");
|
|
if (fi50hz_bit.read())
|
|
Serial.print("50HZ");
|
|
else
|
|
Serial.print("60HZ");
|
|
Serial.println();
|
|
}
|
|
|
|
// Check and print faults. Then clear them.
|
|
void checkFaults(void) {
|
|
if (fault_bit.read()) {
|
|
Serial.print("MAX: ");
|
|
Serial.println(maxRratio_bits.read());
|
|
Serial.print("VAL: ");
|
|
Serial.println(rRatio_bits.read());
|
|
Serial.print("MIN: ");
|
|
Serial.println(minRratio_bits.read());
|
|
|
|
if (range_high_fault_bit.read())
|
|
Serial.println("Range high fault");
|
|
if (range_low_fault_bit.read())
|
|
Serial.println("Range low fault");
|
|
if (refin_high_fault_bit.read())
|
|
Serial.println("REFIN high fault");
|
|
if (refin_low_fault_bit.read())
|
|
Serial.println("REFIN low fault");
|
|
if (rtdin_low_fault_bit.read())
|
|
Serial.println("RTDIN low fault");
|
|
if (voltage_fault_bit.read())
|
|
Serial.println("Voltage fault");
|
|
|
|
faultR_bit.write(1); // clear fault
|
|
}
|
|
}
|
|
|
|
void setup() {
|
|
#if (MAX31865_1_READY_PIN != -1)
|
|
pinMode(MAX31865_READY_PIN, INPUT_PULLUP);
|
|
#endif
|
|
|
|
while (!Serial) {
|
|
delay(10);
|
|
}
|
|
Serial.begin(115200);
|
|
Serial.println("SPI Adafruit_BusIO_RegisterBits test on MAX31865");
|
|
|
|
if (!spi_dev.begin()) {
|
|
Serial.println("Could not initialize SPI device");
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
// Set up for automode 50Hz. We don't care about selfheating. We want the
|
|
// highest possible sampling rate.
|
|
auto_bit.write(0); // Don't switch filtermode while auto_mode is on.
|
|
fi50hz_bit.write(1); // Set filter to 50Hz mode.
|
|
faultR_bit.write(1); // Clear faults.
|
|
bias_bit.write(1); // In automode we want to have the bias current always on.
|
|
delay(5); // Wait until bias current settles down.
|
|
// 10.5 time constants of the input RC network is required.
|
|
// 10ms worst case for 10kω reference resistor and a 0.1µF capacitor
|
|
// across the RTD inputs. Adafruit Module has 0.1µF and only
|
|
// 430/4300ω So here 0.43/4.3ms
|
|
auto_bit.write(
|
|
1); // Now we can set automode. Automatically starting first conversion.
|
|
|
|
// Test the READY_PIN
|
|
#if (defined(MAX31865_READY_PIN) && (MAX31865_READY_PIN != -1))
|
|
int i = 0;
|
|
while (digitalRead(MAX31865_READY_PIN) && i++ <= 100) {
|
|
delay(1);
|
|
}
|
|
if (i >= 100) {
|
|
Serial.print("ERROR: Max31865 Pin detection does not work. PIN:");
|
|
Serial.println(MAX31865_READY_PIN);
|
|
}
|
|
#else
|
|
delay(100);
|
|
#endif
|
|
|
|
// Set ratio range.
|
|
// Setting the temperatures would need some more calculation - not related to
|
|
// Adafruit_BusIO_RegisterBits.
|
|
uint16_t ratio = rRatio_bits.read();
|
|
maxRratio_bits.write((ratio < 0x8fffu - 1000u) ? ratio + 1000u : 0x8fffu);
|
|
minRratio_bits.write((ratio > 1000u) ? ratio - 1000u : 0u);
|
|
|
|
printConfig();
|
|
checkFaults();
|
|
}
|
|
|
|
void loop() {
|
|
#if (defined(MAX31865_READY_PIN) && (MAX31865_1_READY_PIN != -1))
|
|
// Is conversion ready?
|
|
if (!digitalRead(MAX31865_READY_PIN))
|
|
#else
|
|
// Warant conversion is ready.
|
|
delay(21); // 21ms for 50Hz-mode. 19ms in 60Hz-mode.
|
|
#endif
|
|
{
|
|
// Read ratio, calculate temperature, scale, filter and print.
|
|
Serial.println(rRatio2C(rRatio_bits.read()) * 100.0f,
|
|
0); // Temperature scaled by 100
|
|
// Check, print, clear faults.
|
|
checkFaults();
|
|
}
|
|
|
|
// Do something else.
|
|
// delay(15000);
|
|
}
|
|
|
|
// Module/Sensor related. Here Adafruit PT100 module with a 2_Wire PT100 Class C
|
|
// *****************************
|
|
float rRatio2C(uint16_t ratio) {
|
|
// A simple linear conversion.
|
|
const float R0 = 100.0f;
|
|
const float Rref = 430.0f;
|
|
const float alphaPT = 0.003850f;
|
|
const float ADCmax = (1u << 15) - 1.0f;
|
|
const float rscale = Rref / ADCmax;
|
|
// Measured temperature in boiling water 101.08°C with factor a = 1 and b = 0.
|
|
// Rref and MAX at about 22±2°C. Measured temperature in ice/water bath 0.76°C
|
|
// with factor a = 1 and b = 0. Rref and MAX at about 22±2°C.
|
|
// const float a = 1.0f / (alphaPT * R0);
|
|
const float a = (100.0f / 101.08f) / (alphaPT * R0);
|
|
// const float b = 0.0f; // 101.08
|
|
const float b = -0.76f; // 100.32 > 101.08
|
|
|
|
return filterRing(((ratio * rscale) - R0) * a + b);
|
|
}
|
|
|
|
// General purpose
|
|
// *********************************************************************************************
|
|
#define RINGLENGTH 250
|
|
float filterRing(float newVal) {
|
|
static float ring[RINGLENGTH] = {0.0};
|
|
static uint8_t ringIndex = 0;
|
|
static bool ringFull = false;
|
|
|
|
if (ringIndex == RINGLENGTH) {
|
|
ringFull = true;
|
|
ringIndex = 0;
|
|
}
|
|
ring[ringIndex] = newVal;
|
|
uint8_t loopEnd = (ringFull) ? RINGLENGTH : ringIndex + 1;
|
|
float ringSum = 0.0f;
|
|
for (uint8_t i = 0; i < loopEnd; i++)
|
|
ringSum += ring[i];
|
|
ringIndex++;
|
|
return ringSum / loopEnd;
|
|
}
|