Skip to content

Instantly share code, notes, and snippets.

@Tom-Archer
Created June 10, 2023 20:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tom-Archer/f22e123e8c22ae0b721cc36e6d0b5d5d to your computer and use it in GitHub Desktop.
Save Tom-Archer/f22e123e8c22ae0b721cc36e6d0b5d5d to your computer and use it in GitHub Desktop.
Battlestar Chronometer Sample Arduino Code
#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