First bit:
/*
WeatherStation:
Created by Gavin Maxwell, 2010
*/
#include <WProgram.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#include <Wire.h>
#include <DS1307.h>
// --> START PIN ASSIGNMENTS
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd( 17, 16, 12, 11, 10, 9 ); // modified for better board routing
#define TEMP_PIN 0 // analog IN pin 0
#define TEMP_REF_PIN 1 // analog IN pin 1
#define RESET_MINMAX_PIN 13 // button to reset the stored values in EEPROM
#define INT_0 0 // SQW interrupt from DS1307
// --> END PIN ASSIGNMENTS
int rtc[ DS1307_MAX_ITEMS ];
char* DOW[8] = { "", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
#define MV_PER_DEGREE 10 // each 10mV is 1C
#define FULLSCALE_MV ((float)(4700)) // 5000 mV = 1024 from the ADC - actually 4700mV is approx what is supplied to LM35
#define FULLSCALE_ADC ((float)(1024)) // ADC returns from 0 - 1023 so 1024 unique values
#define MV_PER_ADC_STEP ((float)( FULLSCALE_MV / FULLSCALE_ADC )) // mV per ADC increment
#define INTER_READ_DELAY 20 // milliseconds between reads
#define UPDATE_INTERVAL 10000 // milliseconds between updates
#define USE_GROUND_REF 1
#define TEMP_SAMPLES 20 // number of samples to average
// EEPROM Addresses
#define MIN_TEMP_ADDRESS 0x00
#define MAX_TEMP_ADDRESS 0x01
#define CLOCK_SET_ADDRESS 0x02
#define CALIBRATION_ADDRESS 0x03 // NOT USED
unsigned long lastUpdate;
long minTemp = 255;
long maxTemp = -255;
long LM35Calibration = -1; // Rough as nails
boolean showColon = true; // flag to blink the colon seperator
#define DEGREE_CHAR 4
#define STEP1_CHAR 5
#define STEP2_CHAR 6
#define STEP3_CHAR 7
#define ARROW_CHAR 0x7E
byte degree[8] = {
B01100,
B10010,
B10010,
B01100,
B00000,
B00000,
B00000,
};
byte step1[8] = {
B00000,
B01110,
B10001,
B10001,
B10001,
B01110,
B00000,
};
byte step2[8] = {
B00000,
B01110,
B11111,
B11011,
B11111,
B01110,
B00000,
};
byte step3[8] = {
B00000,
B01110,
B11111,
B11111,
B11111,
B01110,
B00000,
};
volatile boolean updateTime = true;
// DS1307 1Hz pulse ISR - set our flag and get out!
void pulseISR()
{
updateTime = true;
}
//
// Setup all of our pins, initialise the RTC, serial port and LCD
//
void setup()
{
int i, ndx;
pinMode( TEMP_PIN, INPUT );
pinMode( TEMP_REF_PIN, INPUT );
pinMode( RESET_MINMAX_PIN, INPUT );
digitalWrite( RESET_MINMAX_PIN, HIGH ); // internal pull-up - switch will pull low to indicate reset
// DS1307 sends a 1Hz pulse - we use this to update the display
attachInterrupt( INT_0, pulseISR, FALLING );
Serial.begin( 9600 );
// read the stored min and max
// values will be 255 if never written before
// if max has never been recorded set it super low
// to force an update first time we measure
minTemp = EEPROM.read( MIN_TEMP_ADDRESS );
maxTemp = EEPROM.read( MAX_TEMP_ADDRESS );
if ( maxTemp == 255 )
maxTemp = -255;
// EEPROM stores a unsigned byte, so we need to handle
// negatives. 200 limit OK as sensor goes down to -55 (0xC9, 201)
if ( minTemp > 200 )
minTemp = minTemp - 256;
if ( maxTemp > 200 )
maxTemp = maxTemp - 256;
// if EEPROM has never been set then use a default date
if ( EEPROM.read( CLOCK_SET_ADDRESS ) == 255 )
{
RTC.stop();
RTC.set( DS1307_SEC, 1 );
RTC.set( DS1307_MIN, 17 );
RTC.set( DS1307_HR, 15 );
RTC.set( DS1307_DOW, 6 );
RTC.set( DS1307_DATE, 16 );
RTC.set( DS1307_MTH, 10 );
RTC.set( DS1307_YR, 10 );
RTC.start();
EEPROM.write( CLOCK_SET_ADDRESS, 1 );
}
// Define custom characters
lcd.createChar( DEGREE_CHAR, degree );
lcd.createChar( STEP1_CHAR, step1 );
lcd.createChar( STEP2_CHAR, step2 );
lcd.createChar( STEP3_CHAR, step3 );
// set up the LCD's number of rows and columns:
lcd.begin( 16, 2 );
// Get the current time and display Xmas Card if it's Xmas!
RTC.get( rtc, true );
// SNIP FOR PRIVACY REASONS
// enable 1Hz square wave output
RTC.enableOutput();
RTC.setOutputRate( 0 );
lcd.clear();
lastUpdate = millis() - UPDATE_INTERVAL;
}
//
// Simple formatter of numeric values
//
void BufferPrint( char *buffer, unsigned long value, unsigned long i, int bufLen )
{
unsigned long temp;
int bufindex = 0;
if ( buffer )
{
memset( buffer, 0, bufLen );
while ( i > 0 )
{
temp = value / i;
value -= temp * i;
buffer[ bufindex++ ] = (char)( '0' + temp );
i/=10;
}
}
}
//
// Retrieves updated time from DS1307, formats it then displays on LCD
//
void UpdateTime()
{
const int timeBufLen = 8;
char buf[ timeBufLen ];
RTC.get( rtc, true );
lcd.setCursor( 0, 0 );
BufferPrint( buf, rtc[ DS1307_HR ], 10, timeBufLen );
lcd.print( buf );
lcd.print( showColon ? ":" : " " );
showColon = !showColon;
BufferPrint( buf, rtc[ DS1307_MIN ], 10, timeBufLen );
lcd.print( buf );
lcd.print( " " );
// Check DOW is a valid value
if ( rtc[ DS1307_DOW ] <= 0 || rtc[ DS1307_DOW ] > 7 )
lcd.print( "???" );
else
lcd.print( DOW[ rtc[ DS1307_DOW ] ] );
lcd.print( " " );
BufferPrint( buf, rtc[ DS1307_DATE ], 10, timeBufLen );
lcd.print( buf );
lcd.print( "/" );
BufferPrint( buf, rtc[ DS1307_MTH ], 10, timeBufLen );
lcd.print( buf );
// reset flag until next interrupt
updateTime = false;
}
//
// Decode the entered time and set the DS1307
// Format: THHMMSSWDDMMYY
// where W is 1->7 for Monday->Sunday
//
void HandleTimeSet()
{
int inByte = Serial.read();
if ( inByte == 't' || inByte == 'T' )
{
int b1, b2, hh, mm, ss, wd, dd, mo, yy;
Serial.println( "SETTING THE TIME" );
b1 = Serial.read();
b2 = Serial.read();
hh = ( ( b1 - '0') * 10 ) + ( b2 - '0' );
b1 = Serial.read();
b2 = Serial.read();
mm = ( ( b1 - '0') * 10 ) + ( b2 - '0' );
b1 = Serial.read();
b2 = Serial.read();
ss = ( ( b1 - '0') * 10 ) + ( b2 - '0' );
b1 = Serial.read();
wd = ( b1 - '0');
b1 = Serial.read();
b2 = Serial.read();
dd = ( ( b1 - '0') * 10 ) + ( b2 - '0' );
b1 = Serial.read();
b2 = Serial.read();
mo = ( ( b1 - '0') * 10 ) + ( b2 - '0' );
b1 = Serial.read();
b2 = Serial.read();
yy = ( ( b1 - '0') * 10 ) + ( b2 - '0' );
RTC.stop();
RTC.set( DS1307_SEC, ss );
RTC.set( DS1307_MIN, mm );
RTC.set( DS1307_HR, hh );
RTC.set( DS1307_DOW, wd );
RTC.set( DS1307_DATE, dd );
RTC.set( DS1307_MTH, mo );
RTC.set( DS1307_YR, yy );
RTC.start();
}
else if ( inByte == 'c' || inByte == 'C' )
{
Serial.println( "TEMPERATURE CALIBRATION NOT IMPLEMENTED YET" );
}
}
//
// A press on the rest button over a set duration indicates
// we need to clear the current stored min and max temperatures
//
void CheckForResetMinMax()
{
// Handle resetting the min and max temp values
if ( digitalRead( RESET_MINMAX_PIN ) == LOW )
{
long press = millis();
// spin whilst the buton is down
while ( digitalRead( RESET_MINMAX_PIN ) == LOW )
{
lcd.setCursor( 0, 1 );
if ( millis() > press + 1500 )
lcd.print( "T:<RELEASE> " );
else
lcd.print( "T:<HOLD 2 RESET>" );
}
// was it down long enough to indicate a real press
if ( millis() > press + 1500 )
{
lcd.setCursor( 0, 1 );
lcd.print( "T:<RESETTING> " );
minTemp = 255;
maxTemp = -255;
EEPROM.write( MIN_TEMP_ADDRESS, 255 );
EEPROM.write( MAX_TEMP_ADDRESS, 255 );
}
// force a temp update
lastUpdate = millis() - UPDATE_INTERVAL;
}
}