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);
}