Burathar
4 years ago
commit
7a49669a92
10 changed files with 588 additions and 0 deletions
@ -0,0 +1,14 @@
@@ -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 |
@ -0,0 +1,43 @@
@@ -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; |
||||
} |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
//https://roboticsbackend.com/arduino-object-oriented-programming-oop/
|
||||
|
||||
#ifndef MY_BUTTON_H |
||||
#define MY_BUTTON_H |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
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 |
@ -0,0 +1,49 @@
@@ -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<sizeof(list); i++){ |
||||
int j = writeIndex % sizeof(list); |
||||
queue[i] = list[j]; |
||||
} |
||||
return queue; |
||||
} |
||||
|
||||
byte Queue::lookup(byte index){ |
||||
return list[(index + writeIndex) % sizeof(list)]; |
||||
} |
||||
|
||||
byte Queue::getMax(){ |
||||
byte maxValue = 0; |
||||
for (int i=0;i<sizeof(list); i++){ |
||||
if(list[i] > maxValue) maxValue = list[i]; |
||||
} |
||||
return maxValue; |
||||
} |
||||
|
||||
byte Queue::getMin(){ |
||||
byte minValue = 255; |
||||
for (int i=0;i<sizeof(list); i++){ |
||||
if(list[i] < minValue && list[i] > 0) minValue = list[i]; |
||||
} |
||||
return minValue;
|
||||
} |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
#ifndef MY_QUEUE_H |
||||
#define MY_QUEUE_H |
||||
|
||||
#define TEMP_QUEUE_LENGTH 58 |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
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 |
@ -0,0 +1,31 @@
@@ -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; |
||||
} |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
#ifndef MY_RELAY_H |
||||
#define MY_RELAY_H |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
class Relay { |
||||
|
||||
private: |
||||
byte pin; |
||||
bool state = false; |
||||
|
||||
public: |
||||
Relay(byte pin); |
||||
|
||||
void init(); |
||||
void on(); |
||||
void off(); |
||||
bool getState(); |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,301 @@
@@ -0,0 +1,301 @@
|
||||
#include <Wire.h> |
||||
#include <Adafruit_GFX.h> |
||||
#include <Adafruit_SSD1306.h> |
||||
|
||||
#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; i<TEMP_QUEUE_LENGTH; i++){ |
||||
byte barHeight = tempQueue.lookup(i); |
||||
if(barHeight < minValue) barHeight = minValue; |
||||
barHeight = map(barHeight, minValue, maxValue, 2, 58); |
||||
display.fillRect(i * 2, SCREEN_HEIGHT - barHeight, 1, barHeight, WHITE); |
||||
} |
||||
} |
||||
|
||||
void alarmSettingState(byte bUp, byte bDown){ |
||||
updateRelay(); |
||||
|
||||
if (bUp == 1) { |
||||
alarmState = 0; |
||||
} |
||||
if (bDown == 1) { |
||||
alarmState = -1; |
||||
} |
||||
|
||||
displayCurrentTemp(); |
||||
|
||||
display.setTextSize(1); |
||||
display.setCursor(0,40); |
||||
display.print("Alarm temp: "); |
||||
display.print(targetTemp + ALARM_TEMP_DELTA); |
||||
display.print(" "); |
||||
display.cp437(true); |
||||
display.write(167); |
||||
display.setTextSize(1); |
||||
display.print("C"); |
||||
|
||||
display.setTextSize(2); |
||||
display.setCursor(0,50); |
||||
if (alarmState == -1){ |
||||
display.print("Alarm OFF"); |
||||
} else { |
||||
display.print("Alarm ON"); |
||||
} |
||||
} |
||||
|
||||
void displayCurrentTemp(){ |
||||
display.setTextSize(1); |
||||
display.setCursor(0,10); |
||||
display.print("Current: "); |
||||
display.setTextSize(2); |
||||
display.setCursor(0,20); |
||||
display.print(airTempSensor.getTemperature()); |
||||
display.print(" "); |
||||
display.setTextSize(1); |
||||
display.cp437(true); |
||||
display.write(167); |
||||
display.setTextSize(2); |
||||
display.print("C"); |
||||
} |
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
#include "temperature_sensor.h" |
||||
|
||||
TemperatureSensor::TemperatureSensor(byte pin, int refResistance, double a, double b, double c) { |
||||
this->pin = 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; |
||||
} |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
#ifndef MY_TEMP_SENSOR_H |
||||
#define MY_TEMP_SENSOR_H |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
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 |
Loading…
Reference in new issue