Hi, I am writing some code to control a compressor based on temperature. After turning the compressor off, it needs at least 3 minutes for the pressure to stabilize before you can turn it back on. The hysteresis is usually enough for this, but I wan't to make it fool-proof.
I have been told I can use interrupt timers so the uC can continue reading the temps, but also be timing. Basically, when the temp reaches the hysteresis temp, it waits 3 minutes then allows the digitalWrite.
Could someone please help me out with it? I've been doing reading on the interrupt timers, but not having a larger background in microcontrollers is becoming a problem trying to understand everything ..
// Variables will change:
int buttonStateUp;
int buttonStateDown;
int lastButtonStateUp = LOW;
int lastButtonStateDown = LOW;
long lastDebounceTimeUp = 0;
long lastDebounceTimeDown = 0;
long debounceDelay = 50; // the debounce time; increase if the output flickers
int mintemp = 10;
int i = 0;
int sample = 30;
float rawArray[30];
int raw;
float averageRaw;
float sumRaw;
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
int upBtn = digitalRead(2);
int downBtn = digitalRead(3);
float raw = analogRead(3);
rawArray[i] = raw;
for (int i = 0; i < 30; i++)
sumRaw = sumRaw + rawArray[i];
averageRaw = sumRaw/sample;
float volts = averageRaw/204.8;
// 1024/5 = 204.8
//float volts = raw/204.8;
float kelvin = (volts * 1000)/10;
float celcius = kelvin - 273.15;
Serial.print(celcius);
Serial.print("C");
Serial.println(" ");
i++;
if (i >= sample) {
i = 0;
}
sumRaw = 0;
delay(200);
// If the switch changed, due to noise or pressing:
if (upBtn != lastButtonStateUp) {
// reset the debouncing timer
lastDebounceTimeUp = millis();
}
if ((millis() - lastDebounceTimeUp) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonStateUp = upBtn;
}
if (buttonStateUp == HIGH) {
mintemp++;
}
lastButtonStateUp = upBtn;
// If the switch changed, due to noise or pressing:
if (downBtn != lastButtonStateDown) {
// reset the debouncing timer
lastDebounceTimeDown = millis();
}
if ((millis() - lastDebounceTimeDown) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonStateDown = downBtn;
}
if (buttonStateDown == HIGH) {
mintemp--;
}
lastButtonStateDown = downBtn;
if (celcius < mintemp) {
digitalWrite(13, LOW);
}
int hysteresis = mintemp + 6;
if (celcius > hysteresis){
// NEED A 3 MINUTE DELAY BEFORE THIS DIGITAL WRITE
digitalWrite(13, HIGH);
}
delay(200);
}
I tried implementing the delay code, but the relay still switches on instantly ...
// Variables will change:
int buttonStateUp;
int buttonStateDown;
int lastButtonStateUp = LOW;
int lastButtonStateDown = LOW;
long lastDebounceTimeUp = 0;
long lastDebounceTimeDown = 0;
long debounceDelay = 50; // the debounce time; increase if the output flickers
int mintemp = 10;
int i = 0;
int sample = 30;
float rawArray[30];
int raw;
float averageRaw;
float sumRaw;
long previousMillis = 0;
long interval = 10000;
#include <LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
pinMode(7, OUTPUT);
lcd.begin(2, 16);
}
void loop() {
int upBtn = digitalRead(2);
int downBtn = digitalRead(3);
float raw = analogRead(3);
rawArray[i] = raw;
for (int i = 0; i < 30; i++)
sumRaw = sumRaw + rawArray[i];
averageRaw = sumRaw/sample;
float volts = averageRaw/204.8;
// 1024/5 = 204.8
//float volts = raw/204.8;
float kelvin = (volts * 1000)/10;
float celcius = kelvin - 273.15;
lcd.clear();
lcd.print("Water:");
lcd.print(" ");
lcd.print(celcius);
lcd.print("C");
Serial.println(celcius);
i++;
if (i >= sample) {
i = 0;
}
sumRaw = 0;
// If the switch changed, due to noise or pressing:
if (upBtn != lastButtonStateUp) {
// reset the debouncing timer
lastDebounceTimeUp = millis();
}
if ((millis() - lastDebounceTimeUp) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonStateUp = upBtn;
}
if (buttonStateUp == HIGH) {
mintemp++;
}
lastButtonStateUp = upBtn;
// If the switch changed, due to noise or pressing:
if (downBtn != lastButtonStateDown) {
// reset the debouncing timer
lastDebounceTimeDown = millis();
}
if ((millis() - lastDebounceTimeDown) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonStateDown = downBtn;
}
if (buttonStateDown == HIGH) {
mintemp--;
}
lastButtonStateDown = downBtn;
if (celcius < 25) {
digitalWrite(7, LOW);
}
int hysteresis = mintemp + 6;
if (celcius > 27){
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
digitalWrite(7, HIGH);
}
}
delay(200);
}
Reading through the code shows your logic is all wrong. You use the variable i defined in two places in the loop(), while it is not wrong it is never a good idea because it is confusing. Therefore you are getting the wrong result from your running average. There is probably other stuff going wrong as well.
Simplify it, use print statements to see what values you are getting at crucial points in the program and trace where what you think is happening diverges from what actually is.
Instead of previousMillis and currentMillis as names, try using more meaningful names. What exactly is previousMillis supposed to record? Is it when the relay was last opened? Last closed? Something else?
Give the variable a more meaningful name, based on it's true purpose, and it will become obvious where you need to SET it.
The problem with your code is not with determining "now" (as you are storing it in currentMillis). It is with initializing "then" (previousMillis).
The types of previousMillis and interval may be issues, too. It's important to store data returned by a function in a variable that matches the type returned by the function, to prevent truncation and data loss.
Got it working, with help from people in the Arduino chat
// Variables will change:
int buttonStateUp;
int buttonStateDown;
int lastButtonStateUp = LOW;
int lastButtonStateDown = LOW;
long lastDebounceTimeUp = 0;
long lastDebounceTimeDown = 0;
long debounceDelay = 50; // the debounce time; increase if the output flickers
int mintemp = 10;
int i = 0;
int sample = 30;
float rawArray[30];
bool isStabilising = true;
unsigned long startTime;
int STABILISING_INTERVALL = 10000;
float averageRaw;
float sumRaw;
#include <LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
void setup() {
// initialize serial communications at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
pinMode(7, OUTPUT);
lcd.begin(2, 16);
}
void loop() {
int upBtn = digitalRead(2);
int downBtn = digitalRead(3);
float raw = analogRead(3);
rawArray[i] = raw;
for (int i = 0; i < 30; i++)
sumRaw = sumRaw + rawArray[i];
averageRaw = sumRaw/sample;
float volts = averageRaw/204.8;
// 1024/5 = 204.8
//float volts = raw/204.8;
float kelvin = (volts * 1000)/10;
float celcius = kelvin - 273.15;
lcd.clear();
lcd.print("Water:");
lcd.print(" ");
lcd.print(celcius);
lcd.print("C");
Serial.println(celcius);
i++;
if (i >= sample) {
i = 0;
}
sumRaw = 0;
// If the switch changed, due to noise or pressing:
if (upBtn != lastButtonStateUp) {
// reset the debouncing timer
lastDebounceTimeUp = millis();
}
if ((millis() - lastDebounceTimeUp) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonStateUp = upBtn;
}
if (buttonStateUp == HIGH) {
mintemp++;
}
lastButtonStateUp = upBtn;
// If the switch changed, due to noise or pressing:
if (downBtn != lastButtonStateDown) {
// reset the debouncing timer
lastDebounceTimeDown = millis();
}
if ((millis() - lastDebounceTimeDown) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonStateDown = downBtn;
}
if (buttonStateDown == HIGH) {
mintemp--;
}
lastButtonStateDown = downBtn;
Serial.println(mintemp);
if (celcius < mintemp) {
digitalWrite(7, LOW);
isStabilising = true;
}
int hysteresis = mintemp + 6;
if (celcius > hysteresis)
{
if (isStabilising == true)
{
startTime = millis();
isStabilising = false;
}
else
{
if((millis() - startTime) > STABILISING_INTERVALL) {
digitalWrite(7, HIGH);
}
}
}
delay(200);
}