#include <SPI.h>
#include <Button_SL.hpp>
// #define LEADING_ZEROS
//
// Global constants
//
constexpr byte CS_PIN {10}; // SPI CS PIN
constexpr uint8_t MAX_DIGITS {4}; // Max. displayable digits
constexpr uint8_t pinBtn {4}; // Button Pin
constexpr uint8_t segmentBits[10] = {
// edDcgbfa // D = decimal point
0b11010111, // 0
0b00010100, // 1
0b11001101, // 2
0b01011101, // 3
0b00011110, // 4
0b01011011, // 5
0b11011011, // 6
0b00010101, // 7
0b11011111, // 8
0b01011111, // 9
};
//
// Global Variables/Objects
//
Btn::ButtonSL btn {pinBtn};
//
// Send data to the shift register
//
void writeShiftRegister(uint16_t pinData) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(pinData >> 8); // upper 8 bits = digit selection
SPI.transfer((pinData & 0x00FF)); // lower 8 Bits = segments of the digit
digitalWrite(CS_PIN, HIGH);
}
//
// Delete Digit on the display
//
void digitsOff() {
writeShiftRegister(0x00); // Clear Digits
}
//
// Show digit on the corresponding display position.
//
void digitToDisplay(uint8_t dgt[], uint8_t dotPos, uint8_t idx) {
uint8_t mask = ~(1 << (idx)); // Set bit mask to display one of the four LED segments
uint16_t bits {mask << 8}; // Highbyte (LED-Segment)
bits |= segmentBits[dgt[idx]]; // Lowbyte (Digit)
if (dotPos > 0 && dotPos < MAX_DIGITS && mask == (0xFF - (1 << dotPos))) { bits |= 0b00100000; }
writeShiftRegister(bits);
}
//
// Divide the number into its decimal places
//
uint8_t breakNumberDown(uint8_t dgt[], uint16_t nbr) {
dgt[3] = nbr / 1000;
nbr %= 1000;
dgt[2] = nbr / 100;
nbr %= 100;
dgt[1] = nbr / 10;
nbr %= 10;
dgt[0] = nbr;
// Check whether leading zeros are present
auto i {MAX_DIGITS - 1};
for (; i > 0; --i) {
if (dgt[i] > 0) { break; }
}
// Return the number - 1 of digits to be displayed without a leading zero;
return i;
}
void sevenSegment(Btn::ButtonSL &b) {
static uint8_t digits[MAX_DIGITS];
static uint16_t dotPos;
static uint8_t activeDigit {0};
static uint8_t numDigits = 0;
// Press the button to display a new number
if (b.tick() == Btn::ButtonState::shortPressed) {
uint16_t number = random(1, 10000);
dotPos = random(0, MAX_DIGITS);
numDigits = breakNumberDown(digits, number);
}
digitToDisplay(digits, dotPos, activeDigit);
#ifdef LEADING_ZEROS
activeDigit = (activeDigit < MAX_DIGITS-1) ? activeDigit + 1 : 0;
#else
// Decimal point position is greater than the number of digits -> 0.X[XX]
numDigits = (dotPos > numDigits) ? dotPos : numDigits;
activeDigit = (activeDigit < numDigits) ? activeDigit + 1 : 0;
#endif
}
//
// Main Program
//
void setup() {
Serial.begin(115200);
pinMode(CS_PIN, OUTPUT);
SPI.begin();
btn.begin();
randomSeed(analogRead(A0));
}
void loop() { sevenSegment(btn); }
Press the button to
display a new number
You should also connect 100nF capacitors
between the respective VCC pins of the 74HC595 and GND
White: LED-Segment
Green: Digit