// MAX7219 bargraph display
// Select left or right insertion
// Lowest value LED blinks when the value is zero
// Select column height from one to eight LEDs
// Select row width from one to eight LEDs
//
// ⃝⃝⃝⃝⃝⃝⃝⃝ 0
// ⃝⃝⃝⃝⃝⃝⃝⃝ 1 Matrix LED identification
// ⃝⃝⃝⃝⃝⃝⃝⃝ 2
// ⃝⃝⃝⃝⃝⃝⃝⃝ 3 Rows
// ⃝⃝⃝⃝⃝⃝⃝⃝ 4
// ⃝⃝⃝⃝⃝⃝⃝⃝ 5
// ⃝⃝⃝⃝⃝⃝⃝⃝ 6
// ⃝⃝⃝⃝⃝⃝⃝⃝ 7
// 76543210
// Columns
#include <LedControl.h>
#include <SoftwareSerial.h>
#define F_CPU 16500000L
#define CS_PIN PB0
#define CLK_PIN PB1
#define DIN_PIN PB2
#define SERIAL_TX PB3
#define SERIAL_RX PB5
#define MAX_SEG 1
//
// Adjust these settings to affect how the value is displayed
//
const uint8_t MAX_ROWS = 5;
const uint8_t MAX_COLUMNS = 6;
bool leftToRight = true; // true = value inserted left to right
bool rightToLeft = false; // false = value inserted right to left
bool insertDirection = leftToRight;
// bool insertDirection = rightToLeft;
//
// Other values used
//
const uint8_t TOTAL_LEDS = MAX_ROWS * MAX_COLUMNS;
const uint8_t BOTTOM_ROW_OF_DISPLAY = 7;
const uint8_t COLUMN_7 = 7;
const uint8_t COLUMN_0 = 0;
const uint8_t ROW_5 = 5;
const uint8_t ROW_6 = 6;
const uint8_t ROW_7 = 7;
byte rowImage[MAX_ROWS]; // Converted value sent to MAX7219
int newValue; // The input value to be converted
uint8_t fullColumns;
uint8_t partialColumn;
uint8_t valuePot = A3;
// blinker function state variables
enum : uint8_t {initializeBlinker, blinkerOnPhase, blinkerOffPhase, blinkerOnTtransition, blinkerOffTransition};
uint8_t blinkState;
unsigned long blinkTimer;
bool runBlinker;
// For symmetrical on/off times just use the same time value for both states.
const unsigned long blinkerOnTime = 700;
const unsigned long blinkerOffTime = 1500;
// Instantiate software serial for ATTINY85 and set pins
SoftwareSerial mySerial(SERIAL_RX, SERIAL_TX);
// Set up the matrix control pins and maximum number of segments
LedControl matrixLEDDisplay = LedControl(DIN_PIN, CLK_PIN, CS_PIN, MAX_SEG); // MAX7219
void setup() {
//Serial.begin(115200);
mySerial.begin(9600);
matrixLEDDisplay.shutdown(0, false);
matrixLEDDisplay.setIntensity(0, 7);
matrixLEDDisplay.clearDisplay(0);
}
void loop() {
newValue = map(analogRead(valuePot), 0, 1023, 0, TOTAL_LEDS);
static int lastValue;
if (newValue != 0) {
runBlinker = false;
blinkState = initializeBlinker;
if (newValue != lastValue) {
clearRows();
lastValue = newValue;
fullColumns = newValue / MAX_ROWS;
partialColumn = newValue - (fullColumns * MAX_ROWS); // modulo alternative - faster?
if (partialColumn != 0) {
insertOneColumn(partialColumn, insertDirection);
}
if (fullColumns != 0) {
for (uint8_t i = 0; i < fullColumns; i++)
insertOneColumn(MAX_ROWS, insertDirection);
}
sendImage();
printStuff();
// mySerial.println(partialColumn);
}
}
else {
runBlinker = true;
}
blinkerFunction(runBlinker);
} // end of loop
//
// State machine to blink an LED.
//
void blinkerFunction(bool runBlinker) {
if (runBlinker) { // blink
uint8_t columnToInsertFrom = (insertDirection == leftToRight) ? COLUMN_7 : COLUMN_0;
switch (blinkState)
{
case initializeBlinker:
clearRows();
sendImage(); // Shut off any remaining ON LEDs
blinkState = blinkerOnTtransition; // Set the next state value
[[fallthrough]]; // Prevents compiler warnings about falling through
// due to lack of break; statement.
case blinkerOnTtransition:
matrixLEDDisplay.setLed(0, ROW_7, columnToInsertFrom, true);
blinkTimer = millis(); // Reset the timer
blinkState = blinkerOnPhase; // Set the next state value
[[fallthrough]];
case blinkerOnPhase:
if (millis() - blinkTimer < blinkerOnTime) { // Which it will be for awhile since the
// previous state set timer = millis()
break;
}
// When on time expires
blinkState = blinkerOffTransition; // Set the next state value
[[fallthrough]];
case blinkerOffTransition:
matrixLEDDisplay.setLed(0, ROW_7, columnToInsertFrom, false); // turns off LED at row, col
blinkTimer = millis(); // Reset the timer
blinkState = blinkerOffPhase; // Set the next state value
[[fallthrough]];
case blinkerOffPhase:
if (millis() - blinkTimer < blinkerOffTime) {
break;
}
blinkState = blinkerOnTtransition; // Set the next state value
break;
default:
blinkState = initializeBlinker; // If invalid state occurs, start at the beginning
}
}
} // end of blinkerFunction
//
// Bit shift the values into the image uint8_ts
//
void insertOneColumn(uint8_t rows, bool leftToRight) {
for (uint8_t i = 0; i < rows; i++) {
if (leftToRight) {
rowImage[i] <<= 1;
rowImage[i] |= B1;
}
else {
rowImage[i] = rowImage[i] >> 1;
rowImage[i] |= B10000000;
}
}
} // end of insertOneColumn
//
// Erase all the bits in the current image
//
void clearRows(void) {
for (uint8_t i = 0; i < MAX_ROWS; i++) {
rowImage[i] = 0;
}
}
//
// Send the image uint8_ts to the display
//
void sendImage(void) {
uint8_t k = BOTTOM_ROW_OF_DISPLAY;
for (uint8_t j = 0; j < MAX_ROWS; j++) {
matrixLEDDisplay.setRow(0, k--, rowImage[j]);
}
}
void printStuff() {
return;
mySerial.print("change\t");
mySerial.print(newValue);
mySerial.print("\t");
mySerial.print(fullColumns);
mySerial.print("\t");
mySerial.println(partialColumn);
}