Version 0.30 av mjukvaran.
- Se över och lägga in kontroll av övriga sensorer (överhettningsskydden) i timer interrupt.
Kod: Markera allt
// #include <MemoryFree.h>
/*
0, gemenOdots); ö
1, versalOdots); Ö
2, gemenAring); å
3, versalAring); Å
4, gemenAdots); ä
5, versalAdots); Ä
*/
#include <TimerOne.h>
#include <Time.h> // For the clock
#include <DS1307RTC.h> // For the RTC
#include <Wire.h> // For serial communication
#include <LiquidCrystal_I2C.h> // For running thel i2c LCD
// Declare variables
// Set pin numbers
byte activityPin = 13; // Used for indicate various activity (blinks led)
byte skruvPin = 12; // Set pin for feeder
byte boilerOverheatPin = 11; // Set pin for overheated boiler
byte heaterPin = 10; // Set pin for heater
byte burnerOverheatPin = 9; // Set pin for overheated burner
byte resetPin = 8; // Reset program (Not Arduino)
byte callingForHeat = 7; // Set pin for listening on boiler calling for heat
byte speedPin1 = 6; // Set pin for fan speed control
byte speedPin2 = 5; // Set pin for fan speed control
byte speedPin3 = 4; // Set pin for fan speed control
byte speedPin4 = 3; // Set pin for fan speed control
byte chutePin = 2; // Set pin for chute sensor
int flameInput = A0; // Analog pin for flame
// Set other variables
int flameVisible; // Is there a flame?
int calling; // Does boiler call for heat?
boolean FOn; // Is there a flame
int k; // What is the boiler status?
time_t t = now();
time_t f = now(); // Sets the variable 't' to now()
long timePlusFiveSec; // Container for now + 5 seconds
long timePlusOneSec; // Container for now + 1 second
long timePlusThirtySec; // Container for now + 30 seconds
long timePlusTenSec; // Container for now + 10 seconds
long timePlusTwentySec; // Container for now + 20 seconds
long timePlusThreehundredSec; // Container for now + 300 seconds (5 minutes)
long timePlusThirteenSec; // Container for now + 13 seconds
long timePlusNineSec; // Container for now + 9 seconds
int filledPellets; // Is pellets filled (start feed)
int flameThreshold = 100; // Contains threshold for when flame is detected
volatile int choosenEffect = 7; // Volatile container makes it possible to change effect during run
int boilOH; // Container for the boiler overheat state
int burnOH; // Container for the burner overheat state
time_t chuteTimerStart;
long chuteTimerNow;
int chuteTime;
byte startCounting;
byte chuteMode;
byte chuteLarm = 0;
// Other settings
LiquidCrystal_I2C lcd(0x27,20,4);
void setup()
{
CreateSwedishChars();
// Initiate some hardware
Timer1.initialize(100000); // Set timer interrupt to 100 000 uS (10 Hz)
Timer1.attachInterrupt(CheckChuteStatus); // Attachthe service routine
lcd.init();
// lcd.backlight();
Wire.begin();
Serial.begin(9600);
pinMode(skruvPin, OUTPUT);
pinMode(callingForHeat, INPUT);
pinMode(heaterPin, OUTPUT);
pinMode(boilerOverheatPin, INPUT);
pinMode(burnerOverheatPin, INPUT);
pinMode(resetPin, INPUT);
pinMode(speedPin1, OUTPUT);
pinMode(speedPin2, OUTPUT);
pinMode(speedPin3, OUTPUT);
pinMode(speedPin4, OUTPUT);
pinMode(chutePin, INPUT);
pinMode(activityPin, OUTPUT);
setSyncProvider(RTC.get);
// Decide if boiler is on at startup (ie after short power out).
}
void loop()
// Things that starts right away
// Check current boiler status
{
if (chuteLarm == 1)
{
larmStop(4);
}
FOn=getFlameStatus(); // Get flame status bool (on or off)/(True or False)
k=CheckBoilerStatus(); // Get the status from boiler int 0-3
lcd.clear();
lcd.setCursor(0,1); // Debug
lcd.print(F("Pannstatus: "));
lcd.print(k); // Debug
switch (k) { // Act on boiler status
case 0: // 0 Boiler is idling, nothing to do but sending log data
// lcd.clear();
lcd.setCursor(0,2);
lcd.print(F("Pannan v"));
lcd.write(char(4));
lcd.print(F("ntar"));
lcd.setCursor(0,3);
lcd.print(F("K"));
lcd.write(char(2));
lcd.print(F("r dataunderh."));
break;
case 1: // 1 Boiler should run with set effect mode
runBoiler(choosenEffect);
break;
case 2:
blowOut(); // 2 Blow out flame, boiler is done
break;
case 3:
fillPellets(); // 3 Start by feed and ignite pellets
break;
}
}
int CheckBoilerStatus() // Checking boiler status and set it as an int 0-3
/*
Controls the status of the boiler
0 = Boiler is hot enough, no need to start, flame is out
1 = Boiler has flame and wants more heat, run pellet feed and fan
2 = Boiler has flame but is hot enough, run fan until flame is out
3 = Boiler has no flame and is not hot enough, start from beginning with feeding pellet and start heating
*/
{
FOn = getFlameStatus(); // Get flame status
calling = digitalRead(callingForHeat); // Does boiler ask for heat?
if ((FOn == 1) && (calling == 1)) // Set proper status according to info
{
return 1;
}
else if ((FOn == 1) && (calling == 0))
{
return 2;
}
else if ((FOn == 0) && (calling == 1))
{
return 3;
}
else
{
return 0;
}
lcd.setCursor(0,2);
lcd.print(F("Pannstatus: "));
lcd.print(FOn);
lcd.setCursor(0,3);
lcd.print(F(" Kallar: "));
lcd.print(calling);
}
int getFlameStatus() { // Determents the flame status
int flameValue; // Int to hold the avg flame value
int avgFlame; // Int variable to hold the sums of flame level
for (int i = 1; i < 51; i++) { // Take 50 samples of the flame value
avgFlame = analogRead(flameInput)+avgFlame;
}
flameValue = avgFlame / 50; // Divide the result by 50
if (flameValue < flameThreshold) // Determent if flame is on or off
{
return false;
}
else if (flameValue >= flameThreshold)
{
return true;
}
}
void fillPellets() { // Routine to fill pellets ans start ignition
lcd.clear();
if (filledPellets == 0) // Check that pellets has not all ready been filled
{
t=now();
timePlusThirtySec = t + 2; // Calculate the 30 second feeding time
while (t < timePlusThirtySec){ // Fill pellets for 30 seconds
t = now();
lcd.setCursor(0,0);
lcd.print(timePlusThirtySec - t);
lcd.print(F(" "));
digitalWrite(skruvPin, HIGH); // Sets the skruvPin high
lcd.print(F("Matar ... "));
}
filledPellets = 1; // Pellets has been filled
digitalWrite(skruvPin, LOW); // Turn off skruvPin (set to low)
lcd.setCursor(0,0);
lcd.print(F("Matning, klar!"));
ignitePellets(); // Run the ignition routine
}
else{
}
}
void ignitePellets() { // Routine to ignite pellets
lcd.clear();
lcd.setCursor(0,1);
lcd.print(F("T"));
lcd.write(char(4));
lcd.print(F("nder pellets "));
for (int c = 1; c < 11; c++) { // Try 10 times to ignite
lcd.setCursor(0,0);
lcd.print(F("T"));
lcd.write(char(4));
lcd.print(F("nder, nr: "));
lcd.print(c);
digitalWrite(heaterPin, HIGH);
t = now();
timePlusTenSec = t + 1;
while (t < timePlusTenSec) {
t = now();
lcd.setCursor(0,2);
lcd.print(F("Fl"));
lcd.write(char(4));
lcd.print(F("kt h"));
lcd.write(char(0));
lcd.print(F("g "));
//Run fan at high speed
}
t = now();
timePlusTenSec = t + 1;
while (t < timePlusTenSec) {
t = now();
lcd.setCursor(0,2);
lcd.print(F("Fl"));
lcd.write(char(4));
lcd.print(F("kt l"));
lcd.write(char(2));
lcd.print(F("g "));
//Run fan at low speed
}
k = CheckBoilerStatus();
if (k == 1)
{
runBoiler(choosenEffect);
}
}
digitalWrite(heaterPin, LOW);
if (k == 3)
{
larmStop(1);
}
}
void runBoiler(int effect) {
lcd.clear();
digitalWrite(heaterPin, LOW);
time_t q = now();
int effectValue;
switch (effect)
{
case 1:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusTwentySec = q + 20;
while (q < timePlusTwentySec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusTwentySec - q);
lcd.write(char(1));
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
break;
case 2:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusThirteenSec = q + 13;
while (q < timePlusThirteenSec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusThirteenSec - q);
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
break;
case 3:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusNineSec = q + 9;
while (q < timePlusNineSec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusNineSec - q);
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
break;
case 4:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusNineSec = q + 7;
while (q < timePlusNineSec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusNineSec - q);
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
// pause 7 sec
effectValue = 4;
break;
case 5:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusNineSec = q + 5;
while (q < timePlusNineSec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusNineSec - q);
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
// pause 4.5 sec
effectValue = 5;
break;
case 6:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusNineSec = q + 3;
while (q < timePlusNineSec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusNineSec - q);
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
// pause 3 sec
effectValue = 6;
break;
case 7:
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
timePlusNineSec = q + 2;
while (q < timePlusNineSec)
{
lcd.setCursor(0,1);
lcd.print(F("Matar om: "));
lcd.print(timePlusNineSec - q);
lcd.print(F(" "));
q = now();
};
digitalWrite(skruvPin, HIGH);
delay(1000);
digitalWrite(skruvPin, LOW);
CheckBoilerStatus();
// pause 2 sec
effectValue = 7;
break;
case 0:
while (choosenEffect == 0)
{
effectValue = 0; // Do nothing, boiler is off
lcd.setCursor(0,0);
lcd.print(F("Effektl"));
lcd.write(char(4));
lcd.print(F("ge: "));
lcd.print(effect);
lcd.setCursor(0,1);
lcd.print(F("Pannan av"));
CheckBoilerStatus();
break;
}
}
}
void blowOut () {
// Set fan high if status is 2, for 5 minutes (300 seconds)
lcd.clear();
time_t r = now();
timePlusThreehundredSec = r + 10;
while ((r < timePlusThreehundredSec) && (!k == 0))
{
lcd.setCursor(0,0);
lcd.print(F("Bl"));
lcd.write(char(2));
lcd.print(F("ser ut flamman"));
lcd.setCursor(0,1);
lcd.print(F("Kvar: "));
lcd.print(timePlusThreehundredSec - r);
lcd.print(F(" av 300 sek "));
r = now();
k = CheckBoilerStatus();
lcd.setCursor(0,2);
lcd.print(k);
// Fan speed high
}
k = CheckBoilerStatus();
while (k == 0);
{
k = CheckBoilerStatus();
lcd.setCursor(0,2);
lcd.print(k);
}
// CheckBoilerStatus();
}
void larmStop(int larmMode) {
lcd.clear();
digitalWrite(skruvPin, LOW);
digitalWrite(heaterPin, LOW);
switch (larmMode)
{
case 0:
// larmMode 0 = no alarm fired
break;
case 1:
// Set fan to High for five minutes
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("LARM!!! Nr: "));
lcd.print(larmMode);
lcd.setCursor(0,1);
lcd.print(F("Misslyckad start!"));
lcd.setCursor(0,2);
lcd.print(F("Starta om manuellt"));
shutDown();
break;
case 2:
// Burner fired overheat protection
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("LARM!!! Nr: "));
lcd.print(larmMode);
lcd.setCursor(0,1);
lcd.write(char(1));
lcd.print(F("verhettad br"));
lcd.write(char(4));
lcd.print(F("nnare"));
lcd.setCursor(0,2);
lcd.print(F("V"));
lcd.write(char(4));
lcd.print(F("nta p"));
lcd.write(char(2));
lcd.print(F(" aut. "));
lcd.write(char(2));
lcd.print(F("terst."));
shutDown();
break;
case 3:
/*
Boiler fired overheat protection (Mains power for fan and screw is off)
Manual reset of boiler required
*/
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("LARM!!! Nr: "));
lcd.print(larmMode);
lcd.setCursor(0,1);
lcd.write(char(1));
lcd.print(F("verhettad panna"));
lcd.setCursor(0,2);
lcd.write(char(3));
lcd.print(F("terst. manuellt"));
shutDown();
break;
case 4:
/*
Chute detector triggers a alarm. Chute is full of pellets or smoke is coming
up the chute. Clean glass and clear chute.
*/
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("LARM!!! Nr: "));
lcd.print(larmMode);
lcd.setCursor(0,1);
lcd.print(F("Fallschakt"));
lcd.setCursor(0,2);
lcd.print(F("Kontr. fallschakt"));
shutDown();
break;
}
// Blink LCD background to get attention
int s = 1;
while (s < 10) {
lcd.backlight();
delay(200);
lcd.noBacklight();
delay(200);
}
}
int CheckOverheat()
{
boilOH = digitalRead(boilerOverheatPin);
burnOH = digitalRead(burnerOverheatPin);
if (burnOH == 1)
{
return 3;
}
else
{
}
if (boilOH == 0)
{
return 2;
}
else
{
}
}
void CheckChuteStatus()
{
digitalWrite(activityPin, LOW);
if ((digitalRead(chutePin) == 1) && (startCounting == 0))
{
chuteMode=1;
digitalWrite(activityPin, !digitalRead(activityPin));
}
else if ((digitalRead(chutePin) == 1) && (startCounting == 1))
{
digitalWrite(activityPin, !digitalRead(activityPin));
chuteMode=2;
}
else
{
// digitalWrite(activityPin, !digitalRead(activityPin));
chuteMode=3;
}
switch (chuteMode)
{
case 1:
{
chuteTimerStart = now() + 5;
startCounting = 1;
}
break;
case 2:
{
f = now();
chuteTime = chuteTimerStart - f;
Serial.println(chuteTime);
switch(chuteTime)
{
case 1:
Serial.println("LARM");
chuteLarm = 1;
break;
default:
break;
}
}
break;
case 3:
{
startCounting = 0;
}
break;
}
}
void shutDown()
{
digitalWrite(skruvPin, LOW);
digitalWrite(heaterPin, LOW);
digitalWrite(speedPin1, LOW);
digitalWrite(speedPin2, LOW);
digitalWrite(speedPin3, LOW);
digitalWrite(speedPin4, LOW);
}
void CreateSwedishChars()
/*
0, gemenOdots); ö
1, versalOdots); Ö
2, gemenAring); å
3, versalAring); Å
4, gemenAdots); ä
5, versalAdots); Ä
*/
{
byte versalOdots[8] = {
B01010,
B01110,
B10001,
B10001,
B10001,
B10001,
B01110,
};
byte gemenOdots[8] = {
B01010,
B00000,
B01110,
B10001,
B10001,
B10001,
B01110,
};
byte gemenAring[8] = {
B00100,
B00000,
B01110,
B00001,
B01111,
B10001,
B01111,
};
byte versalAring[8] = {
B00100,
B01110,
B10001,
B10001,
B11111,
B10001,
B10001,
};
byte gemenAdots[8] = {
B01010,
B00000,
B01110,
B00001,
B01111,
B10001,
B01111,
};
byte versalAdots[8] = {
B01010,
B01110,
B10001,
B10001,
B11111,
B10001,
B10001,
};
lcd.createChar(0, gemenOdots);
lcd.createChar(1, versalOdots);
lcd.createChar(2, gemenAring);
lcd.createChar(3, versalAring);
lcd.createChar(4, gemenAdots);
lcd.createChar(5, versalAdots);
}