/*I N C L U D E S |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ #include #include "Wire.h" #define DS1307_I2C_ADDRESS 0x68 //Real Time Clock I2C Location /*D E F I N E S S E T U P ||||||||||||||||||||||||||||||||||||||||||||||||||*/ #define BUTTON_ADC_PIN A0 // A0 is the button ADC input #define LCD_BACKLIGHT_PIN 8 // D3 controls LCD backlight #define RIGHT_10BIT_ADC 0 // right #define UP_10BIT_ADC 119 // up #define DOWN_10BIT_ADC 315 // down #define LEFT_10BIT_ADC 485 // left #define SELECT_10BIT_ADC 770 // right #define BUTTONHYSTERESIS 10 // hysteresis for valid button sensing window #define BUTTON_NONE 0 // #define BUTTON_RIGHT 1 // #define BUTTON_UP 2 // #define BUTTON_DOWN 3 // #define BUTTON_LEFT 4 // #define BUTTON_SELECT 5 // //some example macros with friendly labels for LCD backlight/pin control, tested and can be swapped into the example code as you like #define LCD_BACKLIGHT_OFF() digitalWrite( LCD_BACKLIGHT_PIN, LOW ) #define LCD_BACKLIGHT_ON() digitalWrite( LCD_BACKLIGHT_PIN, HIGH ) #define LCD_BACKLIGHT(state) { if( state ){digitalWrite( LCD_BACKLIGHT_PIN, HIGH );}else{digitalWrite( LCD_BACKLIGHT_PIN, LOW );} } /*V A R I A B L E S |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ int backlightcountdown = 1000; String mainmenu="Auto"; int SR=360; //Sunrise start time in minutes int SRch1=50; //Channel 1 strength 0-255 int SRch2=50; //Channel 2 strength 0-255 int SRch3=50; //Channel 3 strength 0-255 int SRch4=50; //Channel 4 strength 0-255 int SRramp=30; //Sunrise ramp time in minuntes int DT=450; int DTch1=255; int DTch2=255; int DTch3=255; int DTch4=255; int DTramp=30; int SSt=1080; int SStch1=50; int SStch2=50; int SStch3=50; int SStch4=50; int SStramp=30; int ML=1260; int MLch1=1; int MLch2=1; int MLch3=1; int MLch4=1; int MLramp=30; int ST=1410; int STch1=0; int STch2=0; int STch3=0; int STch4=0; int STramp=30; float Ramppct=0; int chan1=0; int chan2=0; int chan3=0; int chan4=0; float ch1target=0; float ch2target=0; float ch3target=0; float ch4target=0; int menulevel1=0; int menulevel2=0; int PWMchan1=9; int PWMchan2=10; int PWMchan3=6; int PWMchan4=5; int godefault=0; byte buttonJustPressed = false; //this will be true after a ReadButtons() call if triggered byte buttonJustReleased = false; //this will be true after a ReadButtons() call if triggered byte buttonWas = BUTTON_NONE; //used by ReadButtons() for detection of button events int daybyminute = 1; // Current timeof day in minutes const int buttonPin = 41; // The number of the pushbutton Digital pin LiquidCrystal lcd(12,11,0,3,4,5); // LCD: ( RS=12, E=11, D0, D3, D4, D5 ) //setup() /* R T C C L O C K D S 1 3 0 7 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ byte decToBcd(byte val) // Convert normal decimal numbers to binary coded decimal { return ( (val/10*16) + (val%10) ); } byte bcdToDec(byte val) // Convert binary coded decimal to normal decimal numbers { return ( (val/16*10) + (val%16) ); } 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.write(0); Wire.write(decToBcd(second)); // 0 to bit 7 starts the clock Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); // If you want 12 hour am/pm you need to set // bit 6 (also need to change readDateDs1307) Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); 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.write(0); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS, 7); // A few of these need masks because certain bits are control bits *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); // Need to change this if 12 hour am/pm *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } /* O N E S E C O N D |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void onesecond() //function that runs once per second while program is running { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); daybyminute = ((hour * 60) + minute); //converts time of day to a single value in minutes lcd.setCursor(0, 0); if(hour>0) { if(hour<=12) { lcd.print(hour, DEC); } else { lcd.print(hour-12, DEC); } } else { lcd.print("12"); } lcd.print(":"); if (minute < 10) { lcd.print("0"); } lcd.print(minute, DEC); lcd.print(":"); if (second < 10) { lcd.print("0"); } lcd.print(second, DEC); if(hour<12) { lcd.print("am"); } else { lcd.print("pm"); } lcd.print(" "); delay(1000); } /* A U T O |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void auto1() { String timeslot = " " ; microsecond(); if (daybyminute>=SR && daybyminute=DT && daybyminute=SSt && daybyminute=ML && daybyminute=ST && daybyminutechan1) { chan1++ ; } else if (ch1targetchan2) { chan2++; } else if (ch2targetchan3) { chan3++; } else if (ch3targetchan4) { chan4++; } else if (ch4target2){ led_sel=3; } } if (button==BUTTON_LEFT){ led_sel--; if (led_sel<1){ led_sel=0; } } if (button==BUTTON_UP){ switch (led_sel) { case 0: chan1++; if (chan1 > 255) chan1=255; break; case 1: chan2++; if (chan2 > 255) chan2=255; break; case 2: chan3++; if (chan3 > 255) chan3=255; break; case 3: chan4++; if (chan4 > 255) chan4=255; break; } } if (button==BUTTON_DOWN){ switch (led_sel) { case 0: chan1--; if (chan1 < 0) chan1=0; break; case 1: chan2--; if (chan2 < 0) chan2=0; break; case 2: chan3--; if (chan3 < 0) chan3=0; break; case 3: chan4--; if (chan4 < 0) chan4=0; break; } } ledSetAll(); lcd.clear(); lcd.print(" Manual Control"); lcd.setCursor(0,1); lcd.print(map(chan1, 0, 255, 0, 100)); lcd.setCursor(4,1); lcd.print(map(chan2, 0, 255, 0, 100)); lcd.setCursor(8,1); lcd.print(map(chan3, 0, 255, 0, 100)); lcd.setCursor(12,1); lcd.print(map(chan4, 0, 255, 0, 100)); lcd.setCursor(led_sel*4,1); delay(100); button = ReadButtons(); } lcd.clear(); lcd.noBlink(); } /* C O N F I G U R E |||||||||||||||||||||||||||||||||||||||||||||||||||*/ void configure() { } /* R E S E T |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void reset() { byte button; byte timestamp; lcd.setCursor(0,0); lcd.print(" Reset Certain?"); lcd.setCursor(0,1); lcd.print(" No "); delay(500); godefault=0; while (menulevel1==3) { button = ReadButtons(); switch( button ) { case BUTTON_NONE: { break; } case BUTTON_RIGHT: { lcd.setCursor(0,1); lcd.print(" Yes "); godefault=1; delay(200); break; } case BUTTON_UP: { break; } case BUTTON_DOWN: { break; } case BUTTON_LEFT: { lcd.setCursor(0,1); lcd.print(" No "); godefault=0; delay(200); break; } case BUTTON_SELECT: { lcd.setCursor( 0, 1 ); if (godefault==0) { lcd.print("Reset Cancelled "); delay(1000); } else { lcd.print( "Factory Reset " ); delay(1000); //SELECT is a special case, it pulses the LCD backlight off and on for demo digitalWrite( LCD_BACKLIGHT_PIN, LOW ); delay( 150 ); digitalWrite( LCD_BACKLIGHT_PIN, HIGH ); //leave the backlight on at exit delay( 150 ); SR=360; //Sunrise start time in minutes SRch1=50; //Channel 1 strength 0-255 SRch2=50; //Channel 2 strength 0-255 SRch3=50; //Channel 3 strength 0-255 SRch4=50; //Channel 4 strength 0-255 SRramp=30; //Sunrise ramp time in minuntes DT=630; DTch1=255; DTch2=255; DTch3=255; DTch4=255; DTramp=30; SSt=1080; SStch1=50; SStch2=50; SStch3=50; SStch4=50; SStramp=30; ML=1260; MLch1=1; MLch2=1; MLch3=1; MLch4=1; MLramp=30; ST=1410; STch1=0; STch2=0; STch3=0; STch4=0; STramp=30; Ramppct=0; } menulevel1=0; LCD_BACKLIGHT(true); //leave the backlight on at exit delay( 150 ); break; } default: { break; } } } lcd.setCursor(0,0); lcd.print(" "); lcd.setCursor(0,1); lcd.print(" "); } /* M E N U L E V E L |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void menulevel() { switch (menulevel1) { case 0: mainmenu="Auto"; break; case 1: mainmenu="Manual"; break; case 2: mainmenu="Setup"; break; case 3: mainmenu="Reset"; break; } lcd.setCursor(8, 0); lcd.print(" "); lcd.setCursor(8, 0); lcd.print(mainmenu); } /* M I C R O S E C O N D |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void microsecond() //function that pulls current time { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); daybyminute = ((hour * 60) + minute); //converts time of day to a single value in minutes lcd.setCursor(0, 0); if(hour>0) { if(hour<=12) { if(hour<10) { lcd.print(" "); } lcd.print(hour, DEC); } else { lcd.print(hour-12, DEC); } } else { lcd.print("12"); } lcd.print(":"); if (minute < 10) { lcd.print("0"); } lcd.print(minute, DEC); // lcd.print(":"); // if (second < 10) { // lcd.print("0"); // } // lcd.print(second, DEC); if(hour<12) { lcd.print("A"); } else { lcd.print("P"); } lcd.print(" "); delay(50); } // format hours, mins, secs into a readable time (24 hr format) void printHMS (byte hr, byte mn, byte sec //time to print ) { if(hr<10){ lcd.print(" "); } lcd.print(hr, DEC); lcd.print(":"); if(mn<10){ lcd.print("0"); } lcd.print(mn, DEC); lcd.print(":"); if(sec<10){ lcd.print("0"); } lcd.print(sec, DEC); } /* L E D S E T A L L ||||||||||||||||||||||||||||||||||||||||||||||||||*/ void ledSetAll(){ analogWrite(PWMchan1,chan1); analogWrite(PWMchan2,chan2); analogWrite(PWMchan3,chan3); // analogWrite(PWMchan4,chan4); } /* S E T U P |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void setup() { // initialize the manual pushbutton pin as an input: pinMode(buttonPin, INPUT); byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; Wire.begin(); // 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. // second = 45; // minute = 56; // hour = 21; // dayOfWeek = 4; // Sunday is 0 // dayOfMonth = 6; // month = 12; // year = 12; // setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year); lcd.begin(20, 2); // set up the LCD's number of rows and columns: pinMode( BUTTON_ADC_PIN, INPUT ); //ensure A0 is an input digitalWrite( BUTTON_ADC_PIN, LOW ); //ensure pullup is off on A0 //lcd backlight control // digitalWrite( LCD_BACKLIGHT_PIN, HIGH ); //backlight control pin D3 is high (on) // pinMode( LCD_BACKLIGHT_PIN, OUTPUT ); //D3 is an output } /* L O O P |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ void loop() { byte button; byte timestamp; microsecond(); // lcd.clear(); if (menulevel1==0) { auto1(); } if (backlightcountdown > 0) { backlightcountdown--; digitalWrite( LCD_BACKLIGHT_PIN, HIGH ); } else { digitalWrite( LCD_BACKLIGHT_PIN, LOW ); } //get the latest button pressed, also the buttonJustPressed, buttonJustReleased flags button = ReadButtons(); //blank the demo text line if a new button is pressed or released, ready for a new label to be written if( buttonJustPressed || buttonJustReleased ) { lcd.setCursor( 4, 1 ); lcd.print( " " ); } switch( button ) { case BUTTON_NONE: { break; } case BUTTON_RIGHT: { backlightcountdown=1000; menulevel1=menulevel1++; if (menulevel1>3) { menulevel1=0; } lcd.setCursor( 4, 1 ); lcd.print( "RIGHT" ); delay(200); break; } case BUTTON_UP: { backlightcountdown=1000; lcd.setCursor( 4, 1 ); lcd.print( "UP" ); break; } case BUTTON_DOWN: { backlightcountdown=1000; lcd.setCursor( 4, 1 ); lcd.print( "DOWN" ); break; } case BUTTON_LEFT: { backlightcountdown=1000; menulevel1=menulevel1-- ; if (menulevel1<0) { menulevel1=3; } lcd.setCursor( 4, 1 ); lcd.print( "LEFT" ); delay(200); break; } case BUTTON_SELECT: { backlightcountdown=1000; switch(menulevel1) { case 0: { auto1(); break; } case 1: { manual(); break; } case 2: { configure(); break; } case 3: { reset(); break; } } lcd.setCursor( 4, 1 ); lcd.print( "SELECT-FLASH" ); // delay( 150 ); // LCD_BACKLIGHT_OFF(); // delay( 150 ); // LCD_BACKLIGHT_ON(); //leave the backlight on at exit // delay( 150 ); break; } default: { break; } } menulevel(); // print the number of seconds since reset (two digits only) timestamp = ( (millis() / 1000) % 100 ); //"% 100" is the remainder of a divide-by-100, which keeps the value as 0-99 even as the result goes over 100 // lcd.setCursor( 14, 1 ); // if( timestamp <= 9 ) // lcd.print( " " ); //quick trick to right-justify this 2 digit value when it's a single digit // lcd.print( timestamp, DEC ); /* //debug/test display of the adc reading for the button input voltage pin. lcd.setCursor(12, 0); lcd.print( " " ); //quick hack to blank over default left-justification from lcd.print() lcd.setCursor(12, 0); //note the value will be flickering/faint on the LCD lcd.print( analogRead( BUTTON_ADC_PIN ) ); */ //clear the buttonJustPressed or buttonJustReleased flags, they've already done their job now. if( buttonJustPressed ) buttonJustPressed = false; if( buttonJustReleased ) buttonJustReleased = false; ledSetAll(); } /* R E A D B U T T O N S |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ byte ReadButtons() { unsigned int buttonVoltage; byte button = BUTTON_NONE; // return no button pressed if the below checks don't write to btn //read the button ADC pin voltage buttonVoltage = analogRead( BUTTON_ADC_PIN ); //sense if the voltage falls within valid voltage windows if( buttonVoltage < ( RIGHT_10BIT_ADC + BUTTONHYSTERESIS ) ) { button = BUTTON_RIGHT; } else if( buttonVoltage >= ( UP_10BIT_ADC - BUTTONHYSTERESIS ) && buttonVoltage <= ( UP_10BIT_ADC + BUTTONHYSTERESIS ) ) { button = BUTTON_UP; } else if( buttonVoltage >= ( DOWN_10BIT_ADC - BUTTONHYSTERESIS ) && buttonVoltage <= ( DOWN_10BIT_ADC + BUTTONHYSTERESIS ) ) { button = BUTTON_DOWN; } else if( buttonVoltage >= ( LEFT_10BIT_ADC - BUTTONHYSTERESIS ) && buttonVoltage <= ( LEFT_10BIT_ADC + BUTTONHYSTERESIS ) ) { button = BUTTON_LEFT; } else if( buttonVoltage >= ( SELECT_10BIT_ADC - BUTTONHYSTERESIS ) && buttonVoltage <= ( SELECT_10BIT_ADC + BUTTONHYSTERESIS ) ) { button = BUTTON_SELECT; } //handle button flags for just pressed and just released events if( ( buttonWas == BUTTON_NONE ) && ( button != BUTTON_NONE ) ) { //the button was just pressed, set buttonJustPressed, this can optionally be used to trigger a once-off action for a button press eve //it's the duty of the receiver to clear these flags if it wants to detect a new button change event buttonJustPressed = true; buttonJustReleased = false; } if( ( buttonWas != BUTTON_NONE ) && ( button == BUTTON_NONE ) ) { buttonJustPressed = false; buttonJustReleased = true; } //save the latest button value, for change event detection next time round buttonWas = button; return( button ); }