Go Back   Aquarium Advice - Aquarium Forum Community > General Aquarium Forums > DIY Projects
Click Here to Login

Join Aquarium Advice Today
Reply
 
Thread Tools Search this Thread Display Modes
Please support our sponsors and let them know you heard about them on AquariumAdvice.com
 
Old 03-07-2011, 12:49 AM   #11
Aquarium Advice FINatic
 
Jnam's Avatar
 
Join Date: Sep 2008
Location: Boise ID
Posts: 757
what RTC are you using with your arduino? or are you using the internal timers from the millis() function?

i use a one wire ds1307 with batter backup it has a couple cool features like usable eeprom and a square wave generator. It keeps its own time and with a 3v battery it should be good for 9 years. I set the time once and then in the code turn the setting into a fuction that i can call to update the time if i want.

Which LCD did you get?

I have a planted tank with LEDs just started it though. The coolest thing though is that HC I have pearls already... If LEDs can sustain a light demanding reef its just a matter of matching spectrums and PAR requirements for a planted freshwater tank.
__________________

__________________
~Jason

36 BowFront Reef
LED PoweredPlanted 3G Picotope (Build thread)
Jnam is offline   Reply With Quote
Old 03-07-2011, 11:36 AM   #12
Aquarium Advice FINatic
 
AdamHorton's Avatar
 
Join Date: Aug 2009
Location: Cincinnati, OH
Posts: 575
For my clocking, I'm using the millis() function with this fix for the rollover problem:

Arduino playground - TimingRollover

Here's a link to the LCD I bought.

Amazon.com: LCD Module for Arduino 20 x 4, White on Blue: Everything Else

I've gotten the backlight to work, just nothing on the display. I'm planning to post about it on the Arduino forums so I can try and figure out what's wrong with it, but I haven't been feeling well so it may be a few days before I can get to it.

The system is basically done. I plan on commenting my code and posting it soon. I took a couple of videos but the quality isn't very good and I need to re-do them. I'll link to the crappy videos here, but again, I don't feel so good so it may be a while before I get a chance to do that.

YouTube - DIY LED lighting
YouTube - DIY LED lighting - how it works

Besides, I kind of wanted to finish the aquascaping before I took videos like this, and right now I'm dealing with a piece of driftwood that won't sink so it might be a while before it decides to sink for me.
__________________

__________________
-Adam Horton-
AdamHorton is offline   Reply With Quote
Old 03-08-2011, 09:33 AM   #13
Aquarium Advice FINatic
 
AdamHorton's Avatar
 
Join Date: Aug 2009
Location: Cincinnati, OH
Posts: 575
I've commented my source code. Here it is:

Code:
static unsigned long lWaitMillis;
int inByte = 0;
int ValidTime;

int Time_hrs;
int Time_mins;
int Time_secs;

//These #defines allow me to quickly change the lighting schedule.
//Right now they're in a test setup, I'll change it eventually to
//match a more realistic lighting schedule

//Sunrise = 1: From 0:00 to 1:00, fade in orange lights 0-100%
//             From 1:00 to 2:00, fade in white lights 0-100%
//             From 2:00 to 3:00, fade out orange lights 100-0%
#define SUNRISE  1

//Sunset = 5:  From 4:00 to 5:00, fade in orange lights 0-100%
//             From 5:00 to 6:00, fade out white lights 100-0%
//             From 6:00 to 7:00, fade out orange lights 100-0%
#define SUNSET   5

//The moon is independant from the sun at the moment. I think this
//is the way I like it, where the moon rises while the sun is still
//out. I have the ability to change it though.

//Moonrise = 3: From 3:00-4:00, fade in blue lights 0-100%
#define MOONRISE 3
//Moonset = 7:  From 7:00-8:00, fade out blue lights 100-0%
#define MOONSET  7

//This is #defined for test purposes. It really should be 1000, but I
//can make the number smaller so that I don't have to wait so long to
//see the complete light cycle.
#define MILLIS_SEC 10

//This function will calculate the intensity desired for the current
//minute, when we're in the middle of fading in/out a certain light.
//Start_hrs and Start_mins dictate the beginning of the fade
//duration dictates the length of the fade
//Start_intensity and End_intensity dictate how intense the light will
//                                          be at the ends of the fade.
//                                          These values range from
//                                          0 to 0xFF.
int Ramp(int Start_hrs, int Start_mins, int duration,
         int Start_intensity, int End_intensity) {
 int mins_in;
 int intensity;

 //First, calculate how many minutes we are into the fade.
 mins_in = 60*(Time_hrs - Start_hrs);
 mins_in += Time_mins - Start_mins;

 if (Start_intensity < End_intensity) {
   intensity = (End_intensity - Start_intensity) * mins_in / duration;
   intensity += Start_intensity;
 } else {
   intensity = Start_intensity;
   intensity -= (Start_intensity - End_intensity) * mins_in / duration;
 }

 return intensity;
}

//These schedule functions are where I can adjust each individual LED
//channel according to when the sunrise/sunset are set to be. Currently,
//they are set to the schedule described above (near the #defines).
void WhiteSchedule() {
 int intensity;
 if (Time_hrs < SUNRISE) {
   intensity = 0;
 }
 if (Time_hrs == SUNRISE) {
   //I've found that the differences in intensity are more noticeable
   //when the duty cycle is low. Instead of just doing one ramp from
   //0 to 0xFF, doing the ramp like this makes it seem more like a "linear"
   //fade. I may still tweak this, though.
   if (Time_mins < 30) {
     intensity = Ramp(SUNRISE, 0 , 30, 0 , 30  );
   } else {
     intensity = Ramp(SUNRISE, 30, 30, 30, 0xFF);
   }
 }
 if ((Time_hrs > SUNRISE) && (Time_hrs < SUNSET)) {
   intensity = 0xFF;
 }
 if (Time_hrs == SUNSET) {
   if (Time_mins < 30) {
     intensity = Ramp(SUNSET, 0 , 30, 0xFF, 30);
   } else {
     intensity = Ramp(SUNSET, 30, 30, 30  , 0 );
   }
 }
 if (Time_hrs > SUNSET) {
   intensity = 0;
 }

 //The Buck Pucks turn on the LEDs when the voltage is low (0V) which
 //is why I need to invert the intensity value here.
 analogWrite(3, 0xFF - intensity);
}

void BlueSchedule() {
 int intensity;
 if (Time_hrs < MOONRISE) {
   intensity = 0;
 }
 if (Time_hrs == MOONRISE) {
   if (Time_mins < 30) {
     intensity = Ramp(MOONRISE, 0 , 30, 0 , 30  );
   } else {
     intensity = Ramp(MOONRISE, 30, 30, 30, 0xFF);
   }
 }
 if ((Time_hrs > MOONRISE) && (Time_hrs < MOONSET)) {
   intensity = 0xFF;
 }
 if (Time_hrs == MOONSET) {
   if (Time_mins < 30) {
     intensity = Ramp(MOONSET, 0 , 30, 0xFF, 30);
   } else {
     intensity = Ramp(MOONSET, 30, 30, 30  , 0 );
   }
 }
 if (Time_hrs > MOONSET) {
   intensity = 0;
 }

 analogWrite(5, 0xFF - intensity);
}

void OrangeSchedule1() {
 int intensity;
 if (Time_hrs < SUNRISE-1) {
   intensity = 0;
 }
 if (Time_hrs == SUNRISE-1) {
   if (Time_mins < 30) {
     intensity = Ramp(SUNRISE-1, 0 , 30, 0 , 30  );
   } else {
     intensity = Ramp(SUNRISE-1, 30, 30, 30, 0xFF);
   }
 }
 if (Time_hrs == SUNRISE) {
   intensity = 0xFF;
 }
 if (Time_hrs == SUNRISE+1) {
   if (Time_mins < 30) {
     intensity = Ramp(SUNRISE+1, 0 , 30, 0xFF, 30);
   } else {
     intensity = Ramp(SUNRISE+1, 30, 30, 30  , 0 );
   }
 }
 if (Time_hrs > SUNRISE+1) {
   intensity = 0;
 }

 analogWrite(6, 0xFF - intensity);
}

void OrangeSchedule2() {
 int intensity;
 if (Time_hrs < SUNSET-1) {
   intensity = 0;
 }
 if (Time_hrs == SUNSET-1) {
   if (Time_mins < 30) {
     intensity = Ramp(SUNSET-1, 0 , 30, 0 , 30  );
   } else {
     intensity = Ramp(SUNSET-1, 30, 30, 30, 0xFF);
   }
 }
 if (Time_hrs == SUNSET) {
   intensity = 0xFF;
 }
 if (Time_hrs == SUNSET+1) {
   if (Time_mins < 30) {
     intensity = Ramp(SUNSET+1, 0 , 30, 0xFF, 30);
   } else {
     intensity = Ramp(SUNSET+1, 30, 30, 30  , 0 );
   }
 }
 if (Time_hrs > SUNSET+1) {
   intensity = 0;
 }

 analogWrite(9, 0xFF - intensity);
}

void UpdateBrightness() {
 WhiteSchedule();
 BlueSchedule();
 OrangeSchedule1();
 OrangeSchedule2();
}

void setup() {
 // initialize serial communications at 9600 bps:
 Serial.begin(9600);

 lWaitMillis = millis() + MILLIS_SEC;

 //Turn off the LEDs to begin.
 analogWrite(3, 0xFF);
 analogWrite(5, 0xFF);
 analogWrite(6, 0xFF);
 analogWrite(9, 0xFF);
 Time_hrs = 0;
 Time_mins = 0;
 Time_secs = 0;

}

void loop() {
 if ( (long)(millis() - lWaitMillis ) >= 0) {
   lWaitMillis += MILLIS_SEC;

   // The rest of this if loop will only execute once every second.
   Time_secs++;
   if (Time_secs == 60) {
     Time_secs = 0;
     Time_mins++;
     if (Time_mins == 60) {
       Time_mins = 0;
       Time_hrs++;
       if (Time_hrs == 24) {
         Time_hrs = 0;
       }
     }
     //every minute, update the brightess of each channel
     UpdateBrightness();
   }

   // print the time to the serial monitor:
   Serial.print(Time_hrs, DEC);
   Serial.print(":");
   Serial.print(Time_mins, DEC);
   Serial.print(":");
   Serial.println(Time_secs, DEC);
//    Serial.println(" ");

   //analogWrite(analogOutPin, sensorValue);

 } else {

   //If anything has been input on the serial port, it means we
   //want to set the clock.
   if (Serial.available() > 0) {
     inByte = Serial.read();
     //Serial.println(inByte, DEC);

     //set the time
     ValidTime = 0;
     while (ValidTime == 0) {
       Serial.println("Enter time in format AB:CD");
       Serial.println("Enter ABCD");
       while (Serial.available() <= 0) {
         delay(1);
       }
       inByte = Serial.read();
       Serial.println(inByte, DEC);
       Time_hrs = 10*(inByte-0x30);
       inByte = Serial.read();
       Serial.println(inByte, DEC);
       Time_hrs += inByte-0x30;
       inByte = Serial.read();
       Serial.println(inByte, DEC);
       Time_mins = 10*(inByte-0x30);
       inByte = Serial.read();
       Serial.println(inByte, DEC);
       Time_mins += inByte-0x30;
       Time_secs = 0;

       //make sure it's a valid time
       if ((Time_hrs >= 0)  && (Time_hrs < 24) &&
           (Time_mins >= 0) && (Time_mins < 60)) {
         ValidTime = 1;
       } else {
         Serial.println("Invalid time!");
       }
     }

     lWaitMillis = millis() + MILLIS_SEC;
   }

   delay(1);
 }
}
__________________
-Adam Horton-
AdamHorton is offline   Reply With Quote
Old 03-09-2011, 08:31 PM   #14
Aquarium Advice FINatic
 
Jnam's Avatar
 
Join Date: Sep 2008
Location: Boise ID
Posts: 757
millis() works but it makes it a pain to set. I skimmed through your code but i didnt see where you initilize the lights? From the looks of it you need to do a resest at the time you want to start counting form on the millis()? I have the same display but i use an i2C expander to save pins on the arduino
__________________
~Jason

36 BowFront Reef
LED PoweredPlanted 3G Picotope (Build thread)
Jnam is offline   Reply With Quote
Old 03-10-2011, 08:31 AM   #15
Aquarium Advice FINatic
 
AdamHorton's Avatar
 
Join Date: Aug 2009
Location: Cincinnati, OH
Posts: 575
I initialize the lights in my setup function, at least if I correctly understand what you're asking. Right under the "//Turn off the LEDs to begin." comment.

You're right that it is a pain to set, but without a working LCD at the moment I can't think of any other way to do it. I originally wanted to use the LCD screen along with something like a potentiometer/button input to set the time, but I can't see any realistic way of doing it without the display. I'm not exactly hurting for pins on the Arduino, but no matter what I do, I can't get any display on the LCD. Hopefully this weekend I'll be feeling up to posting pictures/videos of what I'm doing with the LCD and getting some help debugging it. My soldering isn't good but it looks OK to me...

How are you setting your clock? I would think you use the LCD screen to provide some output, right?

As far as what I'm using for millis(), the math behind it is pretty sound and makes sense to me. I haven't run it for long enough to make the millis() counter loop over, so it hasn't *officially* been tested yet, but that takes over a month to happen so it's not exactly on the top of my list.
__________________
-Adam Horton-
AdamHorton is offline   Reply With Quote
Old 03-10-2011, 05:56 PM   #16
Aquarium Advice FINatic
 
Jnam's Avatar
 
Join Date: Sep 2008
Location: Boise ID
Posts: 757
I use an I2C realtime clock to impliement time it uses a dallas chip ds1307 to keep track of the real time. You set the time once and it keeps it in a 24 mode including day and month and year. For you this could be pretty cool as you could program to change the paterns based on the time of year say longer in summer month shorter in winter. Or you could program moon phases and vary the intensity of your "moonlight" based on date.

I will take some pics of my project tonight and show you.

here is the code I am using, this is extremely rough and remember I am an EE not a software guy so my coding is awful.

Code:
 
/* First controller project sketch
first functions display temp and time and date
needs reset function to turn extPumps back to 1
*/
/*
TODO LIST
clean up code and organize
LCD import and run
Create voltage diveder code for contol buttons X 5 on analog pin 2
Organized PIN OUT
pin 0 serial use
pin 1 serial us
Inputs
pin 3 open input
pin 2 Leak detection 
pin 4 ATO float switch
pin 5 One wire bus
 
Outputs
pin 6 alarm speaker
pin 7 External pumps relay
pin 8 Feeding pumps relay
pin 9 ATO Relay
pin 10 Daylight relay
pin 11 Actinic relay
pin 12 Unused
pin 13 unused may be used for LCD dimming or additional interupt currently used as reset pin.
 
Analog pins
A1
A2 Control buttons
A3 i2c
A4 i2c
I2C address
LCD
EEPROM  
RTC  0x68
 
*/
// this section to include libraries
 
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <PCFCrystal.h>
// #include LCD LIBRARY
 
//definitions for 1wire and I2C
#define ONE_WIRE_BUS 5 //set one wire bus to pin 5
#define DS1307_I2C_ADDRESS 0x68 //set I2C address for RTC on A4 and A5
 
 
//Contstants
const int atoPin = 4;
const int leakDetectionPin = 2;//assinged as the second interuptpin
//const int leakDetectPin = ; //
//pin 5 is for the onewire bus
const int resetPin = 13;  //reset button for now then menu buttons wit LCD
const int alarmSpeaker = 6;
const int extPumpPin = 7;
const int feedPumpPin = 8;
const int atoPumpPin = 9;
const int dayLightPin = 10;
const int actinicPin = 11;
 
//Global variables
int tHour;
int extPumps = 1; //this pump is for HOB skimmer or any external pump
int atoPump = 0;  //this pump needs to be normally off or 0
int feedpump = 1; //This will be for all powerheads for feeding or cleaning time
int resetState = 0; //global for the state of the reset button on alarm 
int waterDetectState = 0; //global for water detection
int atoState = 0;
int atoHour = 30; //this number must be above 23 or a false ATo error will trigger
int atoAlarm = 0;
int atoCounter ;
int leakDetected = 0;
int currentTemp;
int tempHighAlarm;
//user changeable variables in menu
int aTone = 1000; //frequency of the alert 1000 is pretty annoying
int atoInterval = 180; //max amount of time to run ATO in seconds 
int actinicOn = 0;
int actinicOff = 21;
int dayLightOn = 0;
int dayLightOff = 22;
int alarmTemp = 87;
int feedTime = 180; //this value is in seconds 
//PCFCrystal Variabls
byte buffer = 0;
byte data = 0;
// initialize the library with the numbers of the interface pins
// rs, en, d0, d1, d2, d3, address, buffer
// 4 bits
PCFCrystal lcd(B00100000, B00010000, B00000001, B00000010, B00000100, B00001000, 0x38, &buffer);
// 8 bits
//PCFCrystal lcd(B00100000, B00010000, B10000000, B01000000, B00100000, B00010000, B00000001, B00000010, B00000100, B00001000, 0x21, 0x20, &data, &buffer);
 
// RTC functions
// Convert normal decimal number to binary coded decimal
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second,        // 0-59
byte minute,        // 0-59
byte hour,          // 1-23
byte dayOfWeek,     // 1-7
byte dayOfMonth,    // 1-28/29/30/31
byte month,         // 1-12
byte year)          // 0-99
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.send(decToBcd(second));    // 0 to bit 7 starts the clock
  Wire.send(decToBcd(minute));
  Wire.send(decToBcd(hour));     
  Wire.send(decToBcd(dayOfWeek));
  Wire.send(decToBcd(dayOfMonth));
  Wire.send(decToBcd(month));
  Wire.send(decToBcd(year));
  //Wire.send(00010000); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave
  Wire.endTransmission();
}
// Gets the date and time from the ds1307
void getDateDs1307(
byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  // A few of these need masks because certain bits are control bits
  *second     = bcdToDec(Wire.receive() & 0x7f);
  *minute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}
//END of Rtc functions
//Start ONEWIRE temps
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);
//End onewire temps
void setup() //runs once for all setup functions
{
  //Pin Mode declaring inputs
  pinMode(resetPin, INPUT); //this pin will be made free with kepad or analog
  pinMode(atoPin, INPUT);
  //attachInterrupt(leakDetectionPin, waterDetection, RISING);  //assigns atoPin as an interupt on digital pin 3 interupt pin 1
  pinMode(leakDetectionPin, INPUT);
 
  pinMode(alarmSpeaker, OUTPUT);
  pinMode(extPumpPin, OUTPUT); 
  pinMode(feedPumpPin, OUTPUT); 
  pinMode(atoPumpPin, OUTPUT);
  pinMode(dayLightPin, OUTPUT); 
  pinMode(actinicPin, OUTPUT); 
 
//Setup for Clock
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  //starts the library for RTC
  Wire.begin();
  // Start up the library for temps
  sensors.begin();
  // start serial port so you can see whats going on replace with LCD
  Serial.begin(9600);
  // set up the LCD's number of rows and columns: 
  lcd.begin(20, 4);
  // Open Message
  lcd.print("Reef Controller v .2");
 
  // Change these values to what you want to set your clock to.
  // You probably only want to set your clock once and then remove
  // the setDateDs1307 call.
  //ADD BACK IN TO CHANGE TIME
  /*
  second = 0;
  minute = 54;
  hour = 21;
  dayOfWeek = 1;
  dayOfMonth = 7;
  month = 3;
  year = 11;
setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
*/
 
}
void lightTimer()
{
if(dayLightOn == hour)
  {
   digitalWrite(dayLightPin, HIGH); 
  }
if(dayLightOff == hour)
  {
  digitalWrite(dayLightPin, LOW);
  }
if(actinicOn == hour)
  {
  digitalWrite(actinicPin, HIGH);  
  }
if(actinicOff == hour)
  {
  digitalWrite(actinicPin, LOW);
  }
 
return;
}
 
void ATO()
{
 /*this function when called runs the ATO for a 180 seconds
   which can be changed by the user via an ATO menu, eventually
   the function will also enter the alarm state for the ATO and 
   and sound the alarm if the ato trys to run more than 5 times
   in an hour.
*/
 
 
 
 
 atoState = digitalRead(atoPin); //set the state of the ato to whatever the pin is 
 if(atoState == HIGH)
 {
 int thisHour = hour;
        //Serial.println("this hour is ");
        //Serial.println(thisHour);
        //Serial.println(hour, DEC);
        //delay(2000); //for debug
        lcd.clear();
        lcd.print("ATO MODE Filling");
 delay(1000); //must pause to allow float to stabilize
 if(atoHour == thisHour)//checks to see if the last time the ato ran is the same hour as now
  {
  atoCounter++; //if it is the counter is increased
  }
 if(atoHour == thisHour  && atoCounter == 5)
  {
  atoAlarm = 1; 
  alarmCall(); //need to have atoAlarm done in Alarm section and on reset it must change atoHour back to 30
  } 
 if(atoState == HIGH && atoHour != thisHour) //hour should be in military time and should be called from RTC
  {
  atoHour = thisHour;
                digitalWrite(atoPumpPin, HIGH);//turn the pump on
                for(int x = 0; atoState == HIGH && x != atoInterval; x++)//fill loop; x++)//continually checks for pump to float to be on up to interval
                  {
                  lcd.print("filling");
    delay(1000);
    atoState = digitalRead(atoPin);
    lcd.clear();   
                  if(x == atoInterval)
         {
          digitalWrite(atoPumpPin, LOW);
         }
                  }  
  digitalWrite(atoPumpPin, LOW);
  }
 }
 else
 {
 
        return;
 } 
}
void waterDetection()
{
  //water detection function needs to be moved here
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Water detected");
 lcd.setCursor(0, 1);
        lcd.print("Please check area");
 waterDetectState = 1;
 digitalWrite(extPumpPin, LOW);
        delay(2000);
 alarmCall();
  //int buttonState = 0;
  /*
  for (int y = 0; buttonState == HIGH; y++) {
 
    Serial.println(y);
    delay(1000);
    buttonState = digitalRead(leakDetectPin); //exits for loop after tow trys if false water reading
    Serial.println("Water sensed waiting 5 seconds");
    delay(5000);
    if (y > 0)
    {
      Serial.println("ALARM!!!"); 
 
      extPumps = 0;
      leakDetected = 1;
      alarmCall();
  }
 
  }*/
}
void mainDisplay()
{
  sensors.requestTemperatures();
 
  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  lcd.setCursor(0, 0);
  lcd.print("Reef Controller v .2");
  lcd.setCursor(0, 1);
  //lcd.print(" ");
  if(hour > 12)
    {
    tHour = hour - 12;  
    }
  else
  {
    tHour = hour;
    if(tHour == 0)
    {
      tHour = 12;
    }
  }
  lcd.print(tHour, DEC);
  lcd.print(":");
  if (minute<10)
  {
      lcd.print("0");
  }
  lcd.print(minute, DEC);
  if(hour >=12 )
    {
      lcd.print("PM");
    }
    else
    {lcd.print("AM");
    }
  //lcd.print(":");
  //if (second<10)
  //{
      //lcd.print("0");
  //}
  //lcd.print(second, DEC);
  //lcd.print("  ");
  lcd.setCursor(14, 1);
  lcd.print(month, DEC);
  lcd.print("/");
  lcd.print(dayOfMonth, DEC);
  lcd.print("/");
  lcd.print(year, DEC);
 
  lcd.setCursor(0, 2);
  lcd.print("Temp: ");
  lcd.print(sensors.getTempFByIndex(0));
  lcd.print("F");
  /*lcd.print("  ");
  switch(dayOfWeek){
  case 1: 
    lcd.println("Mon");
    break;
  case 2: 
    lcd.println("Tue");
    break;
  case 3: 
    lcd.println("Wed");
    break;
  case 4: 
    lcd.println("Thur");
    break;
  case 5: 
    lcd.println("Fri");
    break;
  case 6: 
    lcd.println("Sat");
    break;
  case 7: 
    lcd.println("Sun");
    break;
  }
  */
 
  /*add this back in for debugging
  Serial.println(" ");
  Serial.print(hour, DEC);
  Serial.print(":");
  if (minute<10)
  {
      Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
      Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print("  ");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print("  ");
  switch(dayOfWeek){
  case 1: 
    Serial.println("Mon");
    break;
  case 2: 
    Serial.println("Tue");
    break;
  case 3: 
    Serial.println("Wed");
    break;
  case 4: 
    Serial.println("Thur");
    break;
  case 5: 
    Serial.println("Fri");
    break;
  case 6: 
    Serial.println("Sat");
    break;
  case 7: 
    Serial.println("Sun");
    break;
  }
  //  Serial.println(dayOfWeek, DEC);
  //Send command to get temps
  Serial.print("Temperature : ");
 
  Serial.println(sensors.getTempFByIndex(0));
  */
}
void safetyFunctions()
{
if(digitalRead(leakDetectionPin) == HIGH)
{
  waterDetection();
  return;
}
 
if(currentTemp >= alarmTemp)
  {
  digitalWrite(actinicPin, LOW);
  digitalWrite(dayLightPin, LOW);
  tempHighAlarm = 1;
  alarmCall();
  }
}
void alarmCall() //call in the event of an alarm state 
{
/*  when atoAlarm is high run the atoAlarm subroutine
    if the atoAlarm is on ensure the ato gets turned off
    until its reset.
*/  
 //noInterrupts();
        int resetState = 0;
        if (atoAlarm == 1)
   {
   digitalWrite(atoPumpPin, LOW);
   lcd.setCursor(0, 2);
          lcd.print("PRESS RESET TO STOP");
   for(int x = 0 ; x < 1  ;  )
            {
            x = digitalRead(resetPin);
            digitalWrite (alarmSpeaker, HIGH);
            delayMicroseconds(aTone / 2);
            digitalWrite (alarmSpeaker, LOW);
            delayMicroseconds(aTone / 4);
            }
   lcd.clear();
          lcd.setCursor(1, 1);
          lcd.print("ATO alarm Active");
          lcd.setCursor(4, 2);
          lcd.print("check Float");
   lcd.setCursor(1, 3);
          lcd.print("Press Reset if safe");
          do
          {
            resetState = digitalRead(resetPin);
              if(resetState == HIGH)
              {
                atoHour = 30;//comment out
                atoAlarm = 0;
                break;
              }
          }while(resetState == LOW);
        return;  
        }
 
 
  //Water detection
  //sound beeper urgently until reset is hit once
 
  if(waterDetectState == 1)
    {
    extPumps = 0;
    lcd.setCursor(0, 3);
    lcd.print("PRESS RESET TO STOP");
 
    for(int x = 0 ; x < 1  ;  )
      {
      x = digitalRead(resetPin);
      digitalWrite (alarmSpeaker, HIGH);
      delayMicroseconds(aTone / 2);
      digitalWrite (alarmSpeaker, LOW);
      delayMicroseconds(aTone / 4);
      }
    if(extPumps == 0)
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("External pumps off");
        lcd.setCursor(0, 1);
        lcd.print("leak detected");
        delay(5000);
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Reset? Hold reset");
        lcd.setCursor(0, 1);
        lcd.print("for 5 seconds");
        delay(3000);
        if(digitalRead(resetPin) == HIGH)
        {
        extPumps =1;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Pumps reset to on");
        waterDetectState = 0;
        lcd.setCursor(0, 1);
        lcd.print("Water detect reset");
        delay(1000);
        lcd.clear();
        return;
        }
        else
          {
          alarmCall();
          }
      }
    }
//temp alarm
//interrupts();
}    
void feedingTime()
{
 
 for(int startTime = millis(); millis() - startTime <= feedTime * 1000; )
 {
   int sinceStart = millis() - startTime;
   int feedCountDown = feedTime - sinceStart/1000;
   digitalWrite(feedPumpPin, LOW);
   lcd.clear();
   lcd.setCUrsor(0, 0);
   lcd.print("FEED MODE ACTIVE");
   lcd.setCursor(8, 1);
   lcd.print(feedCountDown);
 }
        lcd.clear();
 lcd.setCursor(1, 0);
 lcd.print(Feed Time complete);
 delay(2000);
 lcd.clear();
 return;
}
 
//BEGIN MAIN PROGRAM HERE
void loop()
{
  currentTemp = sensors.getTempFByIndex(0);
  if(extPumps == 1)
  {
    digitalWrite(extPumpPin, HIGH);
  }  
  mainDisplay();
  lightTimer();
  safetyFunctions();
  ATO();
  Wire.beginTransmission(0x38);
    Wire.send(buffer);
    Wire.endTransmission();
 
  //comment this in for debug
  //Serial.println("dump");
  //Serial.print("ATO STATE");
  //Serial.print("  ");
  //Serial.print(atoPump);
  //Serial.print("Exteriour pump");
  //Serial.print("  ");
  //Serial.print(extPumps);
  //delay(5000);  
}
__________________
~Jason

36 BowFront Reef
LED PoweredPlanted 3G Picotope (Build thread)
Jnam is offline   Reply With Quote
Old 03-11-2011, 10:26 AM   #17
Aquarium Advice FINatic
 
AdamHorton's Avatar
 
Join Date: Aug 2009
Location: Cincinnati, OH
Posts: 575
Most of the aquarium-related Arduino projects I've seen do a whole bunch of stuff, like yours is doing. Kind of strange that I'm only controlling lighting with mine. I do have an extra float switch lying around, so I've thought about doing ATO along with my lighting, but for freshwater, it just doesn't seem worth it. Oh well. Maybe if I get ambitious I'll buy a smaller Arduino and make an ATO system for my SW tank some day, that might save me a little stress when I get corals.

I'd be interested to see how your feeding system works. I don't remember if you said you needed help with anything, but I understand pretty much everything that's going on in your code so I could help if you need it.

I tried to edit my post above with the videos but it won't let me. Those videos will just be broken eventually, I guess... I've taken a new video and some still pictures that aren't terrible, so I'll post them here:

YouTube - DIY LED Lighting (HQ)

http://www.adamhorton.com/files/flog/good/diyled01.jpg
http://www.adamhorton.com/files/flog/good/diyled02.jpg
http://www.adamhorton.com/files/flog/good/diyled03.jpg

My mission for this weekend is to put together some pictures/video of me attempting to get my LCD to work and see if I can get some help debugging it. I'll post it on the Arduino forum but I'll probably post it here just for posterity.
__________________
-Adam Horton-
AdamHorton is offline   Reply With Quote
Old 03-11-2011, 01:02 PM   #18
Aquarium Advice FINatic
 
Jnam's Avatar
 
Join Date: Sep 2008
Location: Boise ID
Posts: 757
Yeah I would like to see it. That code is sans the LCD I was using Serial.print to get a visual. Feeding mode just counts down from a pre designated time. Turns off all the pumps for feeding so i can target feed my corals without risk of the food blowing away.
__________________
~Jason

36 BowFront Reef
LED PoweredPlanted 3G Picotope (Build thread)
Jnam is offline   Reply With Quote
Old 03-14-2011, 09:21 AM   #19
Aquarium Advice FINatic
 
AdamHorton's Avatar
 
Join Date: Aug 2009
Location: Cincinnati, OH
Posts: 575
Of course, that makes sense. I'm planning on having a reef in my SW tank but I haven't gotten there yet.

I managed to get my LCD screen to work. It turns out that my soldering was the problem.

http://www.adamhorton.com/files/flog/good/diyled04.jpg

I can now set the time using a button and a potentiometer, so I don't have to connect it to my computer to set the time. I'll upload my code at some point.

I'm thinking the next thing I want to do is to try and have the time saved in a non-volatile part of memory. It would be nice if I had a power hit if the time didn't reset back to midnight, but rather the last time it had before the power hit. I'll be looking into that this week. I've tweaked the lighting schedule a couple of times as well.

The tank will probably be ready for fish in 2-3 weeks, at least that's my guess...
__________________
-Adam Horton-
AdamHorton is offline   Reply With Quote
Old 03-14-2011, 06:56 PM   #20
Aquarium Advice FINatic
 
AdamHorton's Avatar
 
Join Date: Aug 2009
Location: Cincinnati, OH
Posts: 575
I've added the EEPROM so that the time is stored even if the power is turned off, and I fixed a couple of minor bugs and tweaked the lighting schedule a bit. Here's my code.

Code:
#include <LiquidCrystal.h>
#include <Bounce.h>
#include <EEPROM.h>

static unsigned long lWaitMillis;
int inByte = 0;
int ValidTime;

int Time_hrs;
int Time_mins;
int Time_secs;

LiquidCrystal lcd(4, 7, 10, 11, 12, 13);
Bounce bouncer = Bounce(2, 5);

#define SUNRISE  9
#define SUNSET   21
#define MOONSET  23

//#define FAST
#define MILLIS_SEC 1000

int Ramp(int Start_hrs, int Start_mins, int duration, int Start_intensity, int End_intensity) {
  int mins_in;
  int intensity;
  mins_in = 60*(Time_hrs - Start_hrs);
  mins_in += Time_mins - Start_mins;
  
  if (Start_intensity < End_intensity) {
    intensity = (End_intensity - Start_intensity) * mins_in / duration;
    intensity += Start_intensity;
  } else {
    intensity = Start_intensity;
    intensity -= (Start_intensity - End_intensity) * mins_in / duration;
  }
  
  return intensity;  
}

void WhiteSchedule() {
  int intensity;
  if (Time_hrs < SUNRISE) {
    intensity = 0;
  }
  if (Time_hrs == SUNRISE) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNRISE, 0 , 30, 0 , 30  );
    } else {
      intensity = Ramp(SUNRISE, 30, 30, 30, 0xFF);
    }
  }
  if ((Time_hrs > SUNRISE) && (Time_hrs < SUNSET)) {
    intensity = 0xFF;
  }
  if (Time_hrs == SUNSET) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNSET, 0 , 30, 0xFF, 30);
    } else {
      intensity = Ramp(SUNSET, 30, 30, 30  , 0 );
    }
  }
  if (Time_hrs > SUNSET) {
    intensity = 0;
  }
  
  analogWrite(3, 0xFF - intensity);
}

void BlueSchedule() {
  int intensity;
  if (Time_hrs < SUNRISE) {
    intensity = 0;
  }
  if (Time_hrs == SUNRISE) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNRISE, 0 , 30, 0 , 30  );
    } else {
      intensity = Ramp(SUNRISE, 30, 30, 30, 0xFF);
    }
  }
  if ((Time_hrs > SUNRISE) && (Time_hrs < SUNSET)) {
    intensity = 0xFF;
  }
  if (Time_hrs == SUNSET) {
    intensity = Ramp(SUNSET, 0, 60, 0xFF, 0x80);
  }
  if ((Time_hrs > SUNSET) && (Time_hrs < MOONSET)) {
    intensity = 0x80;
  }
  if (Time_hrs == MOONSET) {
    if (Time_mins < 30) {
      intensity = Ramp(MOONSET, 0 , 30, 0xFF, 0x80);
    } else {
      intensity = Ramp(MOONSET, 30, 30, 30  , 0 );
    }
  }
  if (Time_hrs > MOONSET) {
    intensity = 0;
  }
  
  analogWrite(5, 0xFF - intensity);
}

void OrangeSchedule1() {
  int intensity;
  if (Time_hrs < SUNRISE-1) {
    intensity = 0;
  }
  if (Time_hrs == SUNRISE-1) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNRISE-1, 0 , 30, 0 , 30  );
    } else {
      intensity = Ramp(SUNRISE-1, 30, 30, 30, 0xFF);
    }
  }
  if (Time_hrs == SUNRISE) {
    intensity = 0xFF;
  }
  if (Time_hrs == SUNRISE+1) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNRISE+1, 0 , 30, 0xFF, 30);
    } else {
      intensity = Ramp(SUNRISE+1, 30, 30, 30  , 0 );
    }
  }
  if (Time_hrs > SUNRISE+1) {
    intensity = 0;
  }
  
  analogWrite(6, 0xFF - intensity);
}

void OrangeSchedule2() {
  int intensity;
  if (Time_hrs < SUNSET-1) {
    intensity = 0;
  }
  if (Time_hrs == SUNSET-1) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNSET-1, 0 , 30, 0 , 30  );
    } else {
      intensity = Ramp(SUNSET-1, 30, 30, 30, 0xFF);
    }
  }
  if (Time_hrs == SUNSET) {
    intensity = 0xFF;
  }
  if (Time_hrs == SUNSET+1) {
    if (Time_mins < 30) {
      intensity = Ramp(SUNSET+1, 0 , 30, 0xFF, 30);
    } else {
      intensity = Ramp(SUNSET+1, 30, 30, 30  , 0 );
    }
  }
  if (Time_hrs > SUNSET+1) {
    intensity = 0;
  }
  
  analogWrite(9, 0xFF - intensity);
}

void UpdateBrightness() {
  WhiteSchedule();
  BlueSchedule();
  OrangeSchedule1();
  OrangeSchedule2();
}

void OutputTime() {
  // print the time to the serial monitor:
  Serial.print(Time_hrs, DEC);
  Serial.print(":");
  Serial.print(Time_mins, DEC);
  Serial.print(":");
  Serial.println(Time_secs, DEC);
  
  // print the time to the LCD screen
  lcd.setCursor(0, 0);
  
  lcd.print("TIME ");
  if (Time_hrs < 10) {
    lcd.print("0");
  }
  lcd.print(Time_hrs);
  lcd.print(":");
  if (Time_mins < 10) {
    lcd.print("0");
  }
  lcd.print(Time_mins);
  lcd.print(":");
  if (Time_secs < 10) {
    lcd.print("0");
  }
  lcd.print(Time_secs);
}

void SetTime() {
  int Analog;
  int Normalized;
  int bounced;
  
  //Option to set the time using the hardware
  bouncer.update();
  if (bouncer.risingEdge()) {
    //input the hours
    lcd.clear();
    lcd.print("SET TIME");
    lcd.setCursor(0, 1);
    lcd.print("Input hours:");
    lcd.setCursor(0, 2);
    lcd.print("HOUR ");
    do {
      Analog = analogRead(A0);
      Normalized = Analog/43; //gives a value between 0 and 23
      lcd.setCursor(5, 2);
      if (Normalized < 10) {
        lcd.print("0");
      }
      lcd.print(Normalized);
      bouncer.update();
    } while (!bouncer.risingEdge());
    Time_hrs = Normalized;
    
    //input the minutes
    lcd.clear();
    lcd.print("SET TIME");
    lcd.setCursor(0, 1);
    lcd.print("Input minutes:");
    lcd.setCursor(0, 3);
    lcd.print("Hour = ");
    lcd.print(Time_hrs);
    lcd.setCursor(0, 2);
    lcd.print("MINUTE ");
    do {
      Analog = analogRead(A0);
      Normalized = Analog/17; //gives a value between 0 and 61
      if (Normalized > 59) {
        Normalized = 59;
      }
      lcd.setCursor(7, 2);
      if (Normalized < 10) {
        lcd.print("0");
      }
      lcd.print(Normalized);
      bouncer.update();
    } while (!bouncer.risingEdge());
    Time_mins = Normalized;
    Time_secs = 0;
    lcd.clear();     
    UpdateBrightness();
    EEPROM.write(0, Time_hrs);
    EEPROM.write(1, Time_mins);
    EEPROM.write(2, Time_secs);
    lWaitMillis = millis() + MILLIS_SEC;
  }
  
  //Option to set the time through the serial interface
  if (Serial.available() > 0) {
    inByte = Serial.read();
    //Serial.println(inByte, DEC);
    
    //set the time
    ValidTime = 0;
    while (ValidTime == 0) {
      Serial.println("Enter time in format AB:CD");
      Serial.println("Enter ABCD");
      while (Serial.available() <= 0) {
        delay(1);
      }
      inByte = Serial.read();
      Serial.println(inByte, DEC);
      Time_hrs = 10*(inByte-0x30);
      inByte = Serial.read();
      Serial.println(inByte, DEC);
      Time_hrs += inByte-0x30;
      inByte = Serial.read();
      Serial.println(inByte, DEC);
      Time_mins = 10*(inByte-0x30);
      inByte = Serial.read();
      Serial.println(inByte, DEC);
      Time_mins += inByte-0x30;
      Time_secs = 0;
      
      //make sure it's a valid time
      if ((Time_hrs >= 0) && (Time_hrs < 24) && (Time_mins >= 0) && (Time_mins < 60)) {
        ValidTime = 1;
        EEPROM.write(0, Time_hrs);
        EEPROM.write(1, Time_mins);
        EEPROM.write(2, Time_secs);
      } else {
        Serial.println("Invalid time!");
      }        
    }
    
    lWaitMillis = millis() + MILLIS_SEC;
    UpdateBrightness();
    
  }
}

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  
  lWaitMillis = millis() + MILLIS_SEC;
  lcd.begin(20, 4);
  analogWrite(3, 0xFF);
  analogWrite(5, 0xFF);
  analogWrite(6, 0xFF);
  analogWrite(9, 0xFF);
  Time_hrs  = EEPROM.read(0);
  Time_mins = EEPROM.read(1);
  Time_secs = EEPROM.read(2);

}

void loop() {
  if ( (long)(millis() - lWaitMillis ) >= 0) {
    lWaitMillis += MILLIS_SEC;
    // The rest of this if loop will only execute once every second.
#ifndef FAST
    Time_secs++;
    EEPROM.write(2, Time_secs);
    if (Time_secs >= 60) {
      Time_secs = 0;
      EEPROM.write(2, Time_secs);
      Time_mins++;
      EEPROM.write(1, Time_mins);
      if (Time_mins >= 60) {
        Time_mins = 0;
        EEPROM.write(1, Time_mins);
        Time_hrs++;
        EEPROM.write(0, Time_hrs);
        if (Time_hrs >= 24) {
          Time_hrs = 0;
          EEPROM.write(0, Time_hrs);
        }
      }
      //every minute, update the brightess of each channel
      UpdateBrightness();
    }
#else
      Time_mins++;
      if (Time_mins >= 60) {
        Time_mins = 0;
        Time_hrs++;
        if (Time_hrs >= MOONSET + 1) {
          Time_hrs = 0;
        }
      }
      //every minute, update the brightess of each channel
      UpdateBrightness();
#endif
    
    OutputTime();

  } else {
    SetTime();
    delay(1);
  }
}
__________________

__________________
-Adam Horton-
AdamHorton is offline   Reply With Quote
Reply

Tags
diy, led, led lighting, light, lighting

Please support our sponsors and let them know you heard about them on AquariumAdvice.com

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
DIY Led 10 gallon build thread/alternative diy co2 thread krap101 DIY Projects 62 09-03-2012 07:29 AM
Diy led cabezon DIY Projects 8 01-20-2011 02:17 PM
DIY LED Light help lbannie DIY Projects 5 01-07-2011 09:10 AM
Diy Led? Seepu DIY Projects 4 01-22-2008 11:41 PM
My $10 30 led DIY night light Jme DIY Projects 7 03-03-2007 12:07 AM







» Photo Contest Winners








Copyright 2002- Social Knowledge, LLC All Rights Reserved.

All times are GMT -4. The time now is 04:46 AM.


Powered by vBulletin® Version 3.8.8 Beta 1
Copyright ©2000 - 2017, vBulletin Solutions, Inc.