Skip to content

Instantly share code, notes, and snippets.

@ilmaestro
Created December 13, 2014 04:09
Show Gist options
  • Save ilmaestro/0bc0ba78f5ee739bb706 to your computer and use it in GitHub Desktop.
Save ilmaestro/0bc0ba78f5ee739bb706 to your computer and use it in GitHub Desktop.
Arduino LED Saltwater Light
/*****
AquaLight - Versin 2.0 (rewritten after accidentally deleting my project after a year)
Ryan Kilkenny - 12/26/2010
basic functions:
* RTC - timing functions
* Serial LCD - Clock Display, future menu system
* PWM - LED light control
program
* light modes
0 dark: all lights off
1 daylight: 5 hours of constant daylight
2 highlight: 2 - 3 hours of light changes, white to blue, bright blue
3 moonlight: 4 hours of dim blues
* timing
- start time: 2pm
- daylight (2pm - 7pm)
- highlight (7pm - 9pm)
- moonlight (9pm - 1pm)
- dark
***/
#include <Time.h>
#include <TimeAlarms.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <math.h>
//global constants
#define WHITE_PIN 3
#define BLUE_PIN 11
#define DARK_MODE 0
#define DAYLIGHT_MODE 1
#define HIGHLIGHT_MODE 2
#define MOONLIGHT_MODE 3
#define MODE_MENU 0
#define INTENSITY_MENU 1
#define NUM_MENUS 2
#define NUM_LIGHTMODES 4
//global variables
int Lightmode = DARK_MODE;
int DisplayMenu = MODE_MENU;
int CurrentHour;
int TestMode = 0;
char* DisplayMenus[NUM_MENUS] = {"Mode", "Intensity"};
//24 hour clock times
int DarkHour = 2;
int DaylightHour = 14;
int HighlightHour = 19;
int MoonlightHour = 21;
char* LightmodeStrings[NUM_LIGHTMODES] = {"Dark", "Day", "Show", "Moon"}; //light mode display values
//light intensities
int WhiteIntensity = 255;
int BlueIntensity = 255;
int WhiteVariance = 0;
int BlueVariance = 0;
//Timer durations
int DisplayTimerDur = 1000;
int DisplayTimer;
int DisplayMenuTimerDur = 10000;
int DisplayMenuTimer;
int SetLightmodeTimerDur = 30000;
int SetLightmodeTimer;
int SetLightIntensityTimerDur = 500;
int SetLightIntensityTimer;
int HighlightTimerDur = 5000;
int HighlightTimer;
int HighlightLatch = 0;
/***********
MAIN SETUP
***********/
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(0)); //seed with analog noise
beginPwm();
beginSerialLCD();
beginRTC();
beginLightTest();
beginTimers();
clearLCD();
}
/***********
MAIN LOOP
***********/
void loop()
{
int currentMillis = millis();
//Check display Menu
//Check lightmode timer
if (currentMillis - DisplayMenuTimer >= DisplayMenuTimerDur)
{
DisplayMenu++;
if(DisplayMenu >= NUM_MENUS)
DisplayMenu = MODE_MENU;
DisplayMenuTimer = millis();
}
//Check display timer
if (currentMillis - DisplayTimer >= DisplayTimerDur)
{
CurrentHour = hour();
digitalDisplay();
DisplayTimer = millis();
}
//Check lightmode timer
if (currentMillis - SetLightmodeTimer >= SetLightmodeTimerDur)
{
setLightMode();
SetLightmodeTimer = millis();
}
//Check intensity timer
if (currentMillis - SetLightIntensityTimer >= SetLightIntensityTimerDur)
{
setLighting();
setIntensity(WhiteIntensity, BlueIntensity);
SetLightIntensityTimer = millis();
}
}
/**********
Display Functions
**********/
void digitalDisplay(){
// digital clock display of the time
selectLineOne();
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(month());
Serial.print("/");
Serial.print(day());
selectLineTwo();
switch (DisplayMenu) {
case MODE_MENU:
Serial.print("Mode: ");
Serial.print(LightmodeStrings[Lightmode]);
Serial.print(" ");
break;
case INTENSITY_MENU:
Serial.print("Int:");
printDigits999(WhiteIntensity);
Serial.print("w ");
printDigits999(BlueIntensity);
Serial.print("b ");
break;
}
}
/***********
Setup Functions
***********/
void beginLightTest()
{
TestMode = 1;
for(int i = 0; i < 4; i++)
{
Lightmode = i;
setLighting();
setIntensity(WhiteIntensity, BlueIntensity);
clearLCD();
selectLineTwo();
Serial.print("Mode: ");
Serial.print(i);
//Serial.println();
delay(3000);
}
TestMode = 0;
CurrentHour = hour();
setLightMode();
}
void beginTimers()
{
//setTime(8,29,0,1,1,10); // set time to 8:29:00am Jan 1 2010
//setTime(18,0,0,26,12,10); // set time to 8:29:00am Jan 1 2010
//Alarm.timerRepeat(30, taskSetLightMode); // check lightMode every 30 seconds
resetTimers();
}
void beginRTC()
{
setSyncProvider(RTC.get); // the function to get the time from the RTC
if(timeStatus()!= timeSet)
Serial.println("Unable to sync with the RTC");
else
Serial.println("RTC has set the system time");
}
void beginSerialLCD()
{
delay(500); //wait
clearLCD();
selectLineOne();
Serial.print("AquaLight v2.0");
delay(2000);
clearLCD();
}
void beginPwm()
{
//pins 3,11 have a base of 31250 Hz
int divisor = 64; // 488.28125 Hz
setPwmFrequency(WHITE_PIN, divisor);
setPwmFrequency(BLUE_PIN, divisor);
}
void setPwmFrequency(int pin, int divisor) {
byte mode;
if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
switch(divisor) {
case 1: mode = 0x01; break;
case 8: mode = 0x02; break;
case 64: mode = 0x03; break;
case 256: mode = 0x04; break;
case 1024: mode = 0x05; break;
default: return;
}
if(pin == 5 || pin == 6) {
TCCR0B = TCCR0B & 0b11111000 | mode;
} else {
TCCR1B = TCCR1B & 0b11111000 | mode;
}
} else if(pin == 3 || pin == 11) {
switch(divisor) {
case 1: mode = 0x01; break;
case 8: mode = 0x02; break;
case 32: mode = 0x03; break;
case 64: mode = 0x04; break;
case 128: mode = 0x05; break;
case 256: mode = 0x06; break;
case 1024: mode = 0x7; break;
default: return;
}
TCCR2B = TCCR2B & 0b11111000 | mode;
}
}
/***********
Light Modes
***********/
void dark()
{
WhiteIntensity = 255;
BlueIntensity = 255;
}
void daylight()
{
if (TestMode == 1)
{
WhiteIntensity = 10;
BlueIntensity = 10;
return;
}
if (random(100) == 42)
{
WhiteVariance = random(240);
BlueVariance = random(240);
}
WhiteIntensity = fadeTowards(WhiteIntensity, 10 + WhiteVariance, 1);
BlueIntensity = fadeTowards(BlueIntensity, 10 + BlueVariance, 1);
}
void highlight()
{
if (TestMode == 1)
{
WhiteIntensity = 255;
BlueIntensity = 10;
return;
}
int timerDiff = millis() - HighlightTimer;
if (timerDiff >= HighlightTimerDur)
{
switch (HighlightLatch) {
case 0:
//fade out the white, fade in the blue
WhiteIntensity = fadeTowards(WhiteIntensity,255,1);
BlueIntensity = fadeTowards(BlueIntensity,10,1);
if (BlueIntensity <= 10)
HighlightLatch = 1; //goto next sequence
break;
case 1:
//fade out the blue
WhiteIntensity = fadeTowards(WhiteIntensity,255,1);
BlueIntensity = fadeTowards(BlueIntensity,255,1);
if (BlueIntensity > 254)
HighlightLatch = 2; //goto next sequence
break;
case 2:
//fade in the white
WhiteIntensity = fadeTowards(WhiteIntensity,10,1);
BlueIntensity = fadeTowards(BlueIntensity,255,1);
if (WhiteIntensity < 11)
HighlightLatch = 3; //goto next sequence
break;
case 3:
//fade out the white
WhiteIntensity = fadeTowards(WhiteIntensity,255,1);
BlueIntensity = fadeTowards(BlueIntensity,255,1);
if (WhiteIntensity < 11)
HighlightLatch = 0; //goto next sequence
break;
}
HighlightTimer = millis();
}
}
void moonlight()
{
if (TestMode == 1)
{
WhiteIntensity = 255;
BlueIntensity = 254;
return;
}
if (random(100) == 50)
{
BlueVariance = random(5);
}
WhiteIntensity = 255;
BlueIntensity = fadeTowards(BlueIntensity, 250 + BlueVariance, 1);
}
/**********
Light Functions
**********/
void setLighting()
{
switch(Lightmode) {
case DARK_MODE:
dark();
break;
case DAYLIGHT_MODE:
daylight();
break;
case HIGHLIGHT_MODE:
highlight();
break;
case MOONLIGHT_MODE:
moonlight();
break;
default:
dark();
}
}
void setIntensity(int white, int blue)
{
analogWrite(WHITE_PIN, white);
analogWrite(BLUE_PIN, blue);
}
int fadeTowards(int input, int dest, int increment)
{
int output;
if (input > dest)
{
output = input - increment;
}
else if (input < dest)
{
output = input + increment;
}
else
{
output = input;
}
return output;
}
/***********
Sparkfun Serial LCD
Functions
************/
void selectLineOne(){ //puts the cursor at line 0 char 0.
Serial.print(0xFE, BYTE); //command flag
Serial.print(128, BYTE); //position
}
void selectLineTwo(){ //puts the cursor at line 0 char 0.
Serial.print(0xFE, BYTE); //command flag
Serial.print(192, BYTE); //position
}
void goTo(int position) {
//position = line 1: 0-15, line 2: 16-31, 31+ defaults back to 0
if (position<16){ Serial.print(0xFE, BYTE); //command flag
Serial.print((position+128), BYTE); //position
}else if (position<32){Serial.print(0xFE, BYTE); //command flag
Serial.print((position+48+128), BYTE); //position
} else { goTo(0); }
}
void clearLCD(){
Serial.print(0xFE, BYTE); //command flag
Serial.print(0x01, BYTE); //clear command.
}
void backlightOn(){ //turns on the backlight
Serial.print(0x7C, BYTE); //command flag for backlight stuff
Serial.print(157, BYTE); //light level.
}
void backlightOff(){ //turns off the backlight
Serial.print(0x7C, BYTE); //command flag for backlight stuff
Serial.print(128, BYTE); //light level for off.
}
void serCommand(){ //a general function to call the command flag for issuing all other commands
Serial.print(0xFE, BYTE);
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
void printDigits999(int digits)
{
if (digits < 100)
Serial.print('0');
if (digits < 10)
Serial.print('0');
Serial.print(digits);
}
/*****
Timer functions
*****/
void resetTimers()
{
DisplayTimer = millis();
SetLightmodeTimer = millis();
SetLightIntensityTimer = millis();
HighlightTimer = millis();
DisplayMenuTimer = millis();
}
/*
taskSetLightMode - checks the current hour and sets the lighting mode
get all diffs: CurrentHour - Lightmode Hour
rule out any negatives (where current hour already past time)
special case: when should moonlight end?
if hour is between midnight and next dark hour, all diffs will already be negative
if hour is 1, next dark hour is 2, and last moon hour was 21
*/
void setLightMode()
{
int darkDiff = getHourDiff(CurrentHour, DarkHour);
int daylightDiff = getHourDiff(CurrentHour, DaylightHour);
int highlightDiff = getHourDiff(CurrentHour, HighlightHour);
int moonlightDiff = getHourDiff(CurrentHour, MoonlightHour);
//make sure these are in the same order as the lightModes.. then we won't have to compare to figure out which mode is which value.
byte diffs[] = {darkDiff, daylightDiff, highlightDiff, moonlightDiff};
//set all negatives to 99
for(int i = 0; i < 4; i++)
{
if(diffs[i] < 0)
{
diffs[i] = 99;
}
}
//find minimum value
int minimum = diffs[0];
int minCount = 0;
for(int i = 0; i < 4; i++)
{
if(diffs[i] < minimum)
{
minimum = diffs[i];
minCount = i;
}
}
Lightmode = minCount;
setLighting();
}
int getHourDiff(int currenthour, int diffHour)
{
int result = 99;
if (currenthour == 0)
currenthour = 24;
//check if we're in the special case hour
if (currenthour < DarkHour && diffHour > DarkHour)
{
result = currenthour + (24 - diffHour); // example: 1am -> 1 + (24 - 14) = 11, so 11 hours since 2pm
} else {
result = currenthour - diffHour;
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment