#include <SPI.h>
#include <Button_SL.hpp>
#include <Streaming.h>
Print& cout {Serial};
// #define LEADING_ZEROS
//
// Global constants
//
namespace gc {
constexpr byte PinCS {10}; // SPI CS PIN
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
};
} // namespace gc
//
// Global Variables/Objects
//
Btn::ButtonSL btn {gc::PinBtn};
//
// Send data to the shift register
//
void writeShiftRegister(uint16_t PinData) {
digitalWrite(gc::PinCS, LOW);
SPI.transfer(PinData >> 8); // upper 8 Bits = digit selection
SPI.transfer((PinData & 0x00FF)); // lower 8 Bits = segments of the digit
digitalWrite(gc::PinCS, HIGH);
}
//
// Delete Digit on the display
//
void digitsOff() {
writeShiftRegister(0x00); // Clear Digits
}
//
// Show digit on the corresponding display position.
//
template <size_t N> void digitToDisplay(uint8_t (&Dgt)[N], uint8_t DotPos, uint8_t Idx) {
uint16_t Mask = ~(1 << (Idx)) & 0x00FF; // Set bit mask to display one of the four LED segments
uint16_t Bits {Mask << 8}; // Highbyte (LED-Segment)
Bits |= gc::SegmentBits[Dgt[Idx]]; // Lowbyte (Digit)
// Test whether a dot must be displayed (DotPos > 0)
if (DotPos > 0 && DotPos < N && Mask == (0x00FF - (1U << DotPos))) { Bits |= 0b00100000; }
writeShiftRegister(Bits);
}
//
// Divide the Number into its decimal places
//
template <size_t N> uint8_t breakNumberDown(uint8_t (&Dgt)[N], uint16_t Nbr) {
size_t Idx {0};
do {
Dgt[Idx] = Nbr % 10;
Nbr /= 10;
} while (Nbr && ++Idx < N);
return Idx;
}
void sevenSegment(Btn::ButtonSL& b) {
constexpr uint8_t MaxDigits {4}; // Max. displayable Digits
static uint8_t Digits[MaxDigits];
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);
cout << "\r\nNumber: " << _WIDTH(Number, 4) << "\r\n";
DotPos = random(0, MaxDigits);
NumDigits = breakNumberDown(Digits, Number);
cout << "Dot Position: " << DotPos << "\r\nNr. of Digits: " << NumDigits + 1 << "\r\n";
}
digitToDisplay(Digits, DotPos, ActiveDigit);
#ifdef LEADING_ZEROS
ActiveDigit = (ActiveDigit < MaxDigits - 1) ? ActiveDigit + 1 : 0;
#else
// Decimal point position is greater than the number of Digits -> 0.X[XX]
// If the position of the dot is greater than the number of decimal places of the random number,
// a leading zero has to be displayed.
NumDigits = (DotPos > NumDigits) ? DotPos : NumDigits;
ActiveDigit = (ActiveDigit < NumDigits) ? ActiveDigit + 1 : 0;
#endif
}
//
// Main Program
//
void setup() {
Serial.begin(115200);
pinMode(gc::PinCS, 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