#include <FastLED.h>
#include <LiquidCrystal_I2C.h>
#include <stdio.h>
#include <Wire.h>
// thanks to Emmett Lathrop Brown
#define ENABLE_FLUX_CAPACITOR 0
// RTC module at address 0x68
#define DS1307_ADDRESS 0x68
// LCD module at address 0x27
LiquidCrystal_I2C lcd(0x27, 20, 4);
uint8_t clear = 0x00;
#define WIDTH 16
#define HEIGHT 16
#define NUM_LEDS ((WIDTH) * (HEIGHT))
CRGB leds[NUM_LEDS + 1];
byte heat[WIDTH][HEIGHT];
byte *heat1d = (byte *) heat;
uint16_t XY(const uint8_t x, const uint8_t y) {
if (x >= WIDTH) return NUM_LEDS;
if (y >= HEIGHT) return NUM_LEDS;
// if (y & 1)
// return (y + 1) * WIDTH - 1 - x;
// else
return y * WIDTH + x;
}
#include "wuLineAA.h"
struct DS1307_tm {
union {
struct {
uint8_t seconds, minutes, hours;
uint8_t wday, mday, month, year;
};
uint8_t raw[7];
};
} tm;
void ds1307_read() {
// Read the values (date and time) of the DS1307 module
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(clear);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 0x07);
for (uint8_t i = 0; i < 7; i++)
tm.raw[i] = bcdToDec(Wire.read());
}
void setup()
{
FastLED.addLeds<NEOPIXEL, 2>(leds, NUM_LEDS);
Wire.begin();
Serial.begin(9600);
lcd.begin (16, 2);
lcd.backlight();
// Use a line below to customize a date and time
// sec, min, hour, wday, mday, month, year % 100
// setDateTime(50, 59, 23, 7, 28, 2, 21);
// setDateTime(00, 29, 04, 4, 21, 2, 15);
// setDateTime(00, 46, 07, 4, 21, 2, 15);
// setDateTime(00, 20, 01, 7, 26, 10, 85);
ds1307_read();
}
void loop()
{
if (ENABLE_FLUX_CAPACITOR) {
tm.seconds += ENABLE_FLUX_CAPACITOR;
while (tm.seconds >= 60) ++tm.minutes, tm.seconds -= 60;
while (tm.minutes >= 60) ++tm.hours, tm.minutes -= 60;
while (tm.hours >= 24) ++tm.mday, ++tm.wday, tm.hours -= 24;
while (tm.wday >= 8) tm.wday -= 7;
while (tm.mday > 31) ++tm.month, tm.mday = 1; // i'm sure this is correct :p
while (tm.month > 12) ++tm.year, tm.month = 1;
ledclock(tm.hours, tm.minutes, tm.seconds);
} else
ds1307_read();
// update LEDs regularly
ledclock(tm.hours, tm.minutes, tm.seconds);
// update LCD once per second
static uint8_t last_seconds = 255;
if (last_seconds == tm.seconds)
return;
last_seconds = tm.seconds;
// flash the time separator
char time_sep = ':';
if (tm.seconds & 1)
time_sep = ' ';
// format the first line into a temporary buffer
char strbuf[17];
snprintf(strbuf, 17, "%02d%c%02d%c%02d",
tm.hours, time_sep, tm.minutes, time_sep, tm.seconds);
lcd.setCursor(4, 0);
lcd.print(strbuf);
// update 2nd line only when it changes
static uint8_t last_wday = 255;
if (last_wday == tm.wday)
return;
last_wday = tm.wday;
// format the second line
const char day_str[] = "NulSunMonTueWedThuFriSat";
uint16_t year = 2000 + tm.year;
if (year > 2038)
year -= 100;
snprintf(strbuf, 17, "%4d-%02d-%02d @@@",
year, tm.month, tm.mday);
memcpy(strbuf + 11, day_str + tm.wday * 3, 3);
lcd.setCursor(1, 1);
lcd.print(strbuf);
}
// Set the date and time of the DS1307
void setDateTime(uint8_t seconds, uint8_t minutes, uint8_t hours,
uint8_t wday, uint8_t mday, uint8_t month, uint8_t year)
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(clear); // Write clear, so that it can receive data
// The lines below write in the CI the date and time values
// that were placed in the variables above
Wire.write(decToBcd(seconds));
Wire.write(decToBcd(minutes));
Wire.write(decToBcd(hours));
Wire.write(decToBcd(wday));
Wire.write(decToBcd(mday));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.write(clear);
Wire.endTransmission();
}
uint8_t decToBcd(uint8_t value)
{
// Converts the decimal number to BCD
return ((value / 10 * 16) + (value % 10));
}
uint8_t bcdToDec(uint8_t value)
{
// Converts from BCD to decimal
return ((value / 16 * 10) + (value % 16));
}
// LED matrix analogue clock
void wuVectorAA(const uint16_t x, const uint16_t y, const uint16_t length, const uint16_t theta, CRGB *col) {
int16_t dx, dy;
dx = ((int32_t)cos16(theta) * length) / 32768;
dy = ((int32_t)sin16(theta) * length) / 32768;
wuLineAA(x, y, x + dx, y + dy, col);
}
void wuVectorAA8(const uint16_t x, const uint16_t y, const uint16_t length, const uint16_t theta) {
int16_t dx, dy;
dx = ((int32_t)cos16(theta) * length) / 32768;
dy = ((int32_t)sin16(theta) * length) / 32768;
wuLineAA8(x, y, x + dx, y + dy);
}
void ledclock(const uint8_t &hours, const uint8_t &minutes, const uint8_t &seconds) {
// FastLED.clear();
// everything is fixed-point, with 8-bits of fraction
uint16_t centrex = WIDTH * 128 - 128;
uint16_t centrey = HEIGHT * 128 - 128;
uint16_t length = WIDTH * 128;
uint16_t base_theta = 65536 * 3 / 4;
// second hand with sweep action
uint16_t theta = seconds * 65536 / 60;
static uint16_t sweep_theta = theta;
int32_t diff = theta - sweep_theta;
if (diff < 0)
diff += 65536;
sweep_theta += (diff + 8) / 16;
wuVectorAA8(centrex, centrey, length, base_theta + sweep_theta);
// minute hand
theta = (theta + minutes * 65536) / 60;
uint16_t min_theta = theta;
wuVectorAA8(centrex, centrey, length * 7 / 8, base_theta + theta);
// hour hand
theta = (theta + (hours % 12) * 65536) / 12;
wuVectorAA8(centrex, centrey, length * 3 /4, base_theta + theta);
for (int16_t i = NUM_LEDS; i--; )
leds[i] = HeatColor(heat1d[i]);
CRGB col = 0x0;
wuVectorAA(centrex, centrey, length, base_theta + sweep_theta, &col);
wuVectorAA(centrex, centrey, length * 7 / 8, base_theta + min_theta, &col);
wuVectorAA(centrex, centrey, length * 3 / 4, base_theta + theta, &col);
FastLED.show();
Fire2012(random(192));
}
void Fire2012(uint8_t activity) {
for (uint8_t h = 0; h < WIDTH; h++) {
// Step 1. Cool down every cell a little
for ( uint8_t i = 0; i < HEIGHT; i++) {
heat[i][h] = qsub8( heat[i][h], random8(33));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
uint8_t hleft = h > 0 ? (h - 1) : 0;
uint8_t hright = h < WIDTH - 1 ? (h + 1) : WIDTH - 1;
for ( uint8_t k = 0 ; k < HEIGHT - 1; k++) {
heat[k][h] = (heat[k][h]
+ heat[k + 1][hleft]
+ heat[k + 1][h]
+ heat[k + 1][hright] ) / 4;
}
if ( random8() < activity ) {
heat[HEIGHT - 1][h] = qadd8( heat[HEIGHT - 1][h], random8(activity));
}
}
}