From 7a49669a92326128519b0505f5f9b756289d0ff2 Mon Sep 17 00:00:00 2001 From: Burathar Date: Sun, 4 Oct 2020 13:48:50 +0200 Subject: [PATCH] add initial files --- ...Hart coefficients Green Thermorisistor.txt | 14 + button.cpp | 43 +++ button.h | 32 ++ queue.cpp | 49 +++ queue.h | 28 ++ relay.cpp | 31 ++ relay.h | 21 ++ smoker.ino | 301 ++++++++++++++++++ temperature_sensor.cpp | 43 +++ temperature_sensor.h | 26 ++ 10 files changed, 588 insertions(+) create mode 100644 Steinhart-Hart coefficients Green Thermorisistor.txt create mode 100644 button.cpp create mode 100644 button.h create mode 100644 queue.cpp create mode 100644 queue.h create mode 100644 relay.cpp create mode 100644 relay.h create mode 100644 smoker.ino create mode 100644 temperature_sensor.cpp create mode 100644 temperature_sensor.h diff --git a/Steinhart-Hart coefficients Green Thermorisistor.txt b/Steinhart-Hart coefficients Green Thermorisistor.txt new file mode 100644 index 0000000..b921a84 --- /dev/null +++ b/Steinhart-Hart coefficients Green Thermorisistor.txt @@ -0,0 +1,14 @@ +Measurements Green Thermoresistor + +1 graden C: 36500 Ohm +41 graden c: 4930 Ohm +100 graden C: 611 Ohm + +Steinhart-Hart coefficients: + +A 0.0010626977757858514 +B 0.00025567427237838396 +C -8.706543235296982e-8 + +Calculated with: +https://rusefi.com/Steinhart-Hart.html diff --git a/button.cpp b/button.cpp new file mode 100644 index 0000000..76c651f --- /dev/null +++ b/button.cpp @@ -0,0 +1,43 @@ +// Source: https://forum.arduino.cc/index.php?topic=14479.0 + +#include "button.h" + +Button::Button(byte pin) { + this->pin = pin; + init(); +} + +void Button::init() { + pinMode(pin, INPUT); +} + +byte Button::getState() { + byte event = 0; + buttonVal = digitalRead(pin); + // Button pressed down + if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce) + { + event = 1; + downTime = millis(); + ignoreUp = false; + } + // Button released + else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce) + { + if (not ignoreUp) upTime = millis(); + } + + // Test for hold + if (buttonVal == LOW && (millis() - downTime) >= holdTime) { + // Trigger "normal" hold + event = 2; + ignoreUp = true; + // Trigger "long" hold + if ((millis() - downTime) >= longHoldTime) + { + event = 3; + } + } + buttonLast = buttonVal; + return event; +} diff --git a/button.h b/button.h new file mode 100644 index 0000000..21b7d09 --- /dev/null +++ b/button.h @@ -0,0 +1,32 @@ +//https://roboticsbackend.com/arduino-object-oriented-programming-oop/ + +#ifndef MY_BUTTON_H +#define MY_BUTTON_H + +#include + +class Button { + + private: + byte pin; + + // Button timing variables + int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button + int holdTime = 500; // ms hold period: how long to wait for press+hold event + int longHoldTime = 1500; // ms long hold period: how long to wait for press+hold event + + // Button variables + boolean buttonVal = HIGH; // value read from button + boolean buttonLast = HIGH; // buffered value of the button's previous state + long downTime = -1; // time the button was pressed down + long upTime = -1; // time the button was released + boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered + + public: + Button(byte pin); + + void init(); + byte getState(); +}; + +#endif diff --git a/queue.cpp b/queue.cpp new file mode 100644 index 0000000..e2ce285 --- /dev/null +++ b/queue.cpp @@ -0,0 +1,49 @@ +#include "queue.h" + +Queue::Queue() { + init(); +} + +void Queue::init(){ + +} + +void Queue::push(byte value) { + list[writeIndex] = value; + writeIndex = (writeIndex + 1) % sizeof(list); +} + +byte Queue::pop() { + byte value = list[readIndex]; + list[readIndex] = 0; + readIndex = (readIndex + 1) % sizeof(list); + return value; +} + +byte * Queue::clone() { + for(int i=0; i maxValue) maxValue = list[i]; + } + return maxValue; +} + +byte Queue::getMin(){ + byte minValue = 255; + for (int i=0;i 0) minValue = list[i]; + } + return minValue; +} diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..66833ca --- /dev/null +++ b/queue.h @@ -0,0 +1,28 @@ +#ifndef MY_QUEUE_H +#define MY_QUEUE_H + +#define TEMP_QUEUE_LENGTH 58 + +#include + +class Queue { + + private: + byte list[TEMP_QUEUE_LENGTH]; + byte queue[TEMP_QUEUE_LENGTH]; + byte readIndex = 0; + byte writeIndex = 0; + + public: + Queue(); + + void init(); + void push(byte value); + byte pop(); + byte * clone(); + byte getMax(); + byte getMin(); + byte lookup(byte index); +}; + +#endif diff --git a/relay.cpp b/relay.cpp new file mode 100644 index 0000000..8496603 --- /dev/null +++ b/relay.cpp @@ -0,0 +1,31 @@ +#include "relay.h" + +Relay::Relay(byte pin) { + // Use 'this->' to make the difference between the + // 'pin' attribute of the class and the + // local variable 'pin' created from the parameter. + this->pin = pin; + init(); +} + +void Relay::init() { + pinMode(pin, OUTPUT); + // Always try to avoid duplicate code. + // Instead of writing digitalWrite(pin, LOW) here, + // call the function off() which already does that + off(); +} + +void Relay::on() { + digitalWrite(pin, LOW); + state = LOW; +} + +void Relay::off() { + digitalWrite(pin, HIGH); + state = HIGH; +} + +bool Relay::getState() { + return !state; +} diff --git a/relay.h b/relay.h new file mode 100644 index 0000000..2e2f3c8 --- /dev/null +++ b/relay.h @@ -0,0 +1,21 @@ +#ifndef MY_RELAY_H +#define MY_RELAY_H + +#include + +class Relay { + + private: + byte pin; + bool state = false; + + public: + Relay(byte pin); + + void init(); + void on(); + void off(); + bool getState(); +}; + +#endif diff --git a/smoker.ino b/smoker.ino new file mode 100644 index 0000000..358c330 --- /dev/null +++ b/smoker.ino @@ -0,0 +1,301 @@ +#include +#include +#include + +#include "button.h" +#include "relay.h" +#include "temperature_sensor.h" +#include "queue.h" + +#define AIR_TEMP_SENSOR_PIN A1 + +#define RELAY_PIN 6 +#define SPEAKER_PIN 7 +#define BUTTON_RIGHT_PIN 8 +#define BUTTON_LEFT_PIN 9 +#define BUTTON_DOWN_PIN 10 +#define BUTTON_UP_PIN 11 + +#define MAX_STATE 4 // Amount of display states + +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels + +#define TEMP_DELTA 4 // Minimum temperature difference before relay is toggled +#define ALARM_TEMP_DELTA 15 // Minimum temperature difference before the alarm wil sound +#define TEMP_PLOT_INTERVAL 60000 // Amount of milliseconds between temperature measuring points in the plot + +byte state = 0; + +int targetTemp = 70; +int alarmState = 0; + +long lastTempQueue = -1000000; + +Button buttonUp(BUTTON_UP_PIN); +Button buttonDown(BUTTON_DOWN_PIN); +Button buttonLeft(BUTTON_LEFT_PIN); +Button buttonRight(BUTTON_RIGHT_PIN); + +Relay relay(RELAY_PIN); + +// Pass pin, reference voltage, and a,b,c coefficients +TemperatureSensor airTempSensor(AIR_TEMP_SENSOR_PIN, 10000, 0.0010626977757858514, 0.00025567427237838396, -8.706543235296982e-8); + +// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); + +Queue tempQueue; + +void setup() { + //Serial.begin(9600); + if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { + //Serial.println(F("SSD1306 allocation failed")); + for(;;); + } + display.setRotation(2); + display.clearDisplay(); + display.setTextColor(WHITE); + airTempSensor.preload(); +} + +void loop() { + updateAirTemp(); + byte bUp = buttonUp.getState(); + byte bDown = buttonDown.getState(); + byte bLeft = buttonLeft.getState(); + byte bRight = buttonRight.getState(); + + if (bRight >= 1){ + if(state >= MAX_STATE) state = 0; + else state += 1; + } + if (bLeft >= 1){ + if(state <= 0) state = MAX_STATE; + else state -= 1; + } + + display.clearDisplay(); + displayMenuBar(); + + switch (state) { + case 0: + targetTempState(bUp, bDown); + break; + case 1: + manualState(bUp, bDown); + break; + case 2: + uptimeState(bUp, bDown); + break; + case 3: + tempPlotState(bUp, bDown); + break; + case 4: + alarmSettingState(bUp, bDown); + break; + } + display.display(); +} + +void updateAirTemp(){ + airTempSensor.update(); + if(millis() - lastTempQueue > TEMP_PLOT_INTERVAL){ + tempQueue.push(airTempSensor.getTemperature()); + lastTempQueue = millis(); + } +} + +void updateRelay(){ + float temperature = airTempSensor.getTemperature(); + if (temperature - targetTemp >= TEMP_DELTA){ //Temp too high + relay.off(); + } else if (targetTemp - temperature >= TEMP_DELTA) { //Temp too low + relay.on(); + } + if(temperature - targetTemp >= ALARM_TEMP_DELTA){ + int second = millis() % 1000; + if(alarmState == 0 and second < 100){ + alarmState = 1; + tone(SPEAKER_PIN, 440, 400); + } + if(alarmState == 1 and second > 500 and second < 600){ + alarmState = 0; + tone(SPEAKER_PIN, 554, 400); + } + } +} + +void targetTempState(byte bUp, byte bDown){ + updateRelay(); + + switch(bUp){ + case 1: + targetTemp +=1; + break; + case 2: + targetTemp +=1; + break; + case 3: + targetTemp +=3; + break; + } + switch(bDown){ + case 1: + targetTemp -=1; + break; + case 2: + targetTemp -=1; + break; + case 3: + targetTemp -=3; + break; + } + + displayCurrentTemp(); + + // Target Temp + display.setTextSize(1); + display.setCursor(0,40); + display.print("Target: "); + display.setTextSize(2); + display.setCursor(0,50); + display.print(targetTemp); + display.print(" "); + display.setTextSize(1); + display.cp437(true); + display.write(167); + display.setTextSize(2); + display.print("C"); + + //display.drawRect(0, 0, display.width(), display.height(), SSD1306_WHITE); +} + +void manualState(byte bUp, byte bDown) { + if (bUp == 1) { + relay.on(); + } + if (bDown == 1) { + relay.off(); + } + + displayCurrentTemp(); + + display.setTextSize(1); + display.setCursor(0,40); + display.print("Manual Mode"); + display.setTextSize(2); + display.setCursor(0,50); + if (relay.getState()){ + display.print("Heater ON"); + } else { + display.print("Heater OFF"); + } +} + +void uptimeState(byte bUp, byte bDown){ + updateRelay(); + unsigned int seconds = millis()/1000; //convect milliseconds to seconds + unsigned int minutes=seconds/60; //convert seconds to minutes + unsigned int hours=minutes/60; //convert minutes to hours + seconds=seconds-(minutes*60); //subtract the coverted seconds to minutes in order to display 59 secs max + minutes=minutes-(hours*60); //subtract the coverted minutes to hours in order to display 59 minutes max + + displayCurrentTemp(); + + display.setTextSize(1); + display.setCursor(0,40); + display.print("Uptime:"); + display.setTextSize(2); + display.setCursor(0,50); + if(hours < 10) display.print(0); + display.print(hours); + display.print(":"); + if(minutes < 10) display.print(0); + display.print(minutes); + display.print(":"); + if(seconds < 10) display.print(0); + display.print(seconds); +} + +void displayMenuBar(){ + byte space = display.width() / (MAX_STATE + 1); + for (byte i = 0; i < MAX_STATE + 1; i++){ + if (i == state) display.fillCircle(space * i + space / 2, 3, 3, WHITE); + else display.drawCircle(space * i + space / 2, 3, 3, WHITE); + } +} + +void tempPlotState(byte bUp, byte bDown){ + updateRelay(); + + byte maxValue = tempQueue.getMax(); + byte minValue = tempQueue.getMin(); + + if(minValue > 99) minValue = 99; + + display.setTextSize(1); + if(maxValue > 99)display.setCursor(110,8); + else display.setCursor(116,8); + display.print(maxValue); + display.setCursor(116,57); + display.print(minValue); + + if(maxValue - minValue < 10){ + minValue -= 1; + maxValue += 1; + } + + for (int i=0; ipin = pin; + this->refResistance = refResistance; + this->a = a; + this->b = b; + this->c = c; + init(); +} + +#define DEBUG_OUTPUT Serial + +void TemperatureSensor::init() { + pinMode(pin, INPUT); +} + +void TemperatureSensor::preload() { + for(int i=0; i< 10; i++){ + update(); + } +} + +void TemperatureSensor::update() { + if(measurementCounter < 10){ //Measure 10 times before calculating temperature from average + measurementAccumulative += analogRead(pin); + measurementCounter++; + } else { + int sensorValue = measurementAccumulative/measurementCounter; + // voltage = sensorValue*5.0/1024.0 + // r1 = (vdd-vout)*r2/vout + double resistance = ((1.0-sensorValue/1024.0)*refResistance/(sensorValue/1024.0)); // this is our probe resistance. + double lt = log(resistance); + temperature = (1 / (a+b*lt+c*lt*lt*lt)) - 273.15; //Calculate temperature in Kelvin according to Steinhart-Hart equation, then convert to Celcius + if(temperature < -35) temperature = sqrt (-1); // If value is unpossibly low, return NaN + measurementAccumulative = 0; + measurementCounter = 0; + } +} + +float TemperatureSensor::getTemperature() { + return temperature; +} diff --git a/temperature_sensor.h b/temperature_sensor.h new file mode 100644 index 0000000..7658e5c --- /dev/null +++ b/temperature_sensor.h @@ -0,0 +1,26 @@ +#ifndef MY_TEMP_SENSOR_H +#define MY_TEMP_SENSOR_H + +#include + +class TemperatureSensor { + + private: + byte pin; + int refResistance; + double a,b,c; + + byte measurementCounter; + int measurementAccumulative; + float temperature; + + public: + TemperatureSensor(byte pin, int refResistance, double a, double b, double c); + + void init(); + void preload(); + void update(); + float getTemperature(); +}; + +#endif