#include <FastLED.h>
#include <avr/pgmspace.h>
// ================= HARDWARE =================
#define LED_PIN 12
#define COLOR_ORDER GRB
#define CHIPSET WS2812
#define BRIGHTNESS 255
const uint8_t matrixWidth = 32;
const uint8_t matrixHeight = 16;
#define NUM_LEDS (matrixWidth * matrixHeight)
CRGB leds[NUM_LEDS]; // Correct: no +1
// ================= 5x7 FONT =================
const uint8_t font5x7[96][5] PROGMEM = {
{0,0,0,0,0},{0,0,95,0,0},{0,7,0,7,0},{20,127,20,127,20},
{36,42,127,42,18},{35,19,8,100,98},{54,73,86,32,80},{0,7,0,0,0},
{0,28,34,65,0},{0,65,34,28,0},{20,8,62,8,20},{8,8,62,8,8},
{0,160,96,0,0},{8,8,8,8,8},{0,96,96,0,0},{32,16,8,4,2},
{62,81,73,69,62},{0,66,127,64,0},{98,81,73,73,70},
{34,65,73,73,54},{24,20,18,127,16},{39,69,69,69,57},
{60,74,73,73,48},{1,113,9,5,3},{54,73,73,73,54},
{6,73,73,41,30},{0,54,54,0,0},{0,182,102,0,0},
{8,20,34,65,0},{20,20,20,20,20},{0,65,34,20,8},
{2,1,89,9,6},{62,65,93,85,30},{126,17,17,17,126},
{127,73,73,73,54},{62,65,65,65,34},{127,65,65,34,28},
{127,73,73,73,65},{127,9,9,9,1},{62,65,73,73,122},
{127,8,8,8,127},{0,65,127,65,0},{32,64,65,63,1},
{127,8,20,34,65},{127,64,64,64,64},{127,2,12,2,127},
{127,4,8,16,127},{62,65,65,65,62},{127,9,9,9,6},
{62,65,97,33,94},{127,9,25,41,70},{38,73,73,73,50},
{1,1,127,1,1},{63,64,64,64,63},{31,32,64,32,31},
{63,64,56,64,63},{99,20,8,20,99},{3,4,120,4,3},
{97,81,73,69,67},{0,127,65,65,0},{2,4,8,16,32},
{0,65,65,127,0},{4,2,1,2,4},{64,64,64,64,64},
{0,1,2,4,0},{32,84,84,84,120},{127,72,68,68,56},
{56,68,68,68,32},{56,84,84,84,24},{8,126,9,1,2},
{24,164,164,164,124},{127,8,4,4,120},{0,68,125,64,0},
{64,128,128,122,0},{127,16,40,68,0},{0,65,127,64,0},
{124,4,24,4,120},{124,8,4,4,120},{56,68,68,68,56},
{124,20,20,20,8},{8,20,20,24,124},{124,8,4,4,8},
{72,84,84,84,36},{4,63,68,64,32},{60,64,64,32,124},
{28,32,64,32,28},{60,64,48,64,60},{68,40,16,40,68},
{12,144,144,144,124},{68,100,84,76,68},{0,8,54,65,0},
{0,0,119,0,0},{0,65,54,8,0},{2,1,2,4,2},{124,68,68,68,124}
};
// ================= XY =================
uint16_t XY(uint8_t x, uint8_t y) {
if (x >= matrixWidth || y >= matrixHeight) return 0;
if (y & 1) x = matrixWidth - 1 - x; // serpentine layout
return y * matrixWidth + x;
}
// ================= DRAW CHAR =================
void drawChar(int x, int y, char c, CRGB color) {
if (c < 32 || c > 127) return;
for (uint8_t col = 0; col < 5; col++) {
uint8_t line = pgm_read_byte(&font5x7[c - 32][col]);
for (uint8_t row = 0; row < 7; row++) {
if (line & (1 << row))
leds[XY(x + col, y + row)] = color;
}
}
}
// ================= DISPLAY NUMBER =================
void displayNumber(int num) {
FastLED.clear();
char buf[6];
sprintf(buf, "%d", num);
int startX = (matrixWidth - strlen(buf) * 6) / 2;
int startY = 4; // center vertically for 16 rows
for (uint8_t i = 0; buf[i]; i++)
drawChar(startX + i * 6, startY, buf[i], CRGB::Red);
FastLED.show();
}
// ================= SERIAL VARIABLES =================
String serialText = "";
bool newData = false;
// ================= TIMER VARIABLES =================
unsigned long lastMillis = 0;
int countdown = 0;
// ================= READ SERIAL =================
void readSerial() {
while (Serial.available()) {
char c = Serial.read();
if (c == '\n' || c == '\r') {
if (serialText.length() > 0) newData = true;
} else if (isDigit(c)) {
serialText += c;
}
}
}
// ================= SETUP =================
void setup() {
Serial.begin(9600);
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
displayNumber(88); // show something immediately
Serial.println("Enter countdown seconds and press ENTER:");
}
// ================= LOOP =================
void loop() {
readSerial();
// Start new countdown if Serial input received
if (newData) {
countdown = serialText.toInt();
displayNumber(countdown);
lastMillis = millis();
Serial.print("Countdown started: ");
Serial.println(countdown);
serialText = "";
newData = false;
}
// Countdown every second
if (countdown > 0 && millis() - lastMillis >= 1000) {
countdown--;
displayNumber(countdown);
lastMillis = millis();
}
}