#define CLK 13
#define DIN 11
#define CS 10
#define X_SEGMENTS 4
#define Y_SEGMENTS 4
#define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS)
// Pins for the first slide switch
#define SWITCH_PIN_1 7
#define SWITCH_PIN_2 6
// Pins for the second slide switch (mode selector)
#define MODE_SWITCH_PIN_1 5
#define MODE_SWITCH_PIN_2 3
// Pins for the push buttons
#define PB1_PIN 4
#define PB2_PIN 2
// a framebuffer to hold the state of the entire matrix of LEDs
// laid out in raster order, with (0, 0) at the top-left
byte fb[8 * NUM_SEGMENTS];
void shiftAll(byte send_to_address, byte send_this_data) {
digitalWrite(CS, LOW);
for (int i = 0; i < NUM_SEGMENTS; i++) {
shiftOut(DIN, CLK, MSBFIRST, send_to_address);
shiftOut(DIN, CLK, MSBFIRST, send_this_data);
}
digitalWrite(CS, HIGH);
}
void setup() {
Serial.begin(115200);
pinMode(CLK, OUTPUT);
pinMode(DIN, OUTPUT);
pinMode(CS, OUTPUT);
pinMode(SWITCH_PIN_1, INPUT_PULLUP);
pinMode(SWITCH_PIN_2, INPUT_PULLUP);
pinMode(MODE_SWITCH_PIN_1, INPUT_PULLUP);
pinMode(MODE_SWITCH_PIN_2, INPUT_PULLUP);
pinMode(PB1_PIN, INPUT_PULLUP);
pinMode(PB2_PIN, INPUT_PULLUP);
// Setup each MAX7219
shiftAll(0x0f, 0x00); //display test register - test mode off
shiftAll(0x0b, 0x07); //scan limit register - display digits 0 thru 7
shiftAll(0x0c, 0x01); //shutdown register - normal operation
shiftAll(0x0a, 0x0f); //intensity register - max brightness
shiftAll(0x09, 0x00); //decode mode register - No decode
clear();
show();
}
void loop() {
// Arrow patterns
byte rightArrow[8] = {
0b00011000,
0b00001100,
0b01111110,
0b11111111,
0b01111110,
0b00001100,
0b00011000,
0b00000000
};
byte leftArrow[8] = {
0b00011000,
0b00110000,
0b01111110,
0b11111111,
0b01111110,
0b00110000,
0b00011000,
0b00000000
};
// Read the mode switch state
bool modeSwitchState1 = digitalRead(MODE_SWITCH_PIN_1);
bool modeSwitchState2 = digitalRead(MODE_SWITCH_PIN_2);
if (!modeSwitchState1) { // Arrow mode
// Read the arrow direction switch state
bool switchState1 = digitalRead(SWITCH_PIN_1);
bool switchState2 = digitalRead(SWITCH_PIN_2);
if (!switchState1) { // Right position
displayArrow(rightArrow);
} else if (!switchState2) { // Left position
displayArrow(leftArrow);
}
} else if (!modeSwitchState2) { // Fill mode
// Read the push button state
bool pb1State = digitalRead(PB1_PIN);
bool pb2State = digitalRead(PB2_PIN);
if (!pb1State) { // Fill display immediately
fillDisplay(1);
} else if (!pb2State) { // Fill display with 1-second delay
fillDisplayWithDelay(1, 1000);
}
}
// Wait for 100ms
delay(100);
}
void displayArrow(byte arrow[8]) {
// Clear the framebuffer
clear();
// Draw the arrow in the framebuffer
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
byte bit = (arrow[y] >> (7 - x)) & 0x01;
if (bit) {
for (int segX = 0; segX < X_SEGMENTS; segX++) {
for (int segY = 0; segY < Y_SEGMENTS; segY++) {
safe_pixel(x + segX * 8, y + segY * 8, 1);
}
}
}
}
}
// Show the arrow
show();
}
void fillDisplay(uint8_t color) {
// Fill the framebuffer with the given color
for (int i = 0; i < 8 * NUM_SEGMENTS; i++) {
fb[i] = (color ? 0xFF : 0x00);
}
// Show the filled display
show();
}
void fillDisplayWithDelay(uint8_t color, unsigned long delayTime) {
fillDisplay(color);
delay(delayTime);
clear();
show();
}
void set_pixel(uint8_t x, uint8_t y, uint8_t mode) {
byte *addr = &fb[x / 8 + y * X_SEGMENTS];
byte mask = 128 >> (x % 8);
switch (mode) {
case 0: // clear pixel
*addr &= ~mask;
break;
case 1: // plot pixel
*addr |= mask;
break;
case 2: // XOR pixel
*addr ^= mask;
break;
}
}
void safe_pixel(uint8_t x, uint8_t y, uint8_t mode) {
if ((x >= X_SEGMENTS * 8) || (y >= Y_SEGMENTS * 8))
return;
set_pixel(x, y, mode);
}
// turn off every LED in the framebuffer
void clear() {
byte *addr = fb;
for (byte i = 0; i < 8 * NUM_SEGMENTS; i++)
*addr++ = 0;
}
// send the raster order framebuffer in the correct order
// for the boustrophedon layout of daisy-chained MAX7219s
void show() {
for (byte row = 0; row < 8; row++) {
digitalWrite(CS, LOW);
byte segment = NUM_SEGMENTS;
while (segment--) {
byte x = segment % X_SEGMENTS;
byte y = segment / X_SEGMENTS * 8;
byte addr = (row + y) * X_SEGMENTS;
if (segment & X_SEGMENTS) { // odd rows of segments
shiftOut(DIN, CLK, MSBFIRST, 8 - row);
shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]);
} else { // even rows of segments
shiftOut(DIN, CLK, MSBFIRST, 1 + row);
shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]);
}
}
digitalWrite(CS, HIGH);
}
}