Created
June 10, 2023 20:15
-
-
Save Tom-Archer/f22e123e8c22ae0b721cc36e6d0b5d5d to your computer and use it in GitHub Desktop.
Battlestar Chronometer Sample Arduino Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Adafruit_LEDBackpack.h" | |
#ifndef _BV | |
#define _BV(bit) (1<<(bit)) | |
#endif | |
class LEDBackpack : public Adafruit_LEDBackpack | |
{ | |
public: | |
// Convenience function to set a specific pixel. | |
void setPixel(int16_t x, int16_t y, uint8_t on=1) | |
{ | |
if (on) | |
{ | |
displaybuffer[y] |= _BV(x); | |
} | |
else | |
{ | |
displaybuffer[y] &= ~(_BV(x)); | |
} | |
} | |
}; | |
LEDBackpack seconds = LEDBackpack(); | |
LEDBackpack minutes = LEDBackpack(); | |
LEDBackpack hours = LEDBackpack(); | |
void setup() { | |
seconds.begin(0x70); | |
minutes.begin(0x71); | |
minutes.setBrightness(12); | |
hours.begin(0x72); | |
randomSeed(analogRead(0)); | |
} | |
/* Clear all the displays. | |
*/ | |
void clearAll() { | |
hours.clear(); | |
minutes.clear(); | |
seconds.clear(); | |
} | |
/* Write to all the displays. | |
*/ | |
void writeAll() { | |
hours.writeDisplay(); | |
minutes.writeDisplay(); | |
seconds.writeDisplay(); | |
} | |
/* Blink all the displays (doesn't require a write). | |
*/ | |
void blinkAll(uint8_t b) { | |
hours.blinkRate(b); | |
minutes.blinkRate(b); | |
seconds.blinkRate(b); | |
} | |
// The HT16K33 internal memory looks like | |
// a 8x16 bit matrix (8 rows, 16 columns) | |
// The HT16K33 has 8 cathodes and 16 anodes | |
void loop() { | |
delay(1000); | |
pixelTestSingleRings(20, 3); | |
pixelTestAllRings(10, 3); | |
pixelTestSpiral(10, 3); | |
pixelTestFan(10, 3); | |
pixelTestLarson(100); | |
//timeDemo(11,59,55,10); | |
//countdownDemo(0, 1, 15, 200); | |
} | |
/* Turn on each ring individually. | |
*/ | |
void pixelTestSingleRings(uint16_t delta, uint8_t iterations) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
writeAll(); | |
for (uint8_t i=0; i<iterations; i++) | |
{ | |
// Seconds | |
seconds.clear(); | |
seconds.writeDisplay(); | |
for (int a=0; a<60; a++) | |
{ | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k); | |
seconds.writeDisplay(); | |
delay(delta); | |
} | |
seconds.clear(); | |
seconds.writeDisplay(); | |
// Minutes | |
minutes.clear(); | |
minutes.writeDisplay(); | |
for (int a=0; a<60; a++) | |
{ | |
uint8_t k = a/8; | |
minutes.setPixel(a%8, k); | |
minutes.writeDisplay(); | |
delay(delta); | |
} | |
minutes.clear(); | |
minutes.writeDisplay(); | |
// Hours - LED Pairs | |
hours.clear(); | |
hours.writeDisplay(); | |
for (int a=0; a<12; a++) | |
{ | |
uint8_t k = (a/8)*2; | |
hours.setPixel(a%8, k); | |
hours.setPixel(a%8, k+1); | |
hours.writeDisplay(); | |
delay(delta*5); | |
} | |
hours.clear(); | |
hours.writeDisplay(); | |
} | |
} | |
/* Turn on all the rings and then turn off all the rings for the number of iterations. | |
*/ | |
void pixelTestAllRings(uint16_t delta, uint8_t iterations) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
writeAll(); | |
for (uint8_t i=0; i<iterations*2; i++) | |
{ | |
uint8_t on = (i+1)%2; | |
// Seconds | |
for (int a=0; a<60; a++) | |
{ | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k, on); | |
seconds.writeDisplay(); | |
delay(delta); | |
} | |
// Minutes | |
for (int a=0; a<60; a++) | |
{ | |
uint8_t k = a/8; | |
minutes.setPixel(a%8, k, on); | |
minutes.writeDisplay(); | |
delay(delta); | |
} | |
// Hours - Individual LEDs | |
for (int j=1; j>=0; j--) | |
{ | |
for (int a=0; a<12; a++) | |
{ | |
uint8_t k = j + (a/8)*2; | |
hours.setPixel(a%8, k, on); | |
hours.writeDisplay(); | |
delay(delta*5); | |
} | |
} | |
} | |
} | |
/* Illuminate the LEDs in a spiral pattern. | |
*/ | |
void pixelTestSpiral(uint16_t delta, uint8_t iterations) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
writeAll(); | |
uint8_t groupSize = 6; | |
uint8_t numGroups = 10; | |
for (uint8_t i=0; i<iterations*2; i++) | |
{ | |
uint8_t on = (i+1)%2; | |
// Seconds | |
for (uint8_t g=0; g<groupSize; g++) | |
{ | |
for (uint8_t n=0; n<numGroups; n++) | |
{ | |
uint8_t a = n*groupSize + g; | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k, on); | |
seconds.writeDisplay(); | |
// Delay here means nth LEDs turn on one after another | |
// and not at the same time. | |
delay(delta); | |
} | |
} | |
// Minutes | |
for (uint8_t g=0; g<groupSize; g++) | |
{ | |
for (uint8_t n=0; n<numGroups; n++) | |
{ | |
uint8_t a = n*groupSize + g; | |
uint8_t k = a/8; | |
minutes.setPixel(a%8, k, on); | |
minutes.writeDisplay(); | |
// Delay here means nth LEDs turn on one after another | |
// and not at the same time. | |
delay(delta); | |
} | |
} | |
// Hours - Individual LEDs | |
for (int j=1; j>=0; j--) | |
{ | |
for (uint8_t g=0; g<3; g++) | |
{ | |
for (uint8_t n=0; n<4; n++) | |
{ | |
uint8_t a = n*3 + g; | |
uint8_t k = j + (a/8)*2; | |
hours.setPixel(a%8, k, on); | |
hours.writeDisplay(); | |
// Delay here means nth LEDs turn on one after another | |
// and not at the same time. | |
delay(delta*5); | |
} | |
} | |
} | |
} | |
} | |
/* Rotate a fixed number (6) of LEDs around the display. | |
*/ | |
void pixelTestFan(uint16_t delta, uint8_t iterations) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
writeAll(); | |
// Hours - LED Pairs | |
// All on, always | |
for (int a=0; a<12; a++) | |
{ | |
uint8_t k = (a/8)*2; | |
hours.setPixel(a%8, k); | |
hours.setPixel(a%8, k+1); | |
} | |
hours.writeDisplay(); | |
uint8_t groupSize = 6; | |
uint8_t numGroups = 5; | |
uint8_t interval = 60/numGroups; | |
// Make the LEDs appear nicely | |
for (uint8_t g=0; g<groupSize-1; g++) | |
{ | |
for (uint8_t n=0; n<numGroups; n++) | |
{ | |
uint8_t a = (n*interval + g)%60; | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k); | |
minutes.setPixel(a%8, k); | |
} | |
writeAll(); | |
delay(delta*2); | |
} | |
// Rotate | |
for (uint16_t i=0; i<(120*iterations)+1; i++) | |
{ | |
minutes.clear(); | |
seconds.clear(); | |
// Draw each group | |
for (uint8_t n=0; n<numGroups; n++) | |
{ | |
for (uint8_t g=0; g<groupSize; g++) | |
{ | |
uint8_t a = (n*interval + g + i)%60; | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k); | |
minutes.setPixel(a%8, k); | |
} | |
} | |
writeAll(); | |
delay(delta); | |
} | |
// Make remaining LEDs disappear nicely | |
for (uint8_t g=0; g<groupSize; g++) | |
{ | |
for (uint8_t n=0; n<numGroups; n++) | |
{ | |
uint8_t a = (n*interval + g)%60; | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k, 0); | |
minutes.setPixel(a%8, k, 0); | |
} | |
writeAll(); | |
delay(delta*2); | |
} | |
} | |
/* Show a provided time. | |
*/ | |
void displayTime(uint8_t h, uint8_t m, uint8_t s) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
// Make 0 illuminate all LEDs | |
if (h == 0) | |
{ | |
h = 12; | |
} | |
if (m == 0) | |
{ | |
m = 60; | |
} | |
if (s == 0) | |
{ | |
s = 60; | |
} | |
// Set the seconds value | |
for (int a=0; a<s; a++) | |
{ | |
uint8_t k = a/8; | |
seconds.setPixel(a%8, k); | |
} | |
// Set the minutes value | |
for (int a=0; a<m; a++) | |
{ | |
uint8_t k = a/8; | |
minutes.setPixel(a%8, k); | |
} | |
// Set the hours value | |
for (int a=0; a<h; a++) | |
{ | |
uint8_t k = (a/8)*2; | |
hours.setPixel(a%8, k); | |
hours.setPixel(a%8, k+1); | |
} | |
// Display | |
writeAll(); | |
} | |
/* Display a dummy time and count up for the provided number of seconds. | |
*/ | |
void timeDemo(uint8_t h, uint8_t m, uint8_t s, uint8_t duration) | |
{ | |
for (uint8_t i=0; i<duration; i++) | |
{ | |
displayTime(h,m,s); | |
delay(1000); | |
// Increment time | |
s += 1; | |
if (s%60 == 0) | |
{ | |
m += 1; | |
if (m%60 == 0) | |
{ | |
h += 1; | |
} | |
} | |
// Bound time | |
s = s%60; | |
m = m%60; | |
h = h%12; | |
} | |
} | |
/* Countdown from the provided time (hours, minutes and seconds). | |
*/ | |
void countdownDemo(uint8_t h, uint8_t m, uint8_t s, uint16_t delta) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
displayTime(h, m, s); | |
delay(delta); | |
while (true) | |
{ | |
// Decrement the countdown time by 1 second | |
if (s>0) | |
{ | |
s -= 1; | |
if ((s%60 == 0) && (m>0)) | |
{ | |
m -= 1; | |
s = 60; | |
if ((m%60 == 0) && (h>0)) | |
{ | |
m = 60; | |
h -= 1; | |
} | |
} | |
} | |
// Display for delta (1 second) | |
displayTime(h, m, s); | |
delay(delta); | |
// Check whether 0h0m0s has been reached | |
if ((h==0) && (m==0) & (s==0)) | |
{ | |
break; | |
} | |
} | |
blinkAll(HT16K33_BLINK_1HZ); | |
delay(5000); | |
clearAll(); | |
writeAll(); | |
blinkAll(HT16K33_BLINK_OFF); | |
} | |
/* Defines a snake. | |
*/ | |
class Snake { | |
protected: | |
uint8_t _snakeLength; | |
uint8_t _matrixLength; | |
uint8_t _itLow; | |
uint8_t _itHigh; | |
int8_t _startPoint; | |
int8_t _endPoint; | |
uint8_t _iterations; | |
uint8_t _iteration; | |
bool _direction; | |
public: | |
/* Constructor. | |
*/ | |
Snake(uint8_t snakeLength, uint8_t matrixLength, uint8_t itLow, uint8_t itHigh) | |
{ | |
_snakeLength = snakeLength; | |
_matrixLength = matrixLength; | |
_itLow = itLow; | |
_itHigh = itHigh; | |
_startPoint = random(0, _matrixLength); | |
_direction = random(0, 2); | |
if (!_direction) | |
{ | |
_endPoint = _startPoint; | |
_startPoint = (_endPoint - _snakeLength)%_matrixLength; | |
} | |
else | |
{ | |
_endPoint = (_startPoint + _snakeLength)%_matrixLength; | |
} | |
// Ensure the points are valid LED indices | |
if (_startPoint < 0) | |
{ | |
_startPoint+=_matrixLength; | |
} | |
if (_endPoint < 0) | |
{ | |
_endPoint+=_matrixLength; | |
} | |
_iterations = random(_itLow, _itHigh+1); | |
_iteration = 0; | |
} | |
/* Update the position. | |
*/ | |
void update() | |
{ | |
// Move the snake | |
if (!_direction) | |
{ | |
_startPoint = (_startPoint-1)%_matrixLength; | |
_endPoint = (_endPoint-1)%_matrixLength; | |
} | |
else | |
{ | |
_startPoint = (_startPoint+1)%_matrixLength; | |
_endPoint = (_endPoint+1)%_matrixLength; | |
} | |
// Ensure the points are valid LED indices | |
if (_startPoint < 0) | |
{ | |
_startPoint+=_matrixLength; | |
} | |
if (_endPoint < 0) | |
{ | |
_endPoint+=_matrixLength; | |
} | |
// Update the iteration | |
_iteration++; | |
if (_iteration > _iterations) | |
{ | |
_direction = !_direction; | |
_iterations = random(_itLow, _itHigh+1); | |
_iteration = 0; | |
} | |
} | |
/* Write to the matrix buffer. | |
*/ | |
virtual void write(LEDBackpack& matrix, uint8_t a) | |
{ | |
uint8_t k = a/8; | |
matrix.setPixel(a%8, k); | |
} | |
/* Draw the snake. | |
*/ | |
void draw(LEDBackpack& matrix) | |
{ | |
if (_startPoint < _endPoint) | |
{ | |
// Normal | |
for (uint8_t a=_startPoint; a<_endPoint; a++) | |
{ | |
write(matrix, a); | |
} | |
} | |
else | |
{ | |
// Overlapped | |
for (uint8_t a=_startPoint; a<_matrixLength; a++) | |
{ | |
write(matrix, a); | |
} | |
for (uint8_t a=0; a<_endPoint; a++) | |
{ | |
write(matrix, a); | |
} | |
} | |
} | |
}; | |
/* Defines a snake on the outer hours LEDs. | |
*/ | |
class HoursOuterSnake : public Snake | |
{ | |
public: | |
/* Constructor. | |
*/ | |
HoursOuterSnake(uint8_t snakeLength, uint8_t matrixLength, uint8_t itLow, uint8_t itHigh) : | |
Snake(snakeLength, matrixLength, itLow, itHigh) | |
{ | |
} | |
/* Write to the matrix buffer. | |
*/ | |
virtual void write(LEDBackpack& matrix, uint8_t a) | |
{ | |
uint8_t k = (a/8)*2 + 1; | |
matrix.setPixel(a%8, k); | |
} | |
}; | |
/* Defines a snake on the inner hours LEDs. | |
*/ | |
class HoursInnerSnake : public Snake | |
{ | |
public: | |
/* Constructor. | |
*/ | |
HoursInnerSnake(uint8_t snakeLength, uint8_t matrixLength, uint8_t itLow, uint8_t itHigh) : | |
Snake(snakeLength, matrixLength, itLow, itHigh) | |
{ | |
} | |
/* Write to the matrix buffer. | |
*/ | |
virtual void write(LEDBackpack& matrix, uint8_t a) | |
{ | |
uint8_t k = (a/8)*2; | |
matrix.setPixel(a%8, k); | |
} | |
}; | |
/* Curved Larson scanners. | |
*/ | |
void pixelTestLarson(uint16_t delta) | |
{ | |
// Clear all the LEDs for good measure | |
clearAll(); | |
writeAll(); | |
// Define the snakes | |
Snake secondsSnake = Snake(6, 60, 30, 50); | |
Snake minutesSnake = Snake(8, 60, 30, 50); | |
HoursOuterSnake hoursOuterSnake = HoursOuterSnake(4, 12, 15, 25); | |
HoursInnerSnake hoursInnerSnake = HoursInnerSnake(3, 12, 15, 25); | |
while (true) | |
{ | |
clearAll(); | |
secondsSnake.draw(seconds); | |
minutesSnake.draw(minutes); | |
hoursOuterSnake.draw(hours); | |
hoursInnerSnake.draw(hours); | |
writeAll(); | |
secondsSnake.update(); | |
minutesSnake.update(); | |
hoursOuterSnake.update(); | |
hoursInnerSnake.update(); | |
delay(delta); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment