arduino based wordclock
https://www.champonthis.de/projects/wordclock
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
8.1 KiB
385 lines
8.1 KiB
#include <Wire.h>
|
|
#include <Adafruit_NeoPixel.h>
|
|
|
|
#include <AT24C32.h>
|
|
#include <DS3231.h>
|
|
|
|
#include <States.h>
|
|
#include <ViewStates.h>
|
|
#include <ControlStates.h>
|
|
#include <Button.h>
|
|
|
|
// debug
|
|
#define DEBUG 1
|
|
|
|
// Neopixel
|
|
#define MATRIX_PIN 12
|
|
#define MATRIX_SIZE 121
|
|
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(MATRIX_SIZE, MATRIX_PIN, NEO_GRB + NEO_KHZ800);
|
|
|
|
// Date view delimiter
|
|
#define DATE_DELIMITER '.'
|
|
|
|
// Buttons
|
|
#define LEFT_PIN 11
|
|
#define DECREMENT_PIN 10
|
|
#define ENTER_PIN 9
|
|
#define INCREMENT_PIN 8
|
|
#define RIGHT_PIN 7
|
|
|
|
Button leftBtn = Button(LEFT_PIN, LOW);
|
|
Button decrementBtn = Button(DECREMENT_PIN, LOW);
|
|
Button enterBtn = Button(ENTER_PIN, LOW);
|
|
Button incrementBtn = Button(INCREMENT_PIN, LOW);
|
|
Button rightBtn = Button(RIGHT_PIN, LOW);
|
|
|
|
// LED matrix
|
|
uint8_t matrix[MATRIX_SIZE];
|
|
|
|
// EPROMM AT24C32
|
|
AT24C32 at24c32;
|
|
|
|
// RTC DS3231
|
|
DS3231 ds3231;
|
|
|
|
// states
|
|
ControlStates controlState = ControlStates::VIEW;
|
|
ControlStates oldControlState = ControlStates::VIEW;
|
|
ViewStates viewState = ViewStates::TIME;
|
|
ViewStates oldViewState = ViewStates::TIME;
|
|
|
|
// control state
|
|
ControlState *currentControlState = new ControlViewState(at24c32);
|
|
|
|
// view state
|
|
ViewState *currentViewState = new ViewTimeState(ds3231, at24c32);
|
|
|
|
/**
|
|
setup
|
|
*/
|
|
void setup()
|
|
{
|
|
#ifdef DEBUG
|
|
Serial.begin(9600);
|
|
#endif
|
|
pixels.begin();
|
|
ds3231.begin();
|
|
at24c32.begin();
|
|
|
|
leftBtn.begin();
|
|
decrementBtn.begin();
|
|
enterBtn.begin();
|
|
incrementBtn.begin();
|
|
rightBtn.begin();
|
|
|
|
viewState = ViewStates(at24c32.read(VIEW_STATE_ADDRESS) % 6);
|
|
|
|
printStatus();
|
|
}
|
|
|
|
/**
|
|
loop
|
|
*/
|
|
void loop()
|
|
{
|
|
checkControlState();
|
|
controls();
|
|
checkViewState();
|
|
// render
|
|
renderInterval();
|
|
}
|
|
|
|
/**
|
|
check current control state and change eventually
|
|
*/
|
|
void checkControlState()
|
|
{
|
|
if (controlState != oldControlState)
|
|
{
|
|
delete currentControlState;
|
|
switch (controlState)
|
|
{
|
|
case ControlStates::VIEW:
|
|
currentControlState = new ControlViewState(at24c32);
|
|
break;
|
|
case ControlStates::TIME_HOURS:
|
|
currentControlState = new ControlTimeState(ds3231, at24c32);
|
|
break;
|
|
case ControlStates::TIME_MINUTES:
|
|
currentControlState = new ControlTimeState(ds3231, at24c32);
|
|
break;
|
|
case ControlStates::TIME_MODE:
|
|
currentControlState = new ControlTimeState(ds3231, at24c32);
|
|
break;
|
|
case ControlStates::TIME_SECONDS:
|
|
currentControlState = new ControlSecondsState(ds3231);
|
|
break;
|
|
case ControlStates::DATE_DATE:
|
|
currentControlState = new ControlDateState(ds3231);
|
|
break;
|
|
case ControlStates::DATE_MONTH:
|
|
currentControlState = new ControlDateState(ds3231);
|
|
break;
|
|
case ControlStates::DATE_YEAR:
|
|
currentControlState = new ControlDateState(ds3231);
|
|
break;
|
|
case ControlStates::COLOR_R:
|
|
currentControlState = new ControlColorState(at24c32);
|
|
break;
|
|
case ControlStates::COLOR_G:
|
|
currentControlState = new ControlColorState(at24c32);
|
|
break;
|
|
case ControlStates::COLOR_B:
|
|
currentControlState = new ControlColorState(at24c32);
|
|
break;
|
|
case ControlStates::TEXT:
|
|
currentControlState = new ControlTextState(at24c32);
|
|
break;
|
|
default:
|
|
currentControlState = new ControlViewState(at24c32);
|
|
}
|
|
oldControlState = controlState;
|
|
|
|
printStatus();
|
|
}
|
|
}
|
|
|
|
/**
|
|
check current view state and change eventually
|
|
*/
|
|
void checkViewState()
|
|
{
|
|
if (viewState != oldViewState)
|
|
{
|
|
delete currentViewState;
|
|
switch (viewState)
|
|
{
|
|
case ViewStates::TIME:
|
|
currentViewState = new ViewTimeState(ds3231, at24c32);
|
|
break;
|
|
case ViewStates::SECONDS:
|
|
currentViewState = new ViewSecondsState(ds3231, at24c32);
|
|
break;
|
|
case ViewStates::TEMPERATURE:
|
|
currentViewState = new ViewTemperatureState(ds3231, at24c32);
|
|
break;
|
|
case ViewStates::DATE:
|
|
currentViewState = new ViewDateState(ds3231, at24c32, DATE_DELIMITER);
|
|
break;
|
|
case ViewStates::TEXT:
|
|
currentViewState = new ViewTextState(at24c32);
|
|
break;
|
|
case ViewStates::LED_DEMO:
|
|
currentViewState = new ViewLEDState();
|
|
break;
|
|
default:
|
|
currentViewState = new ViewTimeState(ds3231, at24c32);
|
|
}
|
|
|
|
oldViewState = viewState;
|
|
at24c32.write(VIEW_STATE_ADDRESS, uint8_t(viewState));
|
|
|
|
printStatus();
|
|
}
|
|
}
|
|
|
|
/**
|
|
check inputs
|
|
*/
|
|
void controls()
|
|
{
|
|
leftBtn.loop(leftCallback);
|
|
decrementBtn.loop(decrementCallback);
|
|
enterBtn.loop(enterCallback);
|
|
incrementBtn.loop(incrementCallback);
|
|
rightBtn.loop(rightCallback);
|
|
}
|
|
|
|
/**
|
|
left callback
|
|
*/
|
|
void leftCallback()
|
|
{
|
|
// delegate to current control state
|
|
currentControlState->leftPressed(viewState, controlState);
|
|
#ifdef DEBUG
|
|
Serial.print(F("< "));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
decrement callback
|
|
*/
|
|
void decrementCallback()
|
|
{
|
|
// delegate to current control state
|
|
currentControlState->decrementPressed(viewState, controlState);
|
|
#ifdef DEBUG
|
|
Serial.print(F("- "));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
enter callback
|
|
*/
|
|
void enterCallback()
|
|
{
|
|
// delegate to current control state
|
|
currentControlState->enterPressed(viewState, controlState);
|
|
#ifdef DEBUG
|
|
Serial.print(F("# "));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
increment callback
|
|
*/
|
|
void incrementCallback()
|
|
{
|
|
// delegate to current control state
|
|
currentControlState->incrementPressed(viewState, controlState);
|
|
#ifdef DEBUG
|
|
Serial.print(F("+ "));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
right callback
|
|
*/
|
|
void rightCallback()
|
|
{
|
|
// delegate to current control state
|
|
currentControlState->rightPressed(viewState, controlState);
|
|
#ifdef DEBUG
|
|
Serial.print(F("> "));
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
periodic rendering
|
|
*/
|
|
void renderInterval()
|
|
{
|
|
static const unsigned long REFRESH_INTERVAL = 100;
|
|
static unsigned long lastRefreshTime = 0;
|
|
|
|
if (millis() - lastRefreshTime >= REFRESH_INTERVAL)
|
|
{
|
|
lastRefreshTime += REFRESH_INTERVAL;
|
|
render();
|
|
}
|
|
}
|
|
|
|
/**
|
|
render
|
|
*/
|
|
void render()
|
|
{
|
|
// set default color
|
|
uint8_t const color = at24c32.read(COLOR_ADDRESS);
|
|
currentViewState->setColor(color);
|
|
|
|
// set brightness
|
|
uint8_t const brightness = at24c32.read(BRIGHTNESS_ADDRESS);
|
|
pixels.setBrightness(brightness);
|
|
|
|
// reset matrix (to black)
|
|
for (int i = 0; i < MATRIX_SIZE; i++)
|
|
{
|
|
matrix[i] = 0x00;
|
|
}
|
|
|
|
// render matrix
|
|
currentViewState->render(matrix, controlState);
|
|
|
|
// set pixel
|
|
for (int i = 0; i < MATRIX_SIZE; i++)
|
|
{
|
|
uint8_t const r = (matrix[i] >> 5) * 255 / 7;
|
|
uint8_t const g = ((matrix[i] >> 2) & 0x07) * 255 / 7;
|
|
uint8_t const b = (matrix[i] & 0x03) * 255 / 3;
|
|
pixels.setPixelColor(i, pixels.Color(r, g, b));
|
|
}
|
|
|
|
pixels.show();
|
|
}
|
|
|
|
/**
|
|
print current status VIEW STATE \t CONTROL STATE \t FREE RAM
|
|
*/
|
|
void printStatus()
|
|
{
|
|
#ifdef DEBUG
|
|
switch (viewState)
|
|
{
|
|
case ViewStates::TIME:
|
|
Serial.print(F("TIME"));
|
|
break;
|
|
case ViewStates::SECONDS:
|
|
Serial.print(F("SECS"));
|
|
break;
|
|
case ViewStates::TEMPERATURE:
|
|
Serial.print(F("TEMP"));
|
|
break;
|
|
case ViewStates::DATE:
|
|
Serial.print(F("DATE"));
|
|
break;
|
|
case ViewStates::TEXT:
|
|
Serial.print(F("TEXT"));
|
|
break;
|
|
case ViewStates::LED_DEMO:
|
|
Serial.print(F("LEDS"));
|
|
break;
|
|
default:
|
|
Serial.print(F("TIME"));
|
|
}
|
|
|
|
Serial.print(F("\t"));
|
|
switch (controlState)
|
|
{
|
|
case ControlStates::VIEW:
|
|
Serial.print(F("VIEW "));
|
|
break;
|
|
case ControlStates::TIME_HOURS:
|
|
Serial.print(F("HOURS"));
|
|
break;
|
|
case ControlStates::TIME_MINUTES:
|
|
Serial.print(F("MINS "));
|
|
break;
|
|
case ControlStates::TIME_MODE:
|
|
Serial.print(F("MODE "));
|
|
break;
|
|
case ControlStates::TIME_SECONDS:
|
|
Serial.print(F("SECS "));
|
|
break;
|
|
case ControlStates::DATE_DATE:
|
|
Serial.print(F("DATE "));
|
|
break;
|
|
case ControlStates::DATE_MONTH:
|
|
Serial.print(F("MONTH"));
|
|
break;
|
|
case ControlStates::DATE_YEAR:
|
|
Serial.print(F("YEAR "));
|
|
break;
|
|
case ControlStates::COLOR_R:
|
|
Serial.print(F("COLOR_R"));
|
|
break;
|
|
case ControlStates::COLOR_G:
|
|
Serial.print(F("COLOR_G"));
|
|
break;
|
|
case ControlStates::COLOR_B:
|
|
Serial.print(F("COLOR_B"));
|
|
break;
|
|
case ControlStates::TEXT:
|
|
Serial.print(F("TEXT "));
|
|
break;
|
|
default:
|
|
Serial.print(F("VIEW "));
|
|
}
|
|
|
|
extern int __heap_start, *__brkval;
|
|
int v;
|
|
Serial.print(F("\tRAM: "));
|
|
Serial.println((int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval));
|
|
#endif
|
|
}
|