diff --git a/lib/max6675.py b/lib/max6675.py new file mode 100644 index 0000000..bfe3fa9 --- /dev/null +++ b/lib/max6675.py @@ -0,0 +1,125 @@ +#!/usr/bin/python +import RPi.GPIO as GPIO +import time + +class MAX6675(object): + '''Python driver for [MAX6675 Cold-Junction Compensated Thermocouple-to-Digital Converter](http://www.adafruit.com/datasheets/MAX6675.pdf) + Requires: + - The [GPIO Library](https://code.google.com/p/raspberry-gpio-python/) (Already on most Raspberry Pi OS builds) + - A [Raspberry Pi](http://www.raspberrypi.org/) + + ''' + def __init__(self, cs_pin, clock_pin, data_pin, units = "c", board = GPIO.BCM): + '''Initialize Soft (Bitbang) SPI bus + + Parameters: + - cs_pin: Chip Select (CS) / Slave Select (SS) pin (Any GPIO) + - clock_pin: Clock (SCLK / SCK) pin (Any GPIO) + - data_pin: Data input (SO / MOSI) pin (Any GPIO) + - units: (optional) unit of measurement to return. ("c" (default) | "k" | "f") + - board: (optional) pin numbering method as per RPi.GPIO library (GPIO.BCM (default) | GPIO.BOARD) + + ''' + self.cs_pin = cs_pin + self.clock_pin = clock_pin + self.data_pin = data_pin + self.units = units + self.data = None + self.board = board + + # Initialize needed GPIO + GPIO.setmode(self.board) + GPIO.setup(self.cs_pin, GPIO.OUT) + GPIO.setup(self.clock_pin, GPIO.OUT) + GPIO.setup(self.data_pin, GPIO.IN) + + # Pull chip select high to make chip inactive + GPIO.output(self.cs_pin, GPIO.HIGH) + + def get(self): + '''Reads SPI bus and returns current value of thermocouple.''' + self.read() + self.checkErrors() + return getattr(self, "to_" + self.units)(self.data_to_tc_temperature()) + + def read(self): + '''Reads 16 bits of the SPI bus & stores as an integer in self.data.''' + bytesin = 0 + # Select the chip + GPIO.output(self.cs_pin, GPIO.LOW) + # Read in 16 bits + for i in range(16): + GPIO.output(self.clock_pin, GPIO.LOW) + time.sleep(0.001) + bytesin = bytesin << 1 + if (GPIO.input(self.data_pin)): + bytesin = bytesin | 1 + GPIO.output(self.clock_pin, GPIO.HIGH) + time.sleep(0.001) + # Unselect the chip + GPIO.output(self.cs_pin, GPIO.HIGH) + # Save data + self.data = bytesin + + def checkErrors(self, data_16 = None): + '''Checks errors on bit D2''' + if data_16 is None: + data_16 = self.data + noConnection = (data_16 & 0x4) != 0 # tc input bit, D2 + + if noConnection: + raise MAX6675Error("No Connection") # open thermocouple + + def data_to_tc_temperature(self, data_16 = None): + '''Takes an integer and returns a thermocouple temperature in celsius.''' + if data_16 is None: + data_16 = self.data + # Remove bits D0-3 + tc_data = ((data_16 >> 3) & 0xFFF) + # 12-bit resolution + return (tc_data * 0.25) + + def to_c(self, celsius): + '''Celsius passthrough for generic to_* method.''' + return celsius + + def to_k(self, celsius): + '''Convert celsius to kelvin.''' + return celsius + 273.15 + + def to_f(self, celsius): + '''Convert celsius to fahrenheit.''' + return celsius * 9.0/5.0 + 32 + + def cleanup(self): + '''Selective GPIO cleanup''' + GPIO.setup(self.cs_pin, GPIO.IN) + GPIO.setup(self.clock_pin, GPIO.IN) + +class MAX6675Error(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +if __name__ == "__main__": + + # default example + cs_pin = 24 + clock_pin = 23 + data_pin = 22 + units = "c" + thermocouple = MAX6675(cs_pin, clock_pin, data_pin, units) + running = True + while(running): + try: + try: + tc = thermocouple.get() + except MAX6675Error as e: + tc = "Error: "+ e.value + running = False + print("tc: {}".format(tc)) + time.sleep(1) + except KeyboardInterrupt: + running = False + thermocouple.cleanup() diff --git a/lib/oven.py b/lib/oven.py index 80f8710..24c010f 100644 --- a/lib/oven.py +++ b/lib/oven.py @@ -10,7 +10,15 @@ import config log = logging.getLogger(__name__) try: - from max31855 import MAX31855, MAX31855Error + if (config.max31855 == config.max6675): + log.error("choose (only) one converter IC") + exit() + if config.max31855: + from max31855 import MAX31855, MAX31855Error + log.info("import MAX31855") + if config.max6675: + from max6675 import MAX6675, MAX6675Error + log.info("import MAX6675") sensor_available = True except ImportError: log.warning("Could not initialize temperature sensor, using dummy values!") @@ -175,7 +183,15 @@ class TempSensor(threading.Thread): class TempSensorReal(TempSensor): def __init__(self, time_step): TempSensor.__init__(self, time_step) - self.thermocouple = MAX31855(config.gpio_sensor_cs, + if config.max6675: + log.info("init MAX6675") + self.thermocouple = MAX6675(config.gpio_sensor_cs, + config.gpio_sensor_clock, + config.gpio_sensor_data, + "c") + if config.max31855: + log.info("init MAX31855") + self.thermocouple = MAX31855(config.gpio_sensor_cs, config.gpio_sensor_clock, config.gpio_sensor_data, "c")