max31865 Lua NodeMCU library

I made a thing...
max31865 Lua NodeMCU library - https://datasheets.maximintegrated.com/ ... X31865.pdf
A simplified interface for PT-RTD thermometers using the adafruit max31865 module. (most other max31865 modules are identical)
- depends on spi and bit libraries -
PT-RTD thermometers have become an extremely cheap source of highly accurate temperature sensing. The MAX31865 doesn't do all the work for you however, and temperature conversion and calibration are left up to the user. This library seeks to make it extremely fast to hook up the module and get right to measuring temperature while at the same time being capable of fairly high accuracy.
Simple Usage:
Configuration:
Several configuration items are accessable via the config method.
Calibration:
By default the library assumes the burden resistor on your module is perfectly 430 ohms, and your temperature probe is perfectly 100 ohms at 0C. A single
point calibration with the freezing point of distilled water can get you quite a lot closer accuracy.
Advanced Calibration:
A single point calibration is not perfect, and the most advanced systems fully characterize the temperature probe with three constants used in the Callendar-Van Dusen equation: A, B, and C. If you pay a lot of money, you can sometimes purchase pre-characterized probes that may come with these values. Newton's method is then used to calculate this equation, and the number of approximations may be adjusted as desired. This is a fairly heavy equation, so keep in mind processing time and the ever present watchdog timer. In my testing, 5 iterations seemed plenty to get an accurate value. The Zero point depends on the probe as well as the burden resistor, and will still need to be calibrated.
Advanced usage:
The intent of using a library is to simplify one's life, so some of the advanced modes (fault detection) are not explicitly set up with this library. They can still be accessed without too much trouble using the `_spi_transaction` method. See the datasheet (link at top of page) for more information.
MAX31865.lua
max31865 Lua NodeMCU library - https://datasheets.maximintegrated.com/ ... X31865.pdf
A simplified interface for PT-RTD thermometers using the adafruit max31865 module. (most other max31865 modules are identical)
- depends on spi and bit libraries -
PT-RTD thermometers have become an extremely cheap source of highly accurate temperature sensing. The MAX31865 doesn't do all the work for you however, and temperature conversion and calibration are left up to the user. This library seeks to make it extremely fast to hook up the module and get right to measuring temperature while at the same time being capable of fairly high accuracy.
Simple Usage:
Code: Select all
> max31865 = require('MAX31865')
> thermometer = max31865.setup(4) --spi CS on pin 4
> print(thermometer:temp()) --read temperature in C
25.514875945444
Configuration:
Several configuration items are accessable via the config method.
- run_stop: A value of max31865.RUN will turn on the bias voltage to the RTD, and begin sampling the ADC in continuous mode. A value of max31865.STOP will turn off the burden voltage and sampling to conserve power. Readings should be taken after power is on for a little while to allow adc to stabalize, and sensor self-heating to level out (see datasheet).
- wires: max31865.TWO_WIRE, max31865.THREE_WIRE, max31865.FOUR_WIRE. Are you using a 2-wire 3-wire or 4-wire RTD? remember to set the solder pads accordingly as well.
- filter: An included filter intended to reject noise from mains power at either 50Hz or 60Hz. Choose according to your local mains power specification: max31865.FILTER_50, max31865.FILTER_60
Code: Select all
> thermometer:config(max31865.RUN, max31865.THREE_WIRE, max31865.FILTER_60)
> -- ^this is the default config when thermometer:setup() is called
Calibration:
By default the library assumes the burden resistor on your module is perfectly 430 ohms, and your temperature probe is perfectly 100 ohms at 0C. A single
point calibration with the freezing point of distilled water can get you quite a lot closer accuracy.
Code: Select all
> print(thermometer:adc()) --stick thermometer in ice water to calibrate 0C
7635
> thermometer.adc_zero = 7635
Advanced Calibration:
A single point calibration is not perfect, and the most advanced systems fully characterize the temperature probe with three constants used in the Callendar-Van Dusen equation: A, B, and C. If you pay a lot of money, you can sometimes purchase pre-characterized probes that may come with these values. Newton's method is then used to calculate this equation, and the number of approximations may be adjusted as desired. This is a fairly heavy equation, so keep in mind processing time and the ever present watchdog timer. In my testing, 5 iterations seemed plenty to get an accurate value. The Zero point depends on the probe as well as the burden resistor, and will still need to be calibrated.
Code: Select all
> max31865._A = 3.908300e-3
> max31865._B = -5.77500e-7
> max31865._C = -4.18301e-12
> max31865._root_find_iterations = 5
> print(thermometer:adc()) --stick thermometer in ice water to calibrate 0C
7635
> thermometer.adc_zero = 7635
Advanced usage:
The intent of using a library is to simplify one's life, so some of the advanced modes (fault detection) are not explicitly set up with this library. They can still be accessed without too much trouble using the `_spi_transaction` method. See the datasheet (link at top of page) for more information.
Code: Select all
> =encoder.toHex(thermometer:_spi_transaction('\3', 2)) --read fault Hi register
> thermometer:_spi_transaction('\128\208', 0) --write 0xd0 to config register
MAX31865.lua
Code: Select all
--MAX31865.lua
if spi == nil or bit == nil then
error("max31865 Lua requires the spi and bit libraries")
end
spi.setup(1, spi.MASTER, spi.CPOL_HIGH, spi.CPHA_HIGH, 8, 40)
local max31865 = {}
max31865.RUN = 1
max31865.STOP = 0
max31865.FOUR_WIRE = 0
max31865.THREE_WIRE = 1
max31865.TWO_WIRE = 0
max31865.FILTER_50 = 1
max31865.FILTER_60 = 0
max31865._A = 3.908300e-3
max31865._B = -5.77500e-7
max31865._C = -4.18301e-12
max31865._root_find_iterations = 5
local _CVD_root_finder = function(r0, R)
--The Callendar Van Dusen Equation for Platinum Based RTD Thermometers
--Newton's method root finder
local T = 0
local a, b, c = max31865._A, max31865._B , max31865._C
local i = max31865._root_find_iterations
for _ = 1,i do
if T < 0 then
local r = r0 * (1 + a*T + b*T*T + c*(T - 100)*T*T*T) - R
local slope = r0 * (a + 2*b*T + 4*c*(T - 75)*T*T)
T = T - r/slope
else
local r = r0 * (1 + a*T + b*T*T) - R
local slope = r0 * (a + 2*b*T)
T = T - r/slope
end
end
return T
end
max31865.setup = function(CS, config)
local t = {}
--chip select gpio setup
t._CS = CS
gpio.mode(t._CS, gpio.OUTPUT)
gpio.write(t._CS, gpio.HIGH)
t._spi_transaction = function(self, write_data, read_bytes)
spi.set_mosi(1, write_data)
gpio.write(self._CS, 0)
spi.transaction( 1, 0, 0, 0, 0, #write_data * 8, 0, read_bytes * 8)
gpio.write(self._CS, 1)
return spi.get_miso(1, read_bytes)
end
t._config = config or 0xd0 --0b11010000 default
-- see: https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
t.config = function(self, run_stop, wires, filter)
if run_stop ~= nil then
if run_stop == 1 then
self._config = bit.set(self._config, 7)
self._config = bit.set(self._config, 6)
elseif run_stop == 0 then
self._config = bit.clear(self._config, 7)
self._config = bit.clear(self._config, 6)
end
end
if wires ~= nil then
if wires == 1 then
self._config = bit.set(self._config, 4)
elseif wires == 0 then
self._config = bit.clear(self._config, 4)
end
end
if filter ~= nil then
if filter == 1 then
self._config = bit.set(self._config, 0)
elseif filter == 0 then
self._config = bit.clear(self._config, 0)
end
end
self:_spi_transaction('\128' .. string.char(self._config), 0)
end
t.adc = function(self)
local raw = self:_spi_transaction('\1',2)
return bit.rshift(string.byte(raw,1) * 256 + string.byte(raw, 2), 1)
end
t.resistance = function(self, Rref)
Rref = Rref or 430
return (self:adc() * Rref) / 32768
end
--default zero point for ideal 100ohm PRT and ideal 430ohm burden resistor: 7620.5
t.adc_zero = 7620.5
t.temp = function(self)
return _CVD_root_finder(self.adc_zero, self:adc())
end
t:config()
return t
end
return max31865