Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Hand tools and fabrication machines | ||||||
|
This is by far the BEST CLOCK AND CODE EVER. This is why I still have not completed it yet as you can see CLEARLY after these 2 years because I was SOOOO happy I got it to work and I just left it like that. AND IT STILL IS HOLD ON BY TAPE. LIKE PROVEN IN THE PICTURES. LOL. ( inside joke PROOF )
please read the story below the video comic it was there FROM DAY ONE, I BUILD THIS CLOCK IN HIS HONOR. ( this will are be clear soon )
New Code and more info see my Github repo. Also more on libraries there. https://github.com/wannaduino/RiseAndShineNanoClock ( updated code )
The foundations of this code is based on the same document made available by Arduino.cc under the Creative Commons Sharealike license. This derivative document is licensed under the Creative Commons Sharealike license. 3.0 C++
But my advice is use my old code below. And without the switch.
And if you look in the HOW TO SET THE CLOCK DIAGRAM, you see the name of the builders CLOCK ( RISE AND SHINE ) proof enough eeh. lol
TIMELESS or SHAMELESS, you tell me. who wants to go in the TIMELINE OF A FAME SEEKER? Creative Commons Attribution ShareAlike License V3.0
- THIS IS ALL YOU NEED TO KNOW WHY.
I am just a clock/DIY/LED junky, and then i came across a clock build.
I was amazed and mesmerized by the simplicity.
So i had to made it myself in his honor, that is my trademark doing it in honor of the builder barkenmad.
It is working via a Rotary encoder that does all the work, to run thru the settings and act as an switch, all connected to the Arduino Nano the brain of this operation.
I just finished my test setup, and now i will make it CLEAN as an Art Piece, so the tape, YEAH the tape is TEST FITTING.
And you can use almost any 4 cm deep frame, mine comes from the action, but you can also use the RIBBA from IKEA. mine came with some LEDS inside already as you can see with a battery box, that would also be implemented in the power supply with an buck regulator to lower the voltage from 5V to 2.4Volts.
WannaDuino https://www.wannaduino.com
Fritzing diagram
But this diagram shows how you can wire it up, but this is also in the code with exact arduino nano pinouts. ( the code BELOW )
Clock_with_rtc1307.ino
C/C++//The foundations of this code is based on the same document made available by Arduino.cc under the Creative Commons Sharealike license. This derivative document is licensed under the Creative Commons Sharealike license. 3.0 C++
// Add options for background settings
// TO DO: Clean up and comment code...
// BUG: demo state should start as mode 0 after intro
// NICE TO HAVE: When alarm is cancelled, the alarm still remains set for next day.
//Add the following libraries to the respective folder for you operating system. See http://arduino.cc/en/Guide/Environment
#include <FastLED.h> // FastSPI Library from http://code.google.com/p/fastspi/
#include <Wire.h> //This is to communicate via I2C. On arduino Uno & Nano use pins A4 for SDA (yellow/orange) and A5 for SCL (green). For other boards ee http://arduino.cc/en/Reference/Wire
#include <RTClib.h> // Include the RTClib library to enable communication with the real time clock.
#include <EEPROM.h> // Include the EEPROM library to enable the storing and retrevel of settings.
#include <Bounce.h> // Include the Bounce library for de-bouncing issues with push buttons.
#include <Encoder.h> // Include the Encoder library to read the out puts of the rotary encoders
RTC_DS1307 RTC; // Establishes the chipset of the Real Time Clock
#define LEDStripPin 6 // Pin used for the data to the LED strip
#define menuPin 0 // Pin used for the menu button (green stripe)
#define numLEDs 60 // Number of LEDs in strip
// Setting up the LED strip
struct CRGB leds[numLEDs];
Encoder rotary1(3, 4); // Setting up the Rotary Encoder
DateTime old; // Variable to compare new and old time, to see if it has moved on.
int rotary1Pos = 0;
int subSeconds; // 60th's of a second
int secondBrightness;
int secondBrightness2;
int breathBrightness;
long newSecTime; // Variable to record when a new second starts, allowing to create milli seconds
long oldSecTime;
long flashTime; //
long breathCycleTime;
#define holdTime 1500
int cyclesPerSec;
float cyclesPerSecFloat; // So can be used as a float in calcs
float fracOfSec;
float breathFracOfSec;
boolean demo;
#define demoTime 12 // seconds
long previousDemoTime;
long currentDemoTime;
boolean swingBack = false;
int timeHour;
int timeMin;
int timeSec;
int alarmMin; // The minute of the alarm
int alarmHour; // The hour of the alarm 0-23
int alarmDay = 0; // The day of the alarm
boolean alarmSet; // Whether the alarm is set or not
int modeAddress = 0; // Address of where mode is stored in the EEPROM
int alarmMinAddress = 1; // Address of where alarm minute is stored in the EEPROM
int alarmHourAddress = 2; // Address of where alarm hour is stored in the EEPROM
int alarmSetAddress = 3; // Address of where alarm state is stored in the EEPROM
int alarmModeAddress = 4; // Address of where the alarm mode is stored in the EEPROM
boolean alarmTrig = false; // Whether the alarm has been triggered or not
long alarmTrigTime; // Milli seconds since the alarm was triggered
boolean countDown = false;
long countDownTime = 0;
long currentCountDown = 0;
long startCountDown;
int countDownMin;
int countDownSec;
int countDownFlash;
int demoIntro = 0;
int j = 0;
long timeInterval = 5;
long currentMillis;
long previousMillis = 0;
float LEDBrightness = 0;
float fadeTime;
float brightFadeRad;
int state = 0; // Variable of the state of the clock, with the following defined states
#define clockState 0
#define alarmState 1
#define setAlarmHourState 2
#define setAlarmMinState 3
#define setClockHourState 4
#define setClockMinState 5
#define setClockSecState 6
#define countDownState 7
#define demoState 8
int mode; // Variable of the display mode of the clock
int modeMax = 6; // Change this when new modes are added. This is so selecting modes can go back beyond.
int alarmMode; // Variable of the alarm display mode
int alarmModeMax = 3;
Bounce menuBouncer = Bounce(menuPin,20); // Instantiate a Bounce object with a 50 millisecond debounce time for the menu button
boolean menuButton = false;
boolean menuPressed = false;
boolean menuReleased = false;
int advanceMove = 0;
boolean countTime = false;
long menuTimePressed;
long lastRotary;
int rotaryTime = 1000;
int LEDPosition;
int reverseLEDPosition;
int pendulumPos;
int fiveMins;
int odd;
int LEDOffset = 30;
void setup()
{
// Set up all pins
pinMode(menuPin, INPUT_PULLUP); // Uses the internal 20k pull up resistor. Pre Arduino_v.1.0.1 need to be "digitalWrite(menuPin,HIGH);pinMode(menuPin,INPUT);"
// Start LEDs
LEDS.addLeds<WS2811, LEDStripPin, GRB>(leds, numLEDs); // Structure of the LED data. I have changed to from rgb to grb, as using an alternative LED strip. Test & change these if you're getting different colours.
// Start RTC
Wire.begin(); // Starts the Wire library allows I2C communication to the Real Time Clock
RTC.begin(); // Starts communications to the RTC
Serial.begin(9600); // Starts the serial communications
// Uncomment to reset all the EEPROM addresses. You will have to comment again and reload, otherwise it will not save anything each time power is cycled
// write a 0 to all 512 bytes of the EEPROM
// for (int i = 0; i < 512; i++)
// {EEPROM.write(i, 0);}
// Load any saved setting since power off, such as mode & alarm time
mode = EEPROM.read(modeAddress); // The mode will be stored in the address "0" of the EEPROM
alarmMin = EEPROM.read(alarmMinAddress); // The mode will be stored in the address "1" of the EEPROM
alarmHour = EEPROM.read(alarmHourAddress); // The mode will be stored in the address "2" of the EEPROM
alarmSet = EEPROM.read(alarmSetAddress); // The mode will be stored in the address "2" of the EEPROM
alarmMode = EEPROM.read(alarmModeAddress);
// Prints all the saved EEPROM data to Serial
Serial.print("Mode is ");Serial.println(mode);
Serial.print("Alarm Hour is ");Serial.println(alarmHour);
Serial.print("Alarm Min is ");Serial.println(alarmMin);
Serial.print("Alarm is set ");Serial.println(alarmSet);
Serial.print("Alarm Mode is ");Serial.println(alarmMode);
// create a loop that calcuated the number of counted milliseconds between each second.
DateTime now = RTC.now();
// startTime = millis();
// while (RTC.old() = RTC.new())
// if (now.month() == 1 && now.day() == 1 && now.hour() == 0 && now.minute() == 0 && now.minute() == 0)
// {}
Serial.print("Hour time is... ");
Serial.println(now.hour());
Serial.print("Min time is... ");
Serial.println(now.minute());
Serial.print("Sec time is... ");
Serial.println(now.second());
Serial.print("Year is... ");
Serial.println(now.year());
Serial.print("Month is... ");
Serial.println(now.month());
Serial.print("Day is... ");
Serial.println(now.day());
}
void loop()
{
DateTime now = RTC.now(); // Fetches the time from RTC
// Check for any button presses and action accordingley
menuButton = menuBouncer.update(); // Update the debouncer for the menu button and saves state to menuButton
rotary1Pos = rotary1.read(); // Checks the rotary position
if (rotary1Pos <= -2 && lastRotary - millis() >= rotaryTime)
{
advanceMove = -1;
rotary1.write(0);
lastRotary = millis();
}
if (rotary1Pos >= 2 && lastRotary - millis() >= rotaryTime)
{
advanceMove = 1;
rotary1.write(0);
lastRotary = millis();
}
if (menuButton == true || advanceMove != 0 || countTime == true) {buttonCheck(menuBouncer,now);}
// clear LED array
memset(leds, 0, numLEDs * 3);
// Check alarm and trigger if the time matches
if (alarmSet == true && alarmDay != now.day()) // The alarmDay statement ensures it is a newly set alarm or repeat from previous day, not within the minute of an alarm cancel.
{
if (alarmTrig == false) {alarm(now);}
else {alarmDisplay();}
}
// Check the Countdown Timer
if (countDown == true)
{
currentCountDown = countDownTime + startCountDown - now.unixtime();
if ( currentCountDown <= 0)
{
state =countDownState;
}
}
// Set the time LED's
if (state == setClockHourState || state == setClockMinState || state == setClockSecState) {setClockDisplay(now);}
else if (state == alarmState || state == setAlarmHourState || state == setAlarmMinState) {setAlarmDisplay();}
else if (state == countDownState) {countDownDisplay(now);}
else if (state == demoState) {runDemo(now);}
else {timeDisplay(now);}
// Update LEDs
LEDS.show();
}
void buttonCheck(Bounce menuBouncer, DateTime now)
{
if (menuBouncer.fallingEdge()) // Checks if a button is pressed, if so sets countTime to true
{
countTime = true;
Serial.println("rising edge");
}
if (menuBouncer.risingEdge()) // Checks if a button is released,
{
countTime = false;
Serial.println("rising edge");
} // if so sets countTime to false. Now the ...TimePressed will not be updated when enters the buttonCheck,
if (countTime) // otherwise will menuBouncer.duration will
{
menuTimePressed = menuBouncer.duration();
if (menuTimePressed >= (holdTime - 100) && menuTimePressed <= holdTime)
{
clearLEDs();
LEDS.show();
delay(100);
}
}
menuReleased = menuBouncer.risingEdge();
if (menuPressed == true) {Serial.println("Menu Button Pressed");}
if (menuReleased == true) {Serial.println("Menu Button Released");}
Serial.print("Menu Bounce Duration ");
Serial.println(menuTimePressed);
if (alarmTrig == true)
{
alarmTrig = false;
alarmDay = now.day(); // When the alarm is cancelled it will not display until next day. As without it, it would start again if within a minute, or completely turn off the alarm.
delay(300); // I added this 300ms delay, so there is time for the button to be released
return; // This return exits the buttonCheck function, so no actions are performs
}
switch (state)
{
case clockState: // State 0
if (advanceMove == -1 && mode == 0)
{
mode = modeMax;
advanceMove = 0;
}
else if(advanceMove != 0) //if displaying the clock, advance button is pressed & released, then mode will change
{
mode = mode + advanceMove;
EEPROM.write(modeAddress,mode);
advanceMove = 0;
}
else if(menuReleased == true)
{
if (menuTimePressed <= holdTime) {state = alarmState; newSecTime = millis();}// if displaying the clock, menu button is pressed & released, then Alarm is displayed
else {state = setClockHourState;} // if displaying the clock, menu button is held & released, then clock hour can be set
}
break;
case alarmState: // State 1
if (advanceMove == -1 && alarmMode <= 0)
{
alarmMode = alarmModeMax;
alarmSet = 1;
}
else if (advanceMove == 1 && alarmMode >= alarmModeMax)
{
alarmMode = 0;
alarmSet = 0;
}
else if (advanceMove != 0)
{
alarmMode = alarmMode + advanceMove;
if (alarmMode == 0) {alarmSet = 0;}
else {alarmSet = 1;}
}
Serial.print("alarmState is ");
Serial.println(alarmState);
Serial.print("alarmMode is ");
Serial.println(alarmMode);
EEPROM.write(alarmSetAddress,alarmSet);
EEPROM.write(alarmModeAddress,alarmMode);
advanceMove = 0;
alarmTrig = false;
if (menuReleased == true)
{
if (menuTimePressed <= holdTime) {state = countDownState; j = 0;}// if displaying the alarm time, menu button is pressed & released, then clock is displayed
else {state = setAlarmHourState;} // if displaying the alarm time, menu button is held & released, then alarm hour can be set
}
break;
case setAlarmHourState: // State 2
if (menuReleased == true) {state = setAlarmMinState;}
else if (advanceMove == 1 && alarmHour >= 23) {alarmHour = 0;}
else if (advanceMove == -1 && alarmHour <= 0) {alarmHour = 23;}
else if (advanceMove != 0) {alarmHour = alarmHour + advanceMove;}
EEPROM.write(alarmHourAddress,alarmHour);
advanceMove = 0;
break;
case setAlarmMinState: // State 3
if (menuReleased == true)
{
state = alarmState;
alarmDay = 0;
newSecTime = millis();
}
else if (advanceMove == 1 && alarmMin >= 59) {alarmMin = 0;}
else if (advanceMove == -1 && alarmMin <= 0) {alarmMin = 59;}
else if (advanceMove != 0) {alarmMin = alarmMin + advanceMove;}
EEPROM.write(alarmMinAddress,alarmMin);
advanceMove = 0;
break;
case setClockHourState: // State 4
if (menuReleased == true) {state = setClockMinState;}
else if (advanceMove == 1 && now.hour() == 23)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), 0, now.minute(), now.second()));
advanceMove = 0;
}
else if (advanceMove == -1 && now.hour() == 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), 23, now.minute(), now.second()));
advanceMove = 0;
}
else if (advanceMove != 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), (now.hour() + advanceMove), now.minute(), now.second()));
advanceMove = 0;
}
break;
case setClockMinState: // State 5
if (menuReleased == true) {state = setClockSecState;}
else if (advanceMove == 1 && now.minute() == 59)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), 0, now.second()));
advanceMove = 0;
}
else if (advanceMove == -1 && now.minute() == 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), 59, now.second()));
advanceMove = 0;
}
else if (advanceMove != 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), (now.minute() + advanceMove), now.second()));
advanceMove = 0;
}
break;
case setClockSecState: // State 6
if (menuReleased == true) {state = clockState;}
else if (advanceMove == 1 && now.second() == 59)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), 0));
advanceMove = 0;
}
else if (advanceMove == -1 && now.second() == 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), 59));
advanceMove = 0;
}
else if (advanceMove != 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), (now.second() + advanceMove)));
advanceMove = 0;
}
break;
case countDownState: // State 7
if(menuReleased == true)
{
if (menuTimePressed <= holdTime)
{
if (countDown == true && countDownTime <= 0) {countDown = false; countDownTime = 0; currentCountDown = 0;}
else if (countDown == false && countDownTime > 0) {countDown = true; startCountDown = now.unixtime();}
else {state = demoState; demoIntro = 1; j = 0;}// if displaying the count down, menu button is pressed & released, then demo State is displayed
}
else {countDown = false; countDownTime = 0; currentCountDown = 0; j = 0;} // if displaying the clock, menu button is held & released, then the count down is reset
}
else if (advanceMove == -1 && currentCountDown <= 0)
{
countDown = false;
countDownTime = 0;
currentCountDown = 0;
demoIntro = 0;
}
else if (advanceMove == 1 && currentCountDown >= 3600)
{
countDown = false;
countDownTime = 3600;
}
else if (advanceMove != 0) //if displaying the count down, rotary encoder is turned then will change accordingley
{
countDown = false;
countDownTime = currentCountDown - currentCountDown%60 + advanceMove*60; // This rounds the count down minute up to the next minute
}
advanceMove = 0;
break;
case demoState: // State 8
if(menuReleased == true) {state = clockState; mode = EEPROM.read(modeAddress);} // if displaying the demo, menu button pressed then the clock will display and restore to the mode before demo started
break;
}
if (menuReleased || advanceMove !=0) {countTime = false;}
Serial.print("Mode is ");
Serial.println(mode);
Serial.print("State is ");
Serial.println(state);
}
void setAlarmDisplay()
{
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 100;
leds[i].g = 100;
leds[i].b = 100;
}
}
if (alarmSet == 0)
{
for (int i = 0; i < numLEDs; i++) // Sets background to red, to state that alarm IS NOT set
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 20;
leds[i].g = 0;
leds[i].b = 0;
}
}
}
else
{
for (int i = 0; i < numLEDs; i++) // Sets background to green, to state that alarm IS set
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 0;
leds[i].g = 20;
leds[i].b = 0;
}
}
}
if (alarmHour <= 11)
{
leds[(alarmHour*5+LEDOffset)%60].r = 255;
}
else
{
leds[((alarmHour - 12)*5+LEDOffset+59)%60].r = 25;
leds[((alarmHour - 12)*5+LEDOffset)%60].r = 255;
leds[((alarmHour - 12)*5+LEDOffset+1)%60].r = 25;
}
leds[(alarmMin+LEDOffset)%60].g = 100;
flashTime = millis();
if (state == setAlarmHourState && flashTime%300 >= 150)
{
leds[(((alarmHour%12)*5)+LEDOffset+59)%60].r = 0;
leds[(((alarmHour%12)*5)+LEDOffset)%60].r = 0;
leds[(((alarmHour%12)*5)+LEDOffset+1)%60].r = 0;
}
if (state == setAlarmMinState && flashTime%300 >= 150)
{
leds[(alarmMin+LEDOffset)%60].g = 0;
}
leds[(alarmMode+LEDOffset)%60].b = 255;
}
void setClockDisplay(DateTime now)
{
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 10;
leds[i].g = 10;
leds[i].b = 10;
}
}
if (now.hour() <= 11) {leds[(now.hour()*5+LEDOffset)%60].r = 255;}
else
{
leds[((now.hour() - 12)*5+LEDOffset+59)%60].r = 255;
leds[((now.hour() - 12)*5+LEDOffset)%60].r = 255;
leds[((now.hour() - 12)*5+LEDOffset+1)%60].r = 255;
}
flashTime = millis();
if (state == setClockHourState && flashTime%300 >= 150)
{
leds[(((now.hour()%12)*5)+LEDOffset+59)%60].r = 0;
leds[((now.hour()%12)*5+LEDOffset)%60].r = 0;
leds[(((now.hour()%12)*5)+LEDOffset+1)%60].r = 0;
}
if (state == setClockMinState && flashTime%300 >= 150) {leds[(now.minute()+LEDOffset)%60].g = 0;}
else {leds[(now.minute()+LEDOffset)%60].g = 255;}
if (state == setClockSecState && flashTime%300 >= 150) {leds[(now.second()+LEDOffset)%60].b = 0;}
else {leds[(now.second()+LEDOffset)%60].b = 255;}
}
// Check if alarm is active and if is it time for the alarm to trigger
void alarm(DateTime now)
{
if ((alarmMin == now.minute()%60) && (alarmHour == now.hour()%24)) //check if the time is the same to trigger alarm
{
alarmTrig = true;
alarmTrigTime = millis();
}
}
void alarmDisplay() // Displays the alarm
{
switch (alarmMode)
{
case 1:
// set all LEDs to a dim white
for (int i = 0; i < numLEDs; i++)
{
leds[i].r = 100;
leds[i].g = 100;
leds[i].b = 100;
}
break;
case 2:
LEDPosition = ((millis() - alarmTrigTime)/300);
reverseLEDPosition = 60 - LEDPosition;
if (LEDPosition >= 0 && LEDPosition <= 29)
{
for (int i = 0; i < LEDPosition; i++)
{
leds[(i+LEDOffset)%60].r = 5;
leds[(i+LEDOffset)%60].g = 5;
leds[(i+LEDOffset)%60].b = 5;
}
}
if (reverseLEDPosition <= 59 && reverseLEDPosition >= 31)
{
for (int i = 59; i > reverseLEDPosition; i--)
{
leds[(i+LEDOffset)%60].r = 5;
leds[(i+LEDOffset)%60].g = 5;
leds[(i+LEDOffset)%60].b = 5;
}
}
if (LEDPosition >= 30)
{
for (int i = 0; i < numLEDs; i++)
{
leds[(i+LEDOffset)%60].r = 5;
leds[(i+LEDOffset)%60].g = 5;
leds[(i+LEDOffset)%60].b = 5;
}
}
break;
case 3:
fadeTime = 60000;
brightFadeRad = (millis() - alarmTrigTime)/fadeTime; // Divided by the time period of the fade up.
if (millis() > alarmTrigTime + fadeTime) LEDBrightness = 255;
else LEDBrightness = 255.0*(1.0+sin((1.57*brightFadeRad)-1.57));
Serial.println(brightFadeRad);
Serial.println(LEDBrightness);
for (int i = 0; i < numLEDs; i++)
{
leds[i].r = LEDBrightness;
leds[i].g = LEDBrightness;
leds[i].b = LEDBrightness;
}
break;
// Currently not working
// case 4:
// fadeTime = 60000;
// brightFadeRad = (millis() - alarmTrigTime)/fadeTime; // Divided by the time period of the fade up.
// LEDPosition = ((millis() - alarmTrigTime)/(fadeTime/30));
//// if (millis() > alarmTrigTime + fadeTime) LEDBrightness = 255; // If the fade time is complete, then the LED brightness will be set to full.
// if (brightFadeRad <= 0) LEDBrightness = 0;
// else if (brightFadeRad >= 0) LEDBrightness = 1;
// else LEDBrightness = 255.0*(1.0+sin((1.57*brightFadeRad)-1.57));
//
//// Serial.println(brightFadeRad);
//// Serial.println(LEDBrightness);
// reverseLEDPosition = 60 - LEDPosition;
// if (LEDPosition >= 0 && LEDPosition <= 29)
// {
// for (int i = 0; i < LEDPosition; i++)
// {
// leds[i].r = LEDBrightness;
// leds[i].g = LEDBrightness;
// leds[i].b = LEDBrightness;
// }
// }
// if (reverseLEDPosition <= 59 && reverseLEDPosition >= 31)
// {
// for (int i = 59; i > reverseLEDPosition; i--)
// {
// leds[i].r = LEDBrightness;
// leds[i].g = LEDBrightness;
// leds[i].b = LEDBrightness;
// }
// }
// if (LEDPosition >= 30)
// {
// for (int i = 0; i < numLEDs; i++)
// {
// leds[i].r = LEDBrightness;
// leds[i].g = LEDBrightness;
// leds[i].b = LEDBrightness;
// }
// }
// break;
}
}
//
void countDownDisplay(DateTime now)
{
flashTime = millis();
if (countDown == true)
{
currentCountDown = countDownTime + startCountDown - now.unixtime();
if (currentCountDown > 0)
{
countDownMin = currentCountDown / 60;
countDownSec = currentCountDown%60 * 4; // have multiplied by 4 to create brightness
for (int i = 0; i < countDownMin; i++) {leds[(i+LEDOffset+1)%60].b = 240;} // Set a blue LED for each complete minute that is remaining
leds[(countDownMin+LEDOffset+1)%60].b = countDownSec; // Display the remaining secconds of the current minute as its brightness
}
else
{
countDownFlash = now.unixtime()%2;
if (countDownFlash == 0)
{
for (int i = 0; i < numLEDs; i++) // Set the background as all off
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}
else
{
for (int i = 0; i < numLEDs; i++) // Set the background as all blue
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 255;
}
}
}
}
else
{
currentCountDown = countDownTime;
if (countDownTime == 0)
{
currentMillis = millis();
clearLEDs();
switch (demoIntro)
{
case 0:
for (int i = 0; i < j; i++) {leds[(i+LEDOffset+1)%60].b = 20;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {demoIntro = 1;}
break;
case 1:
for (int i = 0; i < j; i++) {leds[(i+LEDOffset+1)%60].b = 20;}
if (currentMillis - previousMillis > timeInterval) {j--; previousMillis = currentMillis;}
if (j < 0) {demoIntro = 0;}
break;
}
}
else if (countDownTime > 0 && flashTime%300 >= 150)
{
countDownMin = currentCountDown / 60; //
for (int i = 0; i < countDownMin; i++) {leds[(i+LEDOffset+1)%60].b = 255;} // Set a blue LED for each complete minute that is remaining
}
}
}
void runDemo(DateTime now)
{
currentDemoTime = now.unixtime();
currentMillis = millis();
clearLEDs();
switch (demoIntro)
{
case 0:
timeDisplay(now);
if (currentDemoTime - previousDemoTime > demoTime) {previousDemoTime = currentDemoTime; mode++;}
break;
case 1:
for (int i = 0; i < j; i++) {leds[i].r = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 2:
for (int i = j; i < numLEDs; i++) {leds[i].r = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 3:
for (int i = 0; i < j; i++) {leds[i].g = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 4:
for (int i = j; i < numLEDs; i++) {leds[i].g = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 5:
for (int i = 0; i < j; i++) {leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 6:
for (int i = j; i < numLEDs; i++) {leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 7:
for (int i = 0; i < j; i++) {leds[i].r = 255; leds[i].g = 255; leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 8:
for (int i = j; i < numLEDs; i++) {leds[i].r = 255; leds[i].g = 255; leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs)
{
demoIntro = 0;
mode = 0;
Serial.print("Mode is ");
Serial.println(mode);
Serial.print("State is ");
Serial.println(state);
}
break;
}
}
void clearLEDs()
{
for (int i = 0; i < numLEDs; i++) // Set all the LEDs to off
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}
void timeDisplay(DateTime now)
{
switch (mode)
{
case 0:
minimalClock(now);
break;
case 1:
basicClock(now);
break;
case 2:
smoothSecond(now);
break;
case 3:
outlineClock(now);
break;
case 4:
minimalMilliSec(now);
break;
case 5:
simplePendulum(now);
break;
case 6:
breathingClock(now);
break;
default: // Keep this here and add more timeDisplay modes as defined cases.
{
mode = 0;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////
// CLOCK DISPLAY MODES
// Add any new display mode functions here. Then add to the "void timeDisplay(DateTime now)" function.
// Add each of the new display mode functions as a new "case", leaving default last.
////////////////////////////////////////////////////////////////////////////////////////////
//
void minimalClock(DateTime now)
{
unsigned char hourPos = (now.hour()%12)*5;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
//
void basicClock(DateTime now)
{
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset+59)%60].g = 0;
leds[(hourPos+LEDOffset+59)%60].b = 0;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset)%60].g = 0;
leds[(hourPos+LEDOffset)%60].b = 0;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].g = 0;
leds[(hourPos+LEDOffset+1)%60].b = 0;
leds[(now.minute()+LEDOffset)%60].r = 0;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.minute()+LEDOffset)%60].b = 0;
leds[(now.second()+LEDOffset)%60].r = 0;
leds[(now.second()+LEDOffset)%60].g = 0;
leds[(now.second()+LEDOffset)%60].b = 255;
}
//
void smoothSecond(DateTime now)
{
if (now.second()!=old.second())
{
old = now;
cyclesPerSec = millis() - newSecTime;
cyclesPerSecFloat = (float) cyclesPerSec;
newSecTime = millis();
}
// set hour, min & sec LEDs
fracOfSec = (millis() - newSecTime)/cyclesPerSecFloat; // This divides by 733, but should be 1000 and not sure why???
if (subSeconds < cyclesPerSec) {secondBrightness = 50.0*(1.0+sin((3.14*fracOfSec)-1.57));}
if (subSeconds < cyclesPerSec) {secondBrightness2 = 50.0*(1.0+sin((3.14*fracOfSec)+1.57));}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
// The colours are set last, so if on same LED mixed colours are created
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = secondBrightness;
leds[(now.second()+LEDOffset+59)%60].b = secondBrightness2;
}
//
void outlineClock(DateTime now)
{
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 100;
leds[i].g = 100;
leds[i].b = 100;
}
}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
//
void minimalMilliSec(DateTime now)
{
if (now.second()!=old.second())
{
old = now;
cyclesPerSec = (millis() - newSecTime);
newSecTime = millis();
}
// set hour, min & sec LEDs
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
subSeconds = (((millis() - newSecTime)*60)/cyclesPerSec)%60; // This divides by 733, but should be 1000 and not sure why???
// Millisec lights are set first, so hour/min/sec lights override and don't flicker as millisec passes
leds[(subSeconds+LEDOffset)%60].r = 50;
leds[(subSeconds+LEDOffset)%60].g = 50;
leds[(subSeconds+LEDOffset)%60].b = 50;
// The colours are set last, so if on same LED mixed colours are created
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
// Pendulum will be at the bottom and left for one second and right for one second
void simplePendulum(DateTime now)
{
if (now.second()!=old.second())
{
old = now;
cyclesPerSec = millis() - newSecTime;
cyclesPerSecFloat = (float) cyclesPerSec;
newSecTime = millis();
if (swingBack == true) {swingBack = false;}
else {swingBack = true;}
}
// set hour, min & sec LEDs
fracOfSec = (millis() - newSecTime)/cyclesPerSecFloat; // This divides by 733, but should be 1000 and not sure why???
if (subSeconds < cyclesPerSec && swingBack == true) {pendulumPos = 27.0 + 3.4*(1.0+sin((3.14*fracOfSec)-1.57));}
if (subSeconds < cyclesPerSec && swingBack == false) {pendulumPos = 27.0 + 3.4*(1.0+sin((3.14*fracOfSec)+1.57));}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
// Pendulum lights are set first, so hour/min/sec lights override and don't flicker as millisec passes
leds[(pendulumPos + LEDOffset)%60].r = 100;
leds[(pendulumPos + LEDOffset)%60].g = 100;
leds[(pendulumPos + LEDOffset)%60].b = 100;
// The colours are set last, so if on same LED mixed colours are created
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
void breathingClock(DateTime now)
{
if (alarmTrig == false)
{
breathBrightness = 15.0*(1.0+sin((3.14*millis()/2000.0)-1.57));
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = breathBrightness + 5;
leds[i].g = breathBrightness + 5;
leds[i].b = breathBrightness + 5;
}
else
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}
}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
/*
// Cycle through the color wheel, equally spaced around the belt
void rainbowCycle(uint8_t wait)
{
uint16_t i, j;
for (j=0; j < 384 * 5; j++)
{ // 5 cycles of all 384 colors in the wheel
for (i=0; i < numLEDs; i++)
{
// tricky math! we use each pixel as a fraction of the full 384-color
// wheel (thats the i / strip.numPixels() part)
// Then add in j which makes the colors go around per pixel
// the % 384 is to make the wheel cycle around
strip.setPixelColor(i, Wheel(((i * 384 / numLEDs) + j) % 384));
}
delay(wait);
}
}
//Input a value 0 to 384 to get a color value.
//The colours are a transition r - g - b - back to r
uint32_t Wheel(uint16_t WheelPos)
{
byte r, g, b;
switch(WheelPos / 128)
{
case 0:
r = 127 - WheelPos % 128; // red down
g = WheelPos % 128; // green up
b = 0; // blue off
break;
case 1:
g = 127 - WheelPos % 128; // green down
b = WheelPos % 128; // blue up
r = 0; // red off
break;
case 2:
b = 127 - WheelPos % 128; // blue down
r = WheelPos % 128; // red up
g = 0; // green off
...
This file has been truncated, please download it to see its full contents.
Clock_with_rtc3231.ino
C/C++// The foundations of this code is based on the same document made available by Arduino.cc under the Creative Commons Sharealike license. This derivative document is licensed under the Creative Commons Sharealike license. 3.0 C++
// Add options for background settings
// TO DO: Clean up and comment code...
// BUG: demo state should start as mode 0 after intro
// NICE TO HAVE: When alarm is cancelled, the alarm still remains set for next day.
//Add the following libraries to the respective folder for you operating system. See http://arduino.cc/en/Guide/Environment
#include <FastLED.h> // FastSPI Library from http://code.google.com/p/fastspi/
#include <Wire.h> //This is to communicate via I2C. On arduino Uno & Nano use pins A4 for SDA (yellow/orange) and A5 for SCL (green). For other boards ee http://arduino.cc/en/Reference/Wire
#include <RTClib.h> // Include the RTClib library to enable communication with the real time clock.
#include <EEPROM.h> // Include the EEPROM library to enable the storing and retrevel of settings.
#include <Bounce.h> // Include the Bounce library for de-bouncing issues with push buttons.
#include <Encoder.h> // Include the Encoder library to read the out puts of the rotary encoders
RTC_DS3231 RTC; // Establishes the chipset of the Real Time Clock
#define LEDStripPin 6 // Pin used for the data to the LED strip
#define menuPin 0 // Pin used for the menu button (green stripe)
#define numLEDs 60 // Number of LEDs in strip
// Setting up the LED strip
struct CRGB leds[numLEDs];
Encoder rotary1(3, 4); // Setting up the Rotary Encoder
DateTime old; // Variable to compare new and old time, to see if it has moved on.
int rotary1Pos = 0;
int subSeconds; // 60th's of a second
int secondBrightness;
int secondBrightness2;
int breathBrightness;
long newSecTime; // Variable to record when a new second starts, allowing to create milli seconds
long oldSecTime;
long flashTime; //
long breathCycleTime;
#define holdTime 1500
int cyclesPerSec;
float cyclesPerSecFloat; // So can be used as a float in calcs
float fracOfSec;
float breathFracOfSec;
boolean demo;
#define demoTime 12 // seconds
long previousDemoTime;
long currentDemoTime;
boolean swingBack = false;
int timeHour;
int timeMin;
int timeSec;
int alarmMin; // The minute of the alarm
int alarmHour; // The hour of the alarm 0-23
int alarmDay = 0; // The day of the alarm
boolean alarmSet; // Whether the alarm is set or not
int modeAddress = 0; // Address of where mode is stored in the EEPROM
int alarmMinAddress = 1; // Address of where alarm minute is stored in the EEPROM
int alarmHourAddress = 2; // Address of where alarm hour is stored in the EEPROM
int alarmSetAddress = 3; // Address of where alarm state is stored in the EEPROM
int alarmModeAddress = 4; // Address of where the alarm mode is stored in the EEPROM
boolean alarmTrig = false; // Whether the alarm has been triggered or not
long alarmTrigTime; // Milli seconds since the alarm was triggered
boolean countDown = false;
long countDownTime = 0;
long currentCountDown = 0;
long startCountDown;
int countDownMin;
int countDownSec;
int countDownFlash;
int demoIntro = 0;
int j = 0;
long timeInterval = 5;
long currentMillis;
long previousMillis = 0;
float LEDBrightness = 0;
float fadeTime;
float brightFadeRad;
int state = 0; // Variable of the state of the clock, with the following defined states
#define clockState 0
#define alarmState 1
#define setAlarmHourState 2
#define setAlarmMinState 3
#define setClockHourState 4
#define setClockMinState 5
#define setClockSecState 6
#define countDownState 7
#define demoState 8
int mode; // Variable of the display mode of the clock
int modeMax = 6; // Change this when new modes are added. This is so selecting modes can go back beyond.
int alarmMode; // Variable of the alarm display mode
int alarmModeMax = 3;
Bounce menuBouncer = Bounce(menuPin,20); // Instantiate a Bounce object with a 50 millisecond debounce time for the menu button
boolean menuButton = false;
boolean menuPressed = false;
boolean menuReleased = false;
int advanceMove = 0;
boolean countTime = false;
long menuTimePressed;
long lastRotary;
int rotaryTime = 1000;
int LEDPosition;
int reverseLEDPosition;
int pendulumPos;
int fiveMins;
int odd;
int LEDOffset = 30;
void setup()
{
// Set up all pins
pinMode(menuPin, INPUT_PULLUP); // Uses the internal 20k pull up resistor. Pre Arduino_v.1.0.1 need to be "digitalWrite(menuPin,HIGH);pinMode(menuPin,INPUT);"
// Start LEDs
LEDS.addLeds<WS2811, LEDStripPin, GRB>(leds, numLEDs); // Structure of the LED data. I have changed to from rgb to grb, as using an alternative LED strip. Test & change these if you're getting different colours.
// Start RTC
Wire.begin(); // Starts the Wire library allows I2C communication to the Real Time Clock
RTC.begin(); // Starts communications to the RTC
Serial.begin(9600); // Starts the serial communications
// Uncomment to reset all the EEPROM addresses. You will have to comment again and reload, otherwise it will not save anything each time power is cycled
// write a 0 to all 512 bytes of the EEPROM
// for (int i = 0; i < 512; i++)
// {EEPROM.write(i, 0);}
// Load any saved setting since power off, such as mode & alarm time
mode = EEPROM.read(modeAddress); // The mode will be stored in the address "0" of the EEPROM
alarmMin = EEPROM.read(alarmMinAddress); // The mode will be stored in the address "1" of the EEPROM
alarmHour = EEPROM.read(alarmHourAddress); // The mode will be stored in the address "2" of the EEPROM
alarmSet = EEPROM.read(alarmSetAddress); // The mode will be stored in the address "2" of the EEPROM
alarmMode = EEPROM.read(alarmModeAddress);
// Prints all the saved EEPROM data to Serial
Serial.print("Mode is ");Serial.println(mode);
Serial.print("Alarm Hour is ");Serial.println(alarmHour);
Serial.print("Alarm Min is ");Serial.println(alarmMin);
Serial.print("Alarm is set ");Serial.println(alarmSet);
Serial.print("Alarm Mode is ");Serial.println(alarmMode);
// create a loop that calcuated the number of counted milliseconds between each second.
DateTime now = RTC.now();
// startTime = millis();
// while (RTC.old() = RTC.new())
// if (now.month() == 1 && now.day() == 1 && now.hour() == 0 && now.minute() == 0 && now.minute() == 0)
// {}
Serial.print("Hour time is... ");
Serial.println(now.hour());
Serial.print("Min time is... ");
Serial.println(now.minute());
Serial.print("Sec time is... ");
Serial.println(now.second());
Serial.print("Year is... ");
Serial.println(now.year());
Serial.print("Month is... ");
Serial.println(now.month());
Serial.print("Day is... ");
Serial.println(now.day());
}
void loop()
{
DateTime now = RTC.now(); // Fetches the time from RTC
// Check for any button presses and action accordingley
menuButton = menuBouncer.update(); // Update the debouncer for the menu button and saves state to menuButton
rotary1Pos = rotary1.read(); // Checks the rotary position
if (rotary1Pos <= -2 && lastRotary - millis() >= rotaryTime)
{
advanceMove = -1;
rotary1.write(0);
lastRotary = millis();
}
if (rotary1Pos >= 2 && lastRotary - millis() >= rotaryTime)
{
advanceMove = 1;
rotary1.write(0);
lastRotary = millis();
}
if (menuButton == true || advanceMove != 0 || countTime == true) {buttonCheck(menuBouncer,now);}
// clear LED array
memset(leds, 0, numLEDs * 3);
// Check alarm and trigger if the time matches
if (alarmSet == true && alarmDay != now.day()) // The alarmDay statement ensures it is a newly set alarm or repeat from previous day, not within the minute of an alarm cancel.
{
if (alarmTrig == false) {alarm(now);}
else {alarmDisplay();}
}
// Check the Countdown Timer
if (countDown == true)
{
currentCountDown = countDownTime + startCountDown - now.unixtime();
if ( currentCountDown <= 0)
{
state =countDownState;
}
}
// Set the time LED's
if (state == setClockHourState || state == setClockMinState || state == setClockSecState) {setClockDisplay(now);}
else if (state == alarmState || state == setAlarmHourState || state == setAlarmMinState) {setAlarmDisplay();}
else if (state == countDownState) {countDownDisplay(now);}
else if (state == demoState) {runDemo(now);}
else {timeDisplay(now);}
// Update LEDs
LEDS.show();
}
void buttonCheck(Bounce menuBouncer, DateTime now)
{
if (menuBouncer.fallingEdge()) // Checks if a button is pressed, if so sets countTime to true
{
countTime = true;
Serial.println("rising edge");
}
if (menuBouncer.risingEdge()) // Checks if a button is released,
{
countTime = false;
Serial.println("rising edge");
} // if so sets countTime to false. Now the ...TimePressed will not be updated when enters the buttonCheck,
if (countTime) // otherwise will menuBouncer.duration will
{
menuTimePressed = menuBouncer.duration();
if (menuTimePressed >= (holdTime - 100) && menuTimePressed <= holdTime)
{
clearLEDs();
LEDS.show();
delay(100);
}
}
menuReleased = menuBouncer.risingEdge();
if (menuPressed == true) {Serial.println("Menu Button Pressed");}
if (menuReleased == true) {Serial.println("Menu Button Released");}
Serial.print("Menu Bounce Duration ");
Serial.println(menuTimePressed);
if (alarmTrig == true)
{
alarmTrig = false;
alarmDay = now.day(); // When the alarm is cancelled it will not display until next day. As without it, it would start again if within a minute, or completely turn off the alarm.
delay(300); // I added this 300ms delay, so there is time for the button to be released
return; // This return exits the buttonCheck function, so no actions are performs
}
switch (state)
{
case clockState: // State 0
if (advanceMove == -1 && mode == 0)
{
mode = modeMax;
advanceMove = 0;
}
else if(advanceMove != 0) //if displaying the clock, advance button is pressed & released, then mode will change
{
mode = mode + advanceMove;
EEPROM.write(modeAddress,mode);
advanceMove = 0;
}
else if(menuReleased == true)
{
if (menuTimePressed <= holdTime) {state = alarmState; newSecTime = millis();}// if displaying the clock, menu button is pressed & released, then Alarm is displayed
else {state = setClockHourState;} // if displaying the clock, menu button is held & released, then clock hour can be set
}
break;
case alarmState: // State 1
if (advanceMove == -1 && alarmMode <= 0)
{
alarmMode = alarmModeMax;
alarmSet = 1;
}
else if (advanceMove == 1 && alarmMode >= alarmModeMax)
{
alarmMode = 0;
alarmSet = 0;
}
else if (advanceMove != 0)
{
alarmMode = alarmMode + advanceMove;
if (alarmMode == 0) {alarmSet = 0;}
else {alarmSet = 1;}
}
Serial.print("alarmState is ");
Serial.println(alarmState);
Serial.print("alarmMode is ");
Serial.println(alarmMode);
EEPROM.write(alarmSetAddress,alarmSet);
EEPROM.write(alarmModeAddress,alarmMode);
advanceMove = 0;
alarmTrig = false;
if (menuReleased == true)
{
if (menuTimePressed <= holdTime) {state = countDownState; j = 0;}// if displaying the alarm time, menu button is pressed & released, then clock is displayed
else {state = setAlarmHourState;} // if displaying the alarm time, menu button is held & released, then alarm hour can be set
}
break;
case setAlarmHourState: // State 2
if (menuReleased == true) {state = setAlarmMinState;}
else if (advanceMove == 1 && alarmHour >= 23) {alarmHour = 0;}
else if (advanceMove == -1 && alarmHour <= 0) {alarmHour = 23;}
else if (advanceMove != 0) {alarmHour = alarmHour + advanceMove;}
EEPROM.write(alarmHourAddress,alarmHour);
advanceMove = 0;
break;
case setAlarmMinState: // State 3
if (menuReleased == true)
{
state = alarmState;
alarmDay = 0;
newSecTime = millis();
}
else if (advanceMove == 1 && alarmMin >= 59) {alarmMin = 0;}
else if (advanceMove == -1 && alarmMin <= 0) {alarmMin = 59;}
else if (advanceMove != 0) {alarmMin = alarmMin + advanceMove;}
EEPROM.write(alarmMinAddress,alarmMin);
advanceMove = 0;
break;
case setClockHourState: // State 4
if (menuReleased == true) {state = setClockMinState;}
else if (advanceMove == 1 && now.hour() == 23)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), 0, now.minute(), now.second()));
advanceMove = 0;
}
else if (advanceMove == -1 && now.hour() == 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), 23, now.minute(), now.second()));
advanceMove = 0;
}
else if (advanceMove != 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), (now.hour() + advanceMove), now.minute(), now.second()));
advanceMove = 0;
}
break;
case setClockMinState: // State 5
if (menuReleased == true) {state = setClockSecState;}
else if (advanceMove == 1 && now.minute() == 59)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), 0, now.second()));
advanceMove = 0;
}
else if (advanceMove == -1 && now.minute() == 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), 59, now.second()));
advanceMove = 0;
}
else if (advanceMove != 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), (now.minute() + advanceMove), now.second()));
advanceMove = 0;
}
break;
case setClockSecState: // State 6
if (menuReleased == true) {state = clockState;}
else if (advanceMove == 1 && now.second() == 59)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), 0));
advanceMove = 0;
}
else if (advanceMove == -1 && now.second() == 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), 59));
advanceMove = 0;
}
else if (advanceMove != 0)
{
RTC.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), (now.second() + advanceMove)));
advanceMove = 0;
}
break;
case countDownState: // State 7
if(menuReleased == true)
{
if (menuTimePressed <= holdTime)
{
if (countDown == true && countDownTime <= 0) {countDown = false; countDownTime = 0; currentCountDown = 0;}
else if (countDown == false && countDownTime > 0) {countDown = true; startCountDown = now.unixtime();}
else {state = demoState; demoIntro = 1; j = 0;}// if displaying the count down, menu button is pressed & released, then demo State is displayed
}
else {countDown = false; countDownTime = 0; currentCountDown = 0; j = 0;} // if displaying the clock, menu button is held & released, then the count down is reset
}
else if (advanceMove == -1 && currentCountDown <= 0)
{
countDown = false;
countDownTime = 0;
currentCountDown = 0;
demoIntro = 0;
}
else if (advanceMove == 1 && currentCountDown >= 3600)
{
countDown = false;
countDownTime = 3600;
}
else if (advanceMove != 0) //if displaying the count down, rotary encoder is turned then will change accordingley
{
countDown = false;
countDownTime = currentCountDown - currentCountDown%60 + advanceMove*60; // This rounds the count down minute up to the next minute
}
advanceMove = 0;
break;
case demoState: // State 8
if(menuReleased == true) {state = clockState; mode = EEPROM.read(modeAddress);} // if displaying the demo, menu button pressed then the clock will display and restore to the mode before demo started
break;
}
if (menuReleased || advanceMove !=0) {countTime = false;}
Serial.print("Mode is ");
Serial.println(mode);
Serial.print("State is ");
Serial.println(state);
}
void setAlarmDisplay()
{
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 100;
leds[i].g = 100;
leds[i].b = 100;
}
}
if (alarmSet == 0)
{
for (int i = 0; i < numLEDs; i++) // Sets background to red, to state that alarm IS NOT set
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 20;
leds[i].g = 0;
leds[i].b = 0;
}
}
}
else
{
for (int i = 0; i < numLEDs; i++) // Sets background to green, to state that alarm IS set
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 0;
leds[i].g = 20;
leds[i].b = 0;
}
}
}
if (alarmHour <= 11)
{
leds[(alarmHour*5+LEDOffset)%60].r = 255;
}
else
{
leds[((alarmHour - 12)*5+LEDOffset+59)%60].r = 25;
leds[((alarmHour - 12)*5+LEDOffset)%60].r = 255;
leds[((alarmHour - 12)*5+LEDOffset+1)%60].r = 25;
}
leds[(alarmMin+LEDOffset)%60].g = 100;
flashTime = millis();
if (state == setAlarmHourState && flashTime%300 >= 150)
{
leds[(((alarmHour%12)*5)+LEDOffset+59)%60].r = 0;
leds[(((alarmHour%12)*5)+LEDOffset)%60].r = 0;
leds[(((alarmHour%12)*5)+LEDOffset+1)%60].r = 0;
}
if (state == setAlarmMinState && flashTime%300 >= 150)
{
leds[(alarmMin+LEDOffset)%60].g = 0;
}
leds[(alarmMode+LEDOffset)%60].b = 255;
}
void setClockDisplay(DateTime now)
{
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 10;
leds[i].g = 10;
leds[i].b = 10;
}
}
if (now.hour() <= 11) {leds[(now.hour()*5+LEDOffset)%60].r = 255;}
else
{
leds[((now.hour() - 12)*5+LEDOffset+59)%60].r = 255;
leds[((now.hour() - 12)*5+LEDOffset)%60].r = 255;
leds[((now.hour() - 12)*5+LEDOffset+1)%60].r = 255;
}
flashTime = millis();
if (state == setClockHourState && flashTime%300 >= 150)
{
leds[(((now.hour()%12)*5)+LEDOffset+59)%60].r = 0;
leds[((now.hour()%12)*5+LEDOffset)%60].r = 0;
leds[(((now.hour()%12)*5)+LEDOffset+1)%60].r = 0;
}
if (state == setClockMinState && flashTime%300 >= 150) {leds[(now.minute()+LEDOffset)%60].g = 0;}
else {leds[(now.minute()+LEDOffset)%60].g = 255;}
if (state == setClockSecState && flashTime%300 >= 150) {leds[(now.second()+LEDOffset)%60].b = 0;}
else {leds[(now.second()+LEDOffset)%60].b = 255;}
}
// Check if alarm is active and if is it time for the alarm to trigger
void alarm(DateTime now)
{
if ((alarmMin == now.minute()%60) && (alarmHour == now.hour()%24)) //check if the time is the same to trigger alarm
{
alarmTrig = true;
alarmTrigTime = millis();
}
}
void alarmDisplay() // Displays the alarm
{
switch (alarmMode)
{
case 1:
// set all LEDs to a dim white
for (int i = 0; i < numLEDs; i++)
{
leds[i].r = 100;
leds[i].g = 100;
leds[i].b = 100;
}
break;
case 2:
LEDPosition = ((millis() - alarmTrigTime)/300);
reverseLEDPosition = 60 - LEDPosition;
if (LEDPosition >= 0 && LEDPosition <= 29)
{
for (int i = 0; i < LEDPosition; i++)
{
leds[(i+LEDOffset)%60].r = 5;
leds[(i+LEDOffset)%60].g = 5;
leds[(i+LEDOffset)%60].b = 5;
}
}
if (reverseLEDPosition <= 59 && reverseLEDPosition >= 31)
{
for (int i = 59; i > reverseLEDPosition; i--)
{
leds[(i+LEDOffset)%60].r = 5;
leds[(i+LEDOffset)%60].g = 5;
leds[(i+LEDOffset)%60].b = 5;
}
}
if (LEDPosition >= 30)
{
for (int i = 0; i < numLEDs; i++)
{
leds[(i+LEDOffset)%60].r = 5;
leds[(i+LEDOffset)%60].g = 5;
leds[(i+LEDOffset)%60].b = 5;
}
}
break;
case 3:
fadeTime = 60000;
brightFadeRad = (millis() - alarmTrigTime)/fadeTime; // Divided by the time period of the fade up.
if (millis() > alarmTrigTime + fadeTime) LEDBrightness = 255;
else LEDBrightness = 255.0*(1.0+sin((1.57*brightFadeRad)-1.57));
Serial.println(brightFadeRad);
Serial.println(LEDBrightness);
for (int i = 0; i < numLEDs; i++)
{
leds[i].r = LEDBrightness;
leds[i].g = LEDBrightness;
leds[i].b = LEDBrightness;
}
break;
// Currently not working
// case 4:
// fadeTime = 60000;
// brightFadeRad = (millis() - alarmTrigTime)/fadeTime; // Divided by the time period of the fade up.
// LEDPosition = ((millis() - alarmTrigTime)/(fadeTime/30));
//// if (millis() > alarmTrigTime + fadeTime) LEDBrightness = 255; // If the fade time is complete, then the LED brightness will be set to full.
// if (brightFadeRad <= 0) LEDBrightness = 0;
// else if (brightFadeRad >= 0) LEDBrightness = 1;
// else LEDBrightness = 255.0*(1.0+sin((1.57*brightFadeRad)-1.57));
//
//// Serial.println(brightFadeRad);
//// Serial.println(LEDBrightness);
// reverseLEDPosition = 60 - LEDPosition;
// if (LEDPosition >= 0 && LEDPosition <= 29)
// {
// for (int i = 0; i < LEDPosition; i++)
// {
// leds[i].r = LEDBrightness;
// leds[i].g = LEDBrightness;
// leds[i].b = LEDBrightness;
// }
// }
// if (reverseLEDPosition <= 59 && reverseLEDPosition >= 31)
// {
// for (int i = 59; i > reverseLEDPosition; i--)
// {
// leds[i].r = LEDBrightness;
// leds[i].g = LEDBrightness;
// leds[i].b = LEDBrightness;
// }
// }
// if (LEDPosition >= 30)
// {
// for (int i = 0; i < numLEDs; i++)
// {
// leds[i].r = LEDBrightness;
// leds[i].g = LEDBrightness;
// leds[i].b = LEDBrightness;
// }
// }
// break;
}
}
//
void countDownDisplay(DateTime now)
{
flashTime = millis();
if (countDown == true)
{
currentCountDown = countDownTime + startCountDown - now.unixtime();
if (currentCountDown > 0)
{
countDownMin = currentCountDown / 60;
countDownSec = currentCountDown%60 * 4; // have multiplied by 4 to create brightness
for (int i = 0; i < countDownMin; i++) {leds[(i+LEDOffset+1)%60].b = 240;} // Set a blue LED for each complete minute that is remaining
leds[(countDownMin+LEDOffset+1)%60].b = countDownSec; // Display the remaining secconds of the current minute as its brightness
}
else
{
countDownFlash = now.unixtime()%2;
if (countDownFlash == 0)
{
for (int i = 0; i < numLEDs; i++) // Set the background as all off
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}
else
{
for (int i = 0; i < numLEDs; i++) // Set the background as all blue
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 255;
}
}
}
}
else
{
currentCountDown = countDownTime;
if (countDownTime == 0)
{
currentMillis = millis();
clearLEDs();
switch (demoIntro)
{
case 0:
for (int i = 0; i < j; i++) {leds[(i+LEDOffset+1)%60].b = 20;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {demoIntro = 1;}
break;
case 1:
for (int i = 0; i < j; i++) {leds[(i+LEDOffset+1)%60].b = 20;}
if (currentMillis - previousMillis > timeInterval) {j--; previousMillis = currentMillis;}
if (j < 0) {demoIntro = 0;}
break;
}
}
else if (countDownTime > 0 && flashTime%300 >= 150)
{
countDownMin = currentCountDown / 60; //
for (int i = 0; i < countDownMin; i++) {leds[(i+LEDOffset+1)%60].b = 255;} // Set a blue LED for each complete minute that is remaining
}
}
}
void runDemo(DateTime now)
{
currentDemoTime = now.unixtime();
currentMillis = millis();
clearLEDs();
switch (demoIntro)
{
case 0:
timeDisplay(now);
if (currentDemoTime - previousDemoTime > demoTime) {previousDemoTime = currentDemoTime; mode++;}
break;
case 1:
for (int i = 0; i < j; i++) {leds[i].r = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 2:
for (int i = j; i < numLEDs; i++) {leds[i].r = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 3:
for (int i = 0; i < j; i++) {leds[i].g = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 4:
for (int i = j; i < numLEDs; i++) {leds[i].g = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 5:
for (int i = 0; i < j; i++) {leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 6:
for (int i = j; i < numLEDs; i++) {leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 7:
for (int i = 0; i < j; i++) {leds[i].r = 255; leds[i].g = 255; leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs) {j = 0; demoIntro++;}
break;
case 8:
for (int i = j; i < numLEDs; i++) {leds[i].r = 255; leds[i].g = 255; leds[i].b = 255;}
if (currentMillis - previousMillis > timeInterval) {j++; previousMillis = currentMillis;}
if (j == numLEDs)
{
demoIntro = 0;
mode = 0;
Serial.print("Mode is ");
Serial.println(mode);
Serial.print("State is ");
Serial.println(state);
}
break;
}
}
void clearLEDs()
{
for (int i = 0; i < numLEDs; i++) // Set all the LEDs to off
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}
void timeDisplay(DateTime now)
{
switch (mode)
{
case 0:
minimalClock(now);
break;
case 1:
basicClock(now);
break;
case 2:
smoothSecond(now);
break;
case 3:
outlineClock(now);
break;
case 4:
minimalMilliSec(now);
break;
case 5:
simplePendulum(now);
break;
case 6:
breathingClock(now);
break;
default: // Keep this here and add more timeDisplay modes as defined cases.
{
mode = 0;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////
// CLOCK DISPLAY MODES
// Add any new display mode functions here. Then add to the "void timeDisplay(DateTime now)" function.
// Add each of the new display mode functions as a new "case", leaving default last.
////////////////////////////////////////////////////////////////////////////////////////////
//
void minimalClock(DateTime now)
{
unsigned char hourPos = (now.hour()%12)*5;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
//
void basicClock(DateTime now)
{
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset+59)%60].g = 0;
leds[(hourPos+LEDOffset+59)%60].b = 0;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset)%60].g = 0;
leds[(hourPos+LEDOffset)%60].b = 0;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].g = 0;
leds[(hourPos+LEDOffset+1)%60].b = 0;
leds[(now.minute()+LEDOffset)%60].r = 0;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.minute()+LEDOffset)%60].b = 0;
leds[(now.second()+LEDOffset)%60].r = 0;
leds[(now.second()+LEDOffset)%60].g = 0;
leds[(now.second()+LEDOffset)%60].b = 255;
}
//
void smoothSecond(DateTime now)
{
if (now.second()!=old.second())
{
old = now;
cyclesPerSec = millis() - newSecTime;
cyclesPerSecFloat = (float) cyclesPerSec;
newSecTime = millis();
}
// set hour, min & sec LEDs
fracOfSec = (millis() - newSecTime)/cyclesPerSecFloat; // This divides by 733, but should be 1000 and not sure why???
if (subSeconds < cyclesPerSec) {secondBrightness = 50.0*(1.0+sin((3.14*fracOfSec)-1.57));}
if (subSeconds < cyclesPerSec) {secondBrightness2 = 50.0*(1.0+sin((3.14*fracOfSec)+1.57));}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
// The colours are set last, so if on same LED mixed colours are created
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = secondBrightness;
leds[(now.second()+LEDOffset+59)%60].b = secondBrightness2;
}
//
void outlineClock(DateTime now)
{
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = 100;
leds[i].g = 100;
leds[i].b = 100;
}
}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
//
void minimalMilliSec(DateTime now)
{
if (now.second()!=old.second())
{
old = now;
cyclesPerSec = (millis() - newSecTime);
newSecTime = millis();
}
// set hour, min & sec LEDs
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
subSeconds = (((millis() - newSecTime)*60)/cyclesPerSec)%60; // This divides by 733, but should be 1000 and not sure why???
// Millisec lights are set first, so hour/min/sec lights override and don't flicker as millisec passes
leds[(subSeconds+LEDOffset)%60].r = 50;
leds[(subSeconds+LEDOffset)%60].g = 50;
leds[(subSeconds+LEDOffset)%60].b = 50;
// The colours are set last, so if on same LED mixed colours are created
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
// Pendulum will be at the bottom and left for one second and right for one second
void simplePendulum(DateTime now)
{
if (now.second()!=old.second())
{
old = now;
cyclesPerSec = millis() - newSecTime;
cyclesPerSecFloat = (float) cyclesPerSec;
newSecTime = millis();
if (swingBack == true) {swingBack = false;}
else {swingBack = true;}
}
// set hour, min & sec LEDs
fracOfSec = (millis() - newSecTime)/cyclesPerSecFloat; // This divides by 733, but should be 1000 and not sure why???
if (subSeconds < cyclesPerSec && swingBack == true) {pendulumPos = 27.0 + 3.4*(1.0+sin((3.14*fracOfSec)-1.57));}
if (subSeconds < cyclesPerSec && swingBack == false) {pendulumPos = 27.0 + 3.4*(1.0+sin((3.14*fracOfSec)+1.57));}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
// Pendulum lights are set first, so hour/min/sec lights override and don't flicker as millisec passes
leds[(pendulumPos + LEDOffset)%60].r = 100;
leds[(pendulumPos + LEDOffset)%60].g = 100;
leds[(pendulumPos + LEDOffset)%60].b = 100;
// The colours are set last, so if on same LED mixed colours are created
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
void breathingClock(DateTime now)
{
if (alarmTrig == false)
{
breathBrightness = 15.0*(1.0+sin((3.14*millis()/2000.0)-1.57));
for (int i = 0; i < numLEDs; i++)
{
fiveMins = i%5;
if (fiveMins == 0)
{
leds[i].r = breathBrightness + 5;
leds[i].g = breathBrightness + 5;
leds[i].b = breathBrightness + 5;
}
else
{
leds[i].r = 0;
leds[i].g = 0;
leds[i].b = 0;
}
}
}
unsigned char hourPos = ((now.hour()%12)*5 + (now.minute()+6)/12);
leds[(hourPos+LEDOffset+59)%60].r = 255;
leds[(hourPos+LEDOffset)%60].r = 255;
leds[(hourPos+LEDOffset+1)%60].r = 255;
leds[(now.minute()+LEDOffset)%60].g = 255;
leds[(now.second()+LEDOffset)%60].b = 255;
}
/*
// Cycle through the color wheel, equally spaced around the belt
void rainbowCycle(uint8_t wait)
{
uint16_t i, j;
for (j=0; j < 384 * 5; j++)
{ // 5 cycles of all 384 colors in the wheel
for (i=0; i < numLEDs; i++)
{
// tricky math! we use each pixel as a fraction of the full 384-color
// wheel (thats the i / strip.numPixels() part)
// Then add in j which makes the colors go around per pixel
// the % 384 is to make the wheel cycle around
strip.setPixelColor(i, Wheel(((i * 384 / numLEDs) + j) % 384));
}
delay(wait);
}
}
//Input a value 0 to 384 to get a color value.
//The colours are a transition r - g - b - back to r
uint32_t Wheel(uint16_t WheelPos)
{
byte r, g, b;
switch(WheelPos / 128)
{
case 0:
r = 127 - WheelPos % 128; // red down
g = WheelPos % 128; // green up
b = 0; // blue off
break;
case 1:
g = 127 - WheelPos % 128; // green down
b = WheelPos % 128; // blue up
r = 0; // red off
break;
case 2:
b = 127 - WheelPos % 128; // blue down
r = WheelPos % 128; // red up
g = 0; // green off
...
This file has been truncated, please download it to see its full contents.
Comments