Compare commits
2 commits
faf0e5421f
...
25ce0ebdff
Author | SHA1 | Date | |
---|---|---|---|
|
25ce0ebdff | ||
|
df8ae2263d |
254
Misc/Temp-Monitor/cs1237.py
Normal file
254
Misc/Temp-Monitor/cs1237.py
Normal file
|
@ -0,0 +1,254 @@
|
|||
# From: https://github.com/robert-hh/CS1237/blob/f442365eab14fb0b8e2df3858ee46e70bfb56536/cs1237.py
|
||||
|
||||
# MIT License
|
||||
|
||||
# Copyright (c) 2024 Robert Hammelrath
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from machine import Pin
|
||||
import time
|
||||
import micropython
|
||||
|
||||
_CMD_READ = const(0x56)
|
||||
_CMD_WRITE = const(0x65)
|
||||
|
||||
|
||||
class CS1237:
|
||||
_gain = {1: 0, 2: 1, 64: 2, 128: 3}
|
||||
_rate = {10: 0, 40: 1, 640: 2, 1280: 3}
|
||||
|
||||
def __init__(self, clock, data, gain=64, rate=10, channel=0):
|
||||
self.clock = clock
|
||||
self.data = data
|
||||
self.data.init(mode=Pin.IN)
|
||||
self.clock.init(mode=Pin.OUT)
|
||||
self.clock(0)
|
||||
# determine the number of attempts to find the trigger pulse
|
||||
start = time.ticks_us()
|
||||
for _ in range(10):
|
||||
temp = data()
|
||||
spent = time.ticks_diff(time.ticks_us(), start)
|
||||
self.__wait_loop = 4_000_000 // spent
|
||||
self.config(gain, rate, channel)
|
||||
# pre-set some values for temperature calibration.
|
||||
self.ref_value = 769000
|
||||
self.ref_temp = 20
|
||||
self.init = self.config
|
||||
self.buffer_full = False
|
||||
|
||||
def __repr__(self):
|
||||
return "{}(gain={}, rate={}, channel={})".format(self.__qualname__, *self.get_config())
|
||||
|
||||
def __call__(self):
|
||||
return self.read()
|
||||
|
||||
def __write_bits(self, value, mask):
|
||||
clock = self.clock
|
||||
data = self.data
|
||||
while mask != 0:
|
||||
clock(1)
|
||||
data(1 if (value & mask) != 0 else 0)
|
||||
clock(0)
|
||||
mask >>= 1
|
||||
|
||||
def __read_bits(self, bits=1):
|
||||
# duplicate the clock high call to extend the positive pulse
|
||||
clock = self.clock
|
||||
data = self.data
|
||||
value = 0
|
||||
for _ in range(bits):
|
||||
clock(1)
|
||||
clock(1)
|
||||
clock(0)
|
||||
value = (value << 1) | data()
|
||||
return value
|
||||
|
||||
def __write_status(self):
|
||||
# get the config write status bits
|
||||
return self.__read_bits(3) >> 1
|
||||
|
||||
def __write_cmd(self, cmd):
|
||||
# clock bits 25 and 29, telling that a command follows
|
||||
clock = self.clock
|
||||
for _ in range(5):
|
||||
clock(1)
|
||||
clock(1)
|
||||
clock(0)
|
||||
# write the command word + 1 extra clock cycle
|
||||
self.data.init(mode=Pin.OUT)
|
||||
self.__write_bits(cmd << 1, 0x80)
|
||||
|
||||
def __write_config(self, config):
|
||||
value = self.read() # get the ADC value
|
||||
self.__write_cmd(_CMD_WRITE)
|
||||
# write the configuration byte + the 46th clock cycle
|
||||
self.__write_bits(config << 1, 0x100)
|
||||
self.data.init(mode=Pin.IN)
|
||||
return value
|
||||
|
||||
def __read_config(self):
|
||||
value = self.read() # get the ADC value
|
||||
self.__write_cmd(_CMD_READ)
|
||||
self.data.init(mode=Pin.IN)
|
||||
# read the configuration byte + 1 extra clock cycle
|
||||
# And return both config and value
|
||||
return self.__read_bits(9) >> 1, value
|
||||
|
||||
def __drdy_cb(self, data):
|
||||
self.data.irq(handler=None)
|
||||
self.__drdy = True
|
||||
|
||||
def read(self):
|
||||
# Set up the trigger for conversion enable.
|
||||
self.__drdy = False
|
||||
self.data.irq(trigger=Pin.IRQ_FALLING, handler=self.__drdy_cb)
|
||||
# Wait for the DRDY event
|
||||
for _ in range(20000):
|
||||
if self.__drdy is True:
|
||||
break
|
||||
time.sleep_us(50)
|
||||
else:
|
||||
self.__drdy = False
|
||||
self.data.irq(handler=None)
|
||||
raise OSError("Sensor does not respond")
|
||||
# Get the data.
|
||||
result = self.__read_bits(24)
|
||||
# Check the sign.
|
||||
if result > 0x7FFFFF:
|
||||
result -= 0x1000000
|
||||
|
||||
return result
|
||||
|
||||
def align_buffer(self, buffer):
|
||||
for i in range(len(buffer)):
|
||||
if buffer[i] > 0x7FFFFF:
|
||||
buffer[i] -= 0x1000000
|
||||
self.data_acquired = True
|
||||
|
||||
def __buffer_cb(self, data):
|
||||
self.data.irq(handler=None)
|
||||
# Check the sign later when it's time to do so
|
||||
if self.buffer_index < self.buffer_size:
|
||||
self.buffer[self.buffer_index] = self.__read_bits(24)
|
||||
self.buffer_index += 1
|
||||
self.data.irq(trigger=Pin.IRQ_FALLING, handler=self.__buffer_cb)
|
||||
else:
|
||||
micropython.schedule(self.align_buffer, self.buffer)
|
||||
|
||||
def read_buffered(self, buffer):
|
||||
self.data_acquired = False
|
||||
self.buffer = buffer
|
||||
self.buffer_size = len(buffer)
|
||||
self.buffer_index = 0
|
||||
self.data.irq(trigger=Pin.IRQ_FALLING, handler=self.__buffer_cb)
|
||||
|
||||
def get_config(self):
|
||||
config, _ = self.__read_config()
|
||||
return (
|
||||
{value: key for key, value in self._gain.items()}[config >> 2 & 0x03],
|
||||
{value: key for key, value in self._rate.items()}[config >> 4 & 0x03],
|
||||
config & 0x03,
|
||||
)
|
||||
|
||||
def config_status(self):
|
||||
self.read() ## dummy read value
|
||||
return self.__write_status() >> 1
|
||||
|
||||
def config(self, gain=None, rate=None, channel=None):
|
||||
if gain is not None:
|
||||
if gain not in self._gain.keys():
|
||||
raise ValueError("Invalid Gain")
|
||||
self.gain = self._gain[gain]
|
||||
if rate is not None:
|
||||
if rate not in self._rate.keys():
|
||||
raise ValueError("Invalid rate")
|
||||
self.rate = self._rate[rate]
|
||||
if channel is not None:
|
||||
if not 0 <= channel <= 3:
|
||||
raise ValueError("Invalid channel")
|
||||
self.channel = channel
|
||||
config = self.rate << 4 | self.gain << 2 | self.channel
|
||||
self.__write_config(config)
|
||||
|
||||
def calibrate_temperature(self, temp, ref_value=None):
|
||||
self.ref_temp = temp
|
||||
if ref_value is None:
|
||||
config, self.ref_value = self.__read_config()
|
||||
if config != 0x02:
|
||||
# Set gain=1, rate=10, channel=2 (temperature)
|
||||
self.__write_config(0x02)
|
||||
# Read the value and restore the previous configuration
|
||||
self.ref_value = self.__write_config(config)
|
||||
else:
|
||||
self.ref_value = ref_value
|
||||
|
||||
def temperature(self):
|
||||
config, value = self.__read_config()
|
||||
if config != 0x02:
|
||||
# set gain=1, rate=10, channel=2 (temperature)
|
||||
self.__write_config(0x02)
|
||||
# Read the value and restore the previous configuration
|
||||
value = self.__write_config(config)
|
||||
return value / self.ref_value * (273.15 + self.ref_temp) - 273.15
|
||||
|
||||
def power_down(self):
|
||||
self.clock(0)
|
||||
self.clock(1)
|
||||
|
||||
def power_up(self):
|
||||
self.clock(0)
|
||||
|
||||
class CS1238(CS1237):
|
||||
pass
|
||||
|
||||
class CS1237P(CS1237):
|
||||
|
||||
def read(self):
|
||||
data = self.data
|
||||
# wait for the trigger pulse
|
||||
start = time.ticks_ms()
|
||||
for _ in range(self.__wait_loop):
|
||||
if data():
|
||||
break
|
||||
else:
|
||||
raise OSError("No trigger pulse found")
|
||||
for _ in range(5000):
|
||||
if not data():
|
||||
break
|
||||
time.sleep_us(50)
|
||||
else:
|
||||
raise OSError("Sensor does not respond")
|
||||
result = self.__read_bits(24)
|
||||
# check the sign.
|
||||
if result > 0x7FFFFF:
|
||||
result -= 0x1000000
|
||||
|
||||
return result
|
||||
|
||||
def read_buffered(self, buffer):
|
||||
self.data_acquired = False
|
||||
self.buffer = buffer
|
||||
self.buffer_size = len(buffer)
|
||||
for i in range(self.buffer_size):
|
||||
self.buffer[i] = self.read()
|
||||
self.data_acquired = True
|
||||
|
||||
class CS1238P(CS1237P):
|
||||
pass
|
20
Misc/Temp-Monitor/firmware.py
Normal file
20
Misc/Temp-Monitor/firmware.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import time
|
||||
from cs1237 import CS1237
|
||||
from machine import Pin
|
||||
|
||||
clock = Pin(2)
|
||||
data = Pin(4)
|
||||
|
||||
cs1237 = CS1237(clock, data)
|
||||
cs1237.config(gain=1)
|
||||
|
||||
while True:
|
||||
raw_value = cs1237.read()
|
||||
value = float(raw_value) / (2**23 - 1)
|
||||
if value > 0.9999:
|
||||
value = 0
|
||||
else:
|
||||
value = 1 / (1 / value - 1)
|
||||
temperature = 25 - value
|
||||
if abs(temperature) < 50:
|
||||
print(temperature)
|
Loading…
Reference in a new issue