Skip to content

Instantly share code, notes, and snippets.

@monsonite
Created June 24, 2011 12:33
Show Gist options
  • Save monsonite/1044680 to your computer and use it in GitHub Desktop.
Save monsonite/1044680 to your computer and use it in GitHub Desktop.
/* MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA MEGA*/
/***********************************************************************************
/****************Navitrino Solar/Heating Controller*********************************
/***********************************************************************************
// ---------------navitrino1_53_M - Changes since last version:--------------------
Updated Mon 20/12/10
Accumulates gas pulse count (10 litres) over hourly intervals to allow mean hourly power to be displayed
Displays value for last hour 60 consecutive outputs allowing easy bar-graphing in XL
Multiply hourly count by 39/360 to get mean power in kWh
Updated Sat 4/12/10
Now measures 2 room temeperatures (temp1 workroom, temp5 livingroom)
Takes average temperature and uses this for temp contol
Updates on Sat 20/11/10
Ported across to Arduino Mega 2560
Weekend daytime temp increased to 19C
Day start now 7am
Boost control lowered to 22C on potentiometer
updates on Sunday 14th November
Relay board software serial (pin 7) added to boilercontrol()
Sends "R1" for CH relay, "R2" for HW relay, "R3" for both relays, "R0" for no relays
Extra code added to catch case where temperature lies within hysteresis band and send boiler off
updated on Wednesday 10th November 2010
This version uses DS1302 Real Time Clock
RF Transmitter module Tx pin is now on Digital 9 (moved from Digital 10)
Boilerstate is now used to control a LED on Digital 7
//----------------------------------------------------------------------------------
26th June 2010 - 7th Nov 2010
Ken Boak Arbour Wood Ltd.
This version for standard Arduino with NuElectronics Sensor Shield Oct 2010
Implements simple heating controller using wireless Boiler On / Boiler Off Packets
ADC 0 Outside Temperature 20K thermistor
ADC 1 Light Level
ADC 2 Set point Potentiometer 24C max
ADC 3 Tank Outlet
ADC 4 Tank Entry
ADC 5 Room Temperature
Simple Time and Temperature display using the ModernDevice's LCD117 Controller
This sketch reads up to 6 10K thermistors, performs linearisation and conversion to degrees C.
It displays the temperatures on a 4 line x 20 character LCD display
A domestic controller board based on the Arduino and Nano ATmega328 microcontroller boards
Intended to replace/augment existing domestic heating controllers and provide datalogging capability
Uses:
1. Solar Water Heating Controller - simple control with circulation pump relay
2. Central Heating / woodburner controller - determines best usage of hot water
3. Electricity Monitor - whole house electricity consumption
4. Gas consumption monitor - pulse counter on optical sensor on gas meter
5. pV / battery charge controller/datalogger
6. Gasifier controller
7. CHP controller - engine start/stop, rpm, voltage monitor etc
8. Battery management system for wind or solar pV.
9. General purpose control tasks
10. Temperature, climate and weather monitoring and datalogging.
The controller is based on the ATmega 328 microcontroller with 32K program space
and is programmed using the popular Arduino C based language.
The basic Arduino is augmented with an SDcard interface for data storage and a real time clock
using the Dallas 130X range of battery backed RTC chips. This functionality can be added to an
existing Arduino using the NuElectronics Real Time Datalog and I/O shield.
LDR sensor has 10K resistor to 0V.
Dark value < 100
Daylight indoors ~ 800
Desk lamp ~ 900
Light level Sensor connected to ADC3
Setpoint control potentiometer on ADC 2
Room Temp Thermistor on ADC4
Hot Water Tank Temp Thermistor on ADC5
433MHz Tx Module
Digital 11 Tx Data
Digital 12 Tx +5V power
Digital 13 LE
// Pseudo Code
Update time
Read and average the ADC channels
Make decision on whether boiler on based on time and temperature
Calculate heat gain/heat lost
Update display according to which mode
Accumulate the readings from the ADCs 64 times into unsigned int
Then divide by 64 to get average
Then put averaged reading through the thermistor linearisation code
*/
//-----------------------------------------------------------------------------------
// Libraries
//-----------------------------------------------------------------------------------
#include <DS1302.h>
#include <SoftwareSerial.h>
#include <math.h>
#include <Timer.h>
#include "etherShield.h"
Timer RTOS = Timer();
timer_h rep;
// Init the DS1302
DS1302 rtc(6, 4, 3);
//******************************************************************************************
//-----------------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------------
unsigned long time_x ;
// 00010203040506070809101112
/*
long monday_am = B00000000000000000000000000000000 ;
long tuesday_am = B00000000000000000000000000000000 ;
long wednesday_am = B00000000000000000000000000000000 ;
long thursday_am = B00000000000000000000000000000000 ;
long friday_am = B00000000000000000000000000000000 ;
long saturday_am = B00000000000000000000000000000000 ;
long sunday_am = B00000000000000000000000000000000 ;
long monday_pm = B00000000000000000000000000000000 ;
long tuesday_pm = B00000000000000000000000000000000 ;
long wednesday_pm = B00000000000000000000000000000000 ;
long thursday_pm = B00000000000000000000000000000000 ;
long friday_pm = B00000000000000000000000000000000 ;
long saturday_pm = B00000000000000000000000000000000 ;
long sunday_pm = B00000000000000000000000000000000 ;
*/
#define Therm0 0 // Analog Pin 0
#define Therm1 1 // Analog Pin 1
#define Therm2 2 // Analog Pin 2
#define Therm3 3 // Analog Pin 3
#define Therm4 4 // Analog Pin 4
#define Therm5 5 // Analog Pin 5
#define LDR 4
unsigned int acc0; // Accumulator for ADC0 64 readings
unsigned int acc1; // Accumulator for ADC1 64 readings
unsigned int acc2; // Accumulator for ADC2 64 readings
unsigned int acc3; // Accumulator for ADC3 64 readings
unsigned int acc4; // Accumulator for ADC4 64 readings
unsigned int acc5; // Accumulator for ADC5 64 readings
double temp;
double temp0; // storage for temperature readings from sensors
double temp1;
double temp2;
double temp3;
double temp4;
double temp5;
double tav; // average temperature
double tless; // lower of room temperatures
double deltaT;
double mtemp0; // storage for averaged minute temperature readings from sensors
double mtemp1;
double mtemp2;
double mtemp3;
double mtemp4;
double mtemp5;
double acctemp0; // accumulated temperature readings from sensors
double acctemp1;
double acctemp2;
double acctemp3;
double acctemp4;
double acctemp5;
double set_temp;
double ten_temp; //ten times room tempertaure
double ten_set; //ten times set tempertaure
int adc0;
int adc1;
int adc2;
int adc3;
int adc4;
int adc5;
int illum;
char N;
int I;
int ByteVar;
int x;
int hours;
int mins;
int secs;
int night_close = 24; // Closedown 12am
int night_am = 1;
int morn_open = 7; // Day start 7am
int evening_start = 16; // Evening start = 16:00
int day_temp = 17; // default temperatures
int eve_temp = 19;
int night_temp = 17;
int min_count = 0;
int hour_pulse_count = 0;
int pulse_count = 0 ;
int day = 0;
int eve = 0;
int night = 0;
int cold = 3; // Temperatures to make thresholding decisions around
int mild = 8;
int warm = 12;
int cool = 40;
int hot = 45;
unsigned long secs_now;
unsigned long secs_old;
unsigned long millis_old = 0;
unsigned long start_time;
unsigned long end_time;
unsigned long print_time = 0;
unsigned long update_time = 0;
unsigned long gas_count;
unsigned long gas_total;
unsigned long start_count = 925368;
unsigned long Counter1 = 0;
unsigned long Counter2 = 0;
unsigned long ct_1 = 0;
unsigned long ct_2 = 0;
unsigned long pulse_on = 0;
unsigned long pulse_off = 0;
unsigned long gas = 0 ; // returmed pulse count for Gas channel
unsigned long elec ; // returned pulsecount for Electricity channel
int gas_old = 0;
int gas_now = 0;
int gas_diff = 0;
int boilerstate = 0;
int waterstate = 0;
int val = 0; // variable to store the read value
int Tx_bytes[] = {170,172,89,153,89,85}; // An array of 6 bytes that are sent to the Tx
int _bitPeriod = 1000000 / 2000; // define the RF Tx serial baudrate in microseconds
int mode = 0 ; // Defines the Screen Mode and what parameters are displayed
char tod_str[] = "night"; // 6 character string for Time of Day (tod_str)
int on_count = 0;
int off_count = 0;
int state_now;
int state_old;
//-----------------------------------------------------------------------------------
// Connections
//-----------------------------------------------------------------------------------
int pulse_0_pin = 2; // pulse counter 0 on pin 2
// int pulse_1_pin = 3; // pulse counter 1 on pin 3
// int _receivePin = 3;
int CH_relay = 7; // Central Heating Relay connected to digital 7
int txPin = 8; // Use pin 8 for software serial to display
int HW_relay = 7; // Hot Water Relay connected to digital pin 9
int _transmitPin = 9; // define the Tx serial output pin
int LEDPin = 7; // LED connected to digital pin 7 - on when boiler on
int rxPin = 3; // rxPin is immaterial - not used - just make this an unused Arduino pin number
int relay_tx = 7; // relay board is controlled by serial on pin 7
int relay_data;
SoftwareSerial LCDserial = SoftwareSerial(rxPin, txPin); // software serial link to LCD
SoftwareSerial relay_board_serial = SoftwareSerial(rxPin, relay_tx); // software serial link to relay board
// LCDserial is connected to the TX pin so LCDserial.print commands are used
//******************************************************************************************
// Init a Time-data structure
Time t;
//-----------------------------------------------------------------------------------
// Setup
//-----------------------------------------------------------------------------------
void setup()
{
// Set the clock to run-mode, and disable the write protection
rtc.halt(false);
rtc.writeProtect(false);
// Setup Serial connections
Serial.begin(9600);
relay_board_serial.begin(9600); // begin the 9600baud serial link to the relay board
// The following lines can be commented out to use the values already stored in the DS1302
rtc.setTime(9,10,00); // Set the time to 9:30:00 (24hr format)
delay(100);
rtc.setDOW(TUESDAY); // Set Day-of-Week to FRIDAY
delay(100);
rtc.setDate(26, 4, 2011); // Set the date to Nov 6th, 2010
delay(100);
t = rtc.getTime(); // Get the real time and initialise the hours, mins and secs variables
hours = (t.hour);
mins = (t.min);
secs = (t.sec);
//----------------------------------------------------------------------------------
// Set up the I/O pins and attache interrupt for pulse counter(s)
pinMode(pulse_0_pin,INPUT);
pinMode(CH_relay,OUTPUT);
pinMode(HW_relay,OUTPUT);
pinMode(LEDPin, OUTPUT);
// pinMode(pulse_1_pin,INPUT);
pinMode(_transmitPin, OUTPUT); // define the tx pin as output
// pinMode(_receivePin, INPUT); // define the receivePin as input
attachInterrupt(0, increaseCounter1, RISING); // set up the interrupts on INT0 and INT1 (digital 2 & 3)
// attachInterrupt(1, increaseCounter2, RISING);
lcd_init(); // Initialise the LCD
//---------------------------------------------------------------------------------------
// Now set up the RTOS task scheduler
//---------------------------------------------------------------------------------------
RTOS.once(1, t_once); // t_once is performed only once - such as display initialisation/ banner screen etc
RTOS.repeat(1, t_sec); // t_sec is the task we do once per second
RTOS.repeat(15, t_15);
RTOS.repeat(60, t_60); // t_60 is the task we do every 60 secs
// rep = RTOS.repeat(10, t_rep);
// RTOS.repeat(2, t_2);
// RTOS.repeat(3, t_3);
// RTOS.repeat(10, t_10);
} // End of setup code
//**************************************************************************************************
// Once Only Tasks
//**************************************************************************************************
void t_once(void) {
Serial.print("Navitrino "); // Print Navitrino to terminal plus time, day of week and date strings
Serial.print(rtc.getTimeStr());
Serial.print(" ");
// Send Day-of-Week
Serial.print(rtc.getDOWStr());
Serial.print(" ");
// Send date
Serial.print(rtc.getDateStr());
Serial.println("");
// RTOS.destroy(rep);
}
//**************************************************************************************************
// Once Per Second Tasks
//**************************************************************************************************
void t_sec(void) {
get_ADCs(); // Read the ADC channels - average of 64 readings
convert_ADCs();
time_update(); // Update the time on the LCD display
print_status(); // Update the temperature, heating and boilaer staus on LCD
// Serial.print(secs);
while (min_count <=59)
{ // Read the ADCs 60 times and average
acctemp0 = acctemp0 + temp0;
acctemp1 = acctemp1 + temp1;
acctemp2 = acctemp2 + temp2;
acctemp3 = acctemp3 + temp3;
acctemp4 = acctemp4 + temp4;
acctemp5 = acctemp5 + temp5;
min_count++;
}
if (min_count>=59)min_count==0;
// End of minute_av_temps()
}
//**************************************************************************************************
// Once Per 15 second Tasks
//**************************************************************************************************
void t_15(void) {
update_boiler(); // Check all the temps and times and turn boiler on or off
// Serial.println("Update Boiler");
}
//**************************************************************************************************
// Once Per Minute Tasks
//**************************************************************************************************
void t_60(void) {
update_time = millis();
t = rtc.getTime(); // get time from RTC and update hours, mins and secs
hours = (t.hour);
mins = (t.min);
secs = (t.sec);
if (mins == 0 ) { // once per hour update the hourly pulse count accumulation
hour_pulse_count = pulse_count;
pulse_count = 0;
}
/*
*/
// Send time
Serial.print(rtc.getTimeStr());
Serial.print(" ");
Serial.print(set_temp);
Serial.print(" ");
print_minute(); // Print the time etc to terminal once per minute
// print_Temps(); // Print out the temperature data
mtemp0 = acctemp0/60; // calcilate the minute average temperatures
mtemp1 = acctemp1/60;
mtemp2 = acctemp2/60;
mtemp3 = acctemp3/60;
mtemp4 = acctemp4/60;
mtemp5 = acctemp5/60;
/*
Serial.print(mtemp0);
Serial.print(" ");
Serial.print(mtemp1);
Serial.print(" ");
Serial.print(mtemp2);
Serial.print(" ");
Serial.print(mtemp3);
Serial.print(" ");
Serial.print(mtemp4);
Serial.print(" ");
Serial.print(mtemp5);
Serial.println(" ");
*/
acctemp0 = 0; // Reset the acummulators for ADC totals
acctemp1 = 0;
acctemp2 = 0;
acctemp3 = 0;
acctemp4 = 0;
acctemp5 = 0;
}
//**************************************************************************************************
/*
void t_rep(void) {
time_x = millis();
Serial.println(time_x);
}
void t_2(void) {
Serial.println("Timer_2");
}
void t_3(void) {
Serial.println("Timer_3");
}
void t_10(void) {
Serial.println("Timer_10");
}
*/
//**************************************************************************************************
// Main Loop
//**************************************************************************************************
// now for the main once per second loop
void loop()
{ /*nil*/ }
// End of main loop
// ****************************************************************************************
//-----------------------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------------------
//***************************Initialise LCD Display**********************************
void lcd_init(void) {
pinMode(txPin, OUTPUT);
LCDserial.begin(9600); // 9600 baud is chip comm speed
LCDserial.print("?G420"); // set display geometry, 4 x 20 characters in this case
delay(500); // pause to allow LCD EEPROM to program
LCDserial.print("?B80"); // set backlight to 80 hex, medium brightness
delay(1000); // pause to allow LCD EEPROM to program
LCDserial.print("?s6"); // set tabs to six spaces
delay(1000); // pause to allow LCD EEPROM to program
LCDserial.print("?D00000000000000000"); // define special characters
delay(300); // delay to allow write to EEPROM
// see moderndevice.com for a handy custom char generator (software app)
LCDserial.print("?f"); // clear the LCD
delay(10);
LCDserial.print("Initialising...");
LCDserial.print("?c0"); // turn cursor off
delay(1000);
LCDserial.print("?x00?y0"); // cursor to first character of line 0
LCDserial.print("Navitrino Controller");
delay(100);
LCDserial.print("?x00?y1"); // move cursor to beginning of line 1
LCDserial.print("Arbour Wood Ltd"); // crass commercial message
delay(1000); // pause 1 sec to admire
LCDserial.print("?x00?y2"); // move cursor to beginning of line 0
LCDserial.print("Time Temp Display"); // displys LCD #117 on the screen
LCDserial.print("?x00?y3"); // cursor to first character of line 1
LCDserial.print("powercubes.com");
delay(1000); // pause 1 sec to admire
LCDserial.print("?f"); // clear the screen
LCDserial.print("?x00?y0"); // cursor to first character of line 0
LCDserial.print("Time");
delay(100);
LCDserial.print("?x00?y1"); // move cursor to beginning of line 1
LCDserial.print("T1"); // T1 message
delay(100);
LCDserial.print("?x00?y2"); // move cursor to beginning of line 2
LCDserial.print("T2"); // displys LCD #117 on the screen
delay(100);
LCDserial.print("?x00?y3"); // cursor to first character of line 3
LCDserial.print("T3");
}
//*************************************************************************************
void print_minute() {
// ********************************************************************************
// read the values from the pulse counters and temperature sensors and print out once per minute
// *********************************************************************************
gas = returnCounter1(ct_1); // get the two pulse figures x = gas, y = electricity
gas_total = gas + start_count;
// gas_count = start_count + returnCounter2(ct_2);
// display_time();
// Serial.print(" ");
// Serial.print(millis());
// Serial.print(" ");
Serial.print(gas);
Serial.print(" ");
Serial.print(gas_total);
Serial.print(" ");
// Serial.print(gas_count);
// Serial.print(" ");
gas_now = gas; // Calculate and display the number of gas pulses received in the last minute
gas_diff = gas_now - gas_old;
gas_old = gas_now;
print_Temps(); // Print out the temperature data
}
//************************************************************************************************************
// Check the time of day and the required temperature and turn on boiler if needed
//************************************************************************************************************
// This is the main decision making part of the program
// Get the day of the week from RTC as t.dow where Monday = 1, Sunday = 7
// If t.dow >= 4 is Thursday, Friday, Saturday, Sunday
// If t.dow >= 6 is Saturday, Sunday i.e. weekend
// If 00 <= hours <= 7 i.e. night-time maintain temperature at minimum of 17C night_temp
// If 8 <= hours <= 16 i.e. daytime maintain temperature at minimum of 17C day_temp
// If 17 <= hours <= 24 i.e. evening maintain temperature at minimum of 19C night_temp
// First look at the time and see if we are day, evening or night
void update_boiler() {
// digitalWrite(CH_relay, HIGH);
// digitalWrite(CH_relay, LOW);
//---------------------------------------------------------------------------------------
// First determine whether day, evening or night
if (hours >= night_am && hours <= morn_open ) { // Night-time idle period
night = HIGH;
day = LOW;
eve = LOW;
set_temp = temp2; // Idle at pot value
}
else if (hours >= morn_open && hours <= evening_start) { // Day-time idle period
night = LOW;
day = HIGH;
eve = LOW;
set_temp = temp2; // Idle at pot value
}
else if (hours >= evening_start && hours <= night_close ) { // Day-time idle period
night = LOW;
day = LOW;
eve = HIGH;
set_temp = temp2; // Idle at pot value in eveningtime
}
/*
//---------------------------------------------------------------------------------------
// Now if Thurs, Fri,Sat, Sun increase the day temperature to 18C
if (t.dow >=4) {
if (night) { // Night-time idle period
set_temp = 17; // Idle at 17C overnight
}
else if (day) { // Day-time idle period
set_temp = 19; // Idle at 19C weekend daytime
}
else if (eve) { // Day-time idle period
set_temp = temp2; // Idle at pot value in eveningtime
}
}
*/
//--------------------------------------------------------------------------------------
// We now know whether day, evening or night and we have a set-temp
// Multiply room temp and set temp by 10 to give 1 decimal place accuracy
// From the set temp and the watertemp decide whether we need hot water and/or central heating
// Decide the boilerstate and watertate and then execute boiler_control()
deltaT = temp5 - temp0; // Calculate the temperature difference between inside and outside
set_temp = temp2; // Idle at pot value
tav = (temp1 * 10 + temp5 * 10)/20;
if (temp5 >= temp1)
{
tless == temp1;
}
if (temp1 >= temp5)
{
tless == temp5;
}
ten_temp = temp5 * 10; // ten times living room temperature
// ten_temp = tav * 10; // ten times average temperature
ten_set = set_temp * 10;
if (ten_temp <= (ten_set -2)) { // put in + 0.2 degrees hysteresis
boilerstate = HIGH; // Boiler On
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("On ");
// boiler_control(); // Send control packet to boiler
}
if (ten_temp >= (ten_set +2)) { // put in - 0.2 degrees hysteresis
boilerstate = LOW; // Boiler Off
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("Off");
// boiler_control(); // Send control packet to boiler
}
/*
if (ten_temp >= (ten_set -2) && ten_temp <= (ten_set +2)); // test if set temp is within hysteresis band
{
boilerstate = LOW; // Boiler Off
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("Set ");
// boiler_control(); // Send control packet to boiler
}
if (temp5 >= 22) { // Boost demanded on pot control
boilerstate = HIGH; // Boiler On
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("Boost ");
// boiler_control(); // Send control packet to boiler
}
// Now check if its 4am and whether its cold outside and a weekday - override temp stat and turn boiler on for 1 hour
if ((t.dow <=5) && (hours == 4) && (temp0 <= cold) ) { // Boiler on at 4am for 1 hour on cold mornings
boilerstate = HIGH; // Boiler On early to compensate for cold weather
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("On ");
// boiler_control();
}
if ((t.dow <=5) && (hours == 5) && (temp0 <= cold) ) { // Keep Boiler on at 5am for 1 hour on cold mornings
boilerstate = HIGH; // Boiler On early to compensate for cold weather
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("On ");
// boiler_control();
}
if ((t.dow <=5) && (hours == 4) && (temp3 <= cool) ) { // If 4am, weekday and water temp is cool - bring on HW
boilerstate = HIGH; // Boiler On early to compensate for cold weather
waterstate = HIGH; // turn on HW valve relay
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("On ");
// boiler_control();
}
else if ((t.dow <=5) && (hours == 4) && (temp3 >= hot) ) { // If 4am, weekday and water temp is hot - hold off HW
boilerstate = LOW; // Boiler On early to compensate for cold weather
waterstate = LOW; // turn off HW valve relay
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("Off ");
// boiler_control();
}
if ((t.dow <=5) && (hours >= 4) && (temp3 >= hot) && (ten_temp >= ten_set) ) { // If after 4am, weekday and water temp is hot - hold off HW
boilerstate = LOW; // Boiler On early to compensate for cold weather
waterstate = LOW; // turn off HW valve relay
LCDserial.print("?x10?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print("Off ");
// boiler_control();
}
*/
boiler_control(); // send command to boiler and set CH and HW relays
} // End of update_boiler()
//******************************************************************************************
// boiler_control()
// Outputs a wireless packet (2000 baud) to control a Drayton Digistat wireles thermostat receiver
// Boiler Off packet AA AC 59 99 59 55 59 56 AA
// Boiler On packet AA AC 59 99 59 55 95 65 AA
// read MSB first from left to right
// Uses function RF_tx to put 8 bit serial on digital output pin 2 (no start or stop bits)
// If boilerstate == HIGH then boiler on
// If boilerstate == LOW then boiler off
//********************************************************************************************
void boiler_control() {
// digitalWrite(LEDPin,boilerstate); // Echo the boilerstate on the LED
// digitalWrite(HW_relay,waterstate); // Turn on the HW if needed
relay_data = 0;
if (boilerstate==HIGH) { // boiler relay is bit 0
relay_data = 1;
}
if (waterstate==HIGH) {
relay_data = relay_data + 2; // hot water relay is bit 1
}
relay_board_serial.print("R");
relay_board_serial.print(relay_data); // send relay control byte
relay_board_serial.print("\r"); // carriage return
int i;
for (i=0; i<6; i++) { // Output the common part of the packet 6 bytes
RF_tx(Tx_bytes[i]);
}
if(boilerstate==HIGH) {
RF_tx(149); // Turn the boiler on
RF_tx(101);
RF_tx(170);
}
else {
RF_tx(89); // Turn the boiler off
RF_tx(86);
RF_tx(170);
}
} // end of boiler_control()
//**************************************************************************************************
// RF_tx - sends the serial packet to the transmitPin
void RF_tx(uint8_t b)
{
int bitDelay = _bitPeriod - clockCyclesToMicroseconds(50); // a digitalWrite is about 50 cycles
byte mask;
for (mask = B10000000; mask; mask >>= 1) {
if (b & mask){ // choose bit
digitalWrite(_transmitPin,HIGH); // send 1
}
else{
digitalWrite(_transmitPin,LOW); // send 0
}
delayMicroseconds(bitDelay);
}
} // End of RF_tx
//***********************************************************************************************
//*****************************************************************************************************
// Thermistor Linearisation and temperature print-out code
// Thermistor Linearisation Code
double Thermistor(int RawADC) {
// Inputs ADC Value from Thermistor and outputs Temperature in Celsius
// requires: include <math.h>
// Utilizes the Steinhart-Hart Thermistor Equation:
// Temperature in Kelvin = 1 / {A + B[ln(R)] + C[ln(R)]^3}
// where A = 0.001129148, B = 0.000234125 and C = 8.76741E-08
long Resistance; double Temp; // Dual-Purpose variable to save space.
Resistance=((10240000/RawADC) - 10000); // Assuming a 10k Thermistor. Calculation is actually: Resistance = (1024 * BalanceResistor/ADC) - BalanceResistor
Temp = log(Resistance); // Saving the Log(resistance) so not to calculate it 4 times later. // "Temp" means "Temporary" on this line.
Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp)); // Now it means both "Temporary" and "Temperature"
Temp = Temp - 273.15; // Convert Kelvin to Celsius // Now it only means "Temperature"
/*
// BEGIN- Remove these lines for the function not to display anything
Serial.print("ADC: "); Serial.print(RawADC); Serial.print("/1024"); // Print out RAW ADC Number
Serial.print(", Volts: "); printDouble(((RawADC*4.860)/1024.0),3); // 4.860 volts is what my USB Port outputs.
Serial.print(", Resistance: "); Serial.print(Resistance); Serial.print("ohms");
// END- Remove these lines for the function not to display anything
*/
// Uncomment this line for the function to return Fahrenheit instead.
//Temp = (Temp * 9.0)/ 5.0 + 32.0; // Convert to Fahrenheit
return Temp; // Return the Temperature
}
//*****************************************************************************************************
void printDouble(double val, byte precision) {
// prints val with number of decimal places determine by precision
// precision is a number from 0 to 6 indicating the desired decimal places
// example: printDouble(3.1415, 2); // prints 3.14 (two decimal places)
Serial.print (int(val)); //prints the int part
if( precision > 0) {
Serial.print("."); // print the decimal point
unsigned long frac, mult = 1;
byte padding = precision -1;
while(precision--) mult *=10;
if(val >= 0) frac = (val - int(val)) * mult; else frac = (int(val) - val) * mult;
unsigned long frac1 = frac;
while(frac1 /= 10) padding--;
while(padding--) Serial.print("0");
Serial.print(frac,DEC) ;
}
}
//*****************************************************************************************************
void LCDprintDouble(double val, byte precision) {
// prints val with number of decimal places determine by precision on the LCD
// precision is a number from 0 to 6 indicating the desired decimal places
// example: printDouble(3.1415, 2); // prints 3.14 (two decimal places)
// Prints at line xpos, column ypos
LCDserial.print (int(val)); //prints the int part
if( precision > 0) {
LCDserial.print("."); // print the decimal point
unsigned long frac, mult = 1;
byte padding = precision -1;
while(precision--) mult *=10;
if(val >= 0) frac = (val - int(val)) * mult; else frac = (int(val) - val) * mult;
unsigned long frac1 = frac;
while(frac1 /= 10) padding--;
while(padding--) LCDserial.print("0");
LCDserial.print(frac,DEC) ;
}
}
//*****************************************************************************************************
//*************************************************************************************************************************
// Get the average of 64 ADC readings
//*************************************************************************************************************************
void get_ADCs() {
acc0 = 0; // Reset the acummulators for ADC totals
acc1 = 0;
acc2 = 0;
acc3 = 0;
acc4 = 0;
acc5 = 0;
for ( int i = 0; i<=63; i++) { // Read the ADCs 64 times and average
acc0 = acc0 + analogRead(Therm0);
acc1 = acc1 + analogRead(Therm1);
acc2 = acc2 + analogRead(Therm2);
acc3 = acc3 + analogRead(Therm3);
acc4 = acc4 + analogRead(Therm4);
acc5 = acc5 + analogRead(Therm5);
}
adc0 = acc0/64; // scale back down
adc1 = acc1/64;
adc2 = acc2/64;
adc3 = acc3/64;
adc4 = acc4/64;
adc5 = acc5/64;
} // End of get_ADCs()
//****************************************************************************************************
// Convert the averaged ADC Readings to Centigrade
//****************************************************************************************************
void convert_ADCs() { // Take the averaged ADC readings and convert to degrees centigrade
temp0 = Thermistor(adc0);
temp1 = Thermistor(adc1);
temp2 = Thermistor(adc2);
temp3 = Thermistor(adc3);
temp4 = Thermistor(adc4);
temp5 = Thermistor(adc5);
}
//***********************************************************************************************
// Print out the temperature readings to serial terminal
//***********************************************************************************************
void print_Temps(){ // Print out the temperature readings to serial terminal
Serial.print(temp0); // outside temp
Serial.print(", ");
Serial.print(temp5); // room temp :- lounge
Serial.print(", ");
Serial.print(temp1); // room temp :- bed
Serial.print(", ");
Serial.print(deltaT); // delta temp
Serial.print(", ");
Serial.print(temp3); // tank temp
Serial.print(", ");
Serial.print(temp4); // flow temp
Serial.print(", ");
Serial.print(boilerstate); // boiler on or off
Serial.print(", ");
Serial.print(waterstate); // hot water on or off
Serial.print(", ");
if (boilerstate) Serial.print("On"); // Print whether boiler is On or Off
if (!boilerstate) Serial.print("Off");
Serial.print(", ");
// Now calculate the duty cycle - wait for a change in boilerstate and count the on times and the off times
state_now = boilerstate;
if (state_now == HIGH && state_old == LOW) { // entered a heating on period
off_count = 0;
on_count = on_count + 1;
}
if (state_now == HIGH && state_old == HIGH) { // still in a heating on period
off_count = 0;
on_count = on_count + 1;
}
if (state_now == LOW && state_old == HIGH) { // entered a heating off period
off_count = off_count + 1;
on_count = 0 ;
}
if (state_now == LOW && state_old == LOW ) { // entered a heating off period
off_count = off_count + 1;
on_count = 0 ;
}
state_old = state_now;
Serial.print(on_count); // hot water on or off
Serial.print(", ");
Serial.print(off_count); // hot water on or off
Serial.print(", ");
Serial.print(hour_pulse_count);
Serial.print(", ");
Serial.print(pulse_count);
Serial.print(", ");
Serial.print(gas_diff);
Serial.print(", ");
if (night) { // Night-time idle period
Serial.println("Night");
}
else if (day) { // Day-time idle period
Serial.println("Day");
}
else if (eve) { // Day-time idle period
Serial.println("Evening");
}
} // End of print_Temps()
//*******************************************************************************
// Print out the time in HH:MM:SS format with leading zeros where applicable
void display_time() {
if (hours < 10)
{
Serial.print("0"); // print leading zero
Serial.print(hours); // display hours
}
else {
Serial.print(hours); // display hours
}
Serial.print(":"); // print colon
if (mins < 10)
{
Serial.print("0"); // print leading zero
Serial.print(mins);
}
else {
Serial.print(mins);
}
Serial.print(":"); // print colon
if (secs < 10)
{
Serial.print("0");
// print leading zero
Serial.print(secs);
}
else {
Serial.print(secs);
}
}
// ******************************************************************************************
// Interrupt Service Routine
// ******************************************************************************************
void increaseCounter1() // Interupt Sservice Routines - update the two counters
{
Counter1++;
pulse_count++; // increment the hourly total register
}
unsigned long returnCounter1(unsigned long ct_1) // return the counts ct_1 and ct_2 to the main loop
{
{
uint8_t SaveSREG = SREG; // save interrupt flag
noInterrupts(); // disable interrupts
ct_1 = Counter1; // access the shared data
// Counter1 = 0; // reset Counter1 to 0
SREG = SaveSREG; // restore the interrupt flag
}
return ct_1 ;
}
// Second interrupt pulsecounter - not used when RTC is used
/*
void increaseCounter2()
{
Counter2++;
}
unsigned long returnCounter2(unsigned long ct_2)
{
{
uint8_t SaveSREG = SREG; // save interrupt flag
noInterrupts(); // disable interrupts
ct_2 = Counter2; // access the counter
// Counter2 = 0; // reset Counter2 to 0
SREG = SaveSREG; // restore the interrupt flag
}
return ct_2;
}
*/
//*******************************************************************************************************************************
// Update Time on LCD display
//*******************************************************************************************************************************
void time_update()
{
LCDserial.print("?x10?y0"); // move cursor to col 10 of line 1
LCDserial.print(" : : "); // clear time display
// Increment the seconds and update the hours, mins and secs variables
// secs ++ ;
/* Old code for incrementing hh:mm:ss superceded by RTC
if (secs > 59)
{
secs = 0;
mins ++;
// print_minute(); // Print the time etc to terminal once per minute
}
if (mins > 59)
{
mins = 0;
hours ++;
}
if (hours > 23)
{
hours = 0;
}
*/
t = rtc.getTime(); // get the hours, mins and secs from RTC
hours = (t.hour);
mins = (t.min);
secs = (t.sec);
// Now format the hours minutes and seconds with any leading zeros for printing to LCD and terminal
if (hours < 10)
{
LCDserial.print("?x10?y0"); // move cursor to beginning of line 1
LCDserial.print("0"); // print leading zero
// Serial.print("0"); // print leading zero
LCDserial.print("?x11?y0"); // move cursor to beginning of line 1
LCDserial.print(hours); // display hours
// Serial.print(hours); // display hours
}
else {
LCDserial.print("?x10?y0"); // move cursor to beginning of line 1
LCDserial.print(hours); // display hours
// Serial.print(hours); // display hours
}
LCDserial.print("?x12?y0"); // move cursor to beginning of line 1
LCDserial.print(":"); // display colon
// Serial.print(":"); // print colon
if (mins < 10)
{
LCDserial.print("?x13?y0"); // move cursor to beginning of line 1
LCDserial.print("0"); // print leading zero
// Serial.print("0"); // print leading zero
LCDserial.print("?x14?y0"); // move cursor to beginning of line 1
LCDserial.print(mins); // display mins
// Serial.print(mins);
}
else {
LCDserial.print("?x13?y0"); // move cursor to beginning of line 1
LCDserial.print(mins); // display mins
// Serial.print(mins);
}
LCDserial.print("?x15?y0"); // move cursor to beginning of line 1
LCDserial.print(":"); // display colon
// Serial.print(":"); // print colon
if (secs < 10)
{
LCDserial.print("?x16?y0"); // move cursor to beginning of line 1
LCDserial.print("0"); // print leading zero
// Serial.print("0");
// print leading zero
LCDserial.print("?x17?y0"); // move cursor to beginning of line 1
LCDserial.print(secs); // display secs
// Serial.print(secs);
}
else {
LCDserial.print("?x16?y0"); // move cursor to beginning of line 1
LCDserial.print(secs); // display secs
// Serial.print(secs);
}
}
//**********************************************************************************************************
// Print out the Boiler, Temperature and Water Status to LCD in friendly format
// temp0 Outside Temperature
// temp1 Spare - or used for 1 wire network
// temp2 Set Temp
// temp3 Hot Water Temp
// temp4 Boiler Flow Temperature
// temp5 Room Temperature
//**********************************************************************************************************
void print_status() {
LCDserial.print("?x00?y0"); // move cursor to beginning of line 0
LCDserial.print("Set ");
// temp=Thermistor(analogRead(Therm2)); // read ADC 2 (Setpoint) and convert it to Celsius
// temp2=temp; // temp2 = Setpoint temperature
LCDserial.print("?x4?y0"); // move cursor to beginning of xpos,ypos
LCDprintDouble(temp2,2); // display Celsius on the LCD display to 2 dp
LCDserial.print("?x00?y1"); // move cursor to beginning of line 1
LCDserial.print("Heating ");
LCDserial.print("?x14?y1"); // move cursor to beginning of xpos,ypos
LCDserial.print(gas_total); // print out the gas meter total pulse count
LCDserial.print("?x00?y2"); // move cursor to beginning of line 2
LCDserial.print("Hot Water ");
// temp=Thermistor(analogRead(Therm3)); // read ADC 3 (Tank Outlet) and convert it to Celsius
// temp3=temp; // temp3 = Hot Water temperature
LCDserial.print("?x10?y2"); // move cursor to beginning of xpos,ypos
LCDprintDouble(temp3,2); // display Celsius on the LCD display to 2 dp
if (temp3 >= 45) { // Check the hot water temperature
LCDserial.print("?x15?y2"); // move cursor to end of line 2
LCDserial.print(" Hot"); // display it
}
else {
LCDserial.print("?x15?y2"); // move cursor to end of line 2
LCDserial.print(" Wait"); // display it
}
// Print out the roomtemps
LCDserial.print("?x00?y3"); // move cursor to beginning of line 3
LCDserial.print("R1 ");
LCDserial.print("?x03?y3"); // move cursor to beginning of xpos,ypos
LCDprintDouble(temp5,2); // display Celsius on the LCD display to 2 dp
LCDserial.print("?x10?y3"); // move cursor to beginning of line 3
LCDserial.print("R2 ");
LCDserial.print("?x13?y3"); // move cursor to beginning of xpos,ypos
LCDprintDouble(temp1,2); // display Celsius on the LCD display to 2 dp
// Print outside temperature
// temp=Thermistor(analogRead(Therm0)); // read ADC 0 and convert it to Celsius
// Serial.print(" ,"); printDouble(temp,3); // display temperature in Celsius
// LCDserial.print("?x03?y1"); // move cursor to beginning of xpos,ypos
// LCDprintDouble(temp,2); // display Celsius on the LCD display to 2 dp
// temp0 = temp;
// temp=Thermistor(analogRead(Therm5)); // read ADC 5 and convert it to Celsius
// Serial.print(","); printDouble(temp,3); // display Celsius
// temp5 = temp;
// temp=Thermistor(analogRead(Therm2)); // read ADC 2 and convert it to Celsius
// Serial.print(","); printDouble(temp,3); // display Celsius
// temp2 = temp;
}
//*************************************************************************************************
// End of minute_av_temps()
//****************************************************************************************************
//********************************************************************************************************************************
// Mode 0 - Display the Start Up Screen
//********************************************************************************************************************************
//********************************************************************************************************************************
// Mode 1 - Display the User Friendly Screen
//********************************************************************************************************************************
//********************************************************************************************************************************
// Mode 2 - Display the Second User Screen
//********************************************************************************************************************************
//********************************************************************************************************************************
// Mode 3 - Display the Diagnostics Screen
//********************************************************************************************************************************
//********************************************************************************************************************************
// Mode 4 - Display the Time and Parameter Settings Screen
//********************************************************************************************************************************
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment