/*
Project: No library 7 segment counter
Description: Counts up on a 4 digit seven segment display
In a real circuit no pin can carry more than 40mA.
(Wokwi doesn't care...)
Best is to use transistor drivers on each common pin.
Here 680 ohm resistors keep the current acceptable.
The gray wires are digits, colored are the segments.
Creation date: 8/1/26
Author: AnonEngineering
License: Beerware
*/
const int MAX_DIGITS = 4;
const int DP_POS = 3; // decimal point position, digit 1 - MAX_DIGITS
const unsigned long CNT_INTERVAL = 100; // 0.1 second count
// pin constants
const uint8_t CLOCK_PIN = 7;
const uint8_t LATCH_PIN = 6;
const uint8_t DATA_PIN = 5;
const int DIGIT_PINS[MAX_DIGITS] = {10, 11, 12, 9}; // most significant digit first
// segment lookup table - DP, G - A
const byte NUM_SEGS[] = {
0b00111111, /* 0 */
0b00000110, /* 1 */
0b01011011, /* 2 */
0b01001111, /* 3 */
0b01100110, /* 4 */
0b01101101, /* 5 */
0b01111101, /* 6 */
0b00000111, /* 7 */
0b01111111, /* 8 */
0b01101111, /* 9 */
0b00000000 /* blank */
};
unsigned long prev_cnt_time = 0;
long countVal = 0;
void updateDisplay(long value, int dpPos) {
int maxPowOfTen = MAX_DIGITS - 1;
int minBlankDigit = dpPos - 1;
int digitVal = 0;
long operand1 = 1, operand2 = 1;
// separate the digits
//thousands = (value % 10000) / 1000 (value % operand1 / operand2)
//hundreds = (value % 1000) / 100
//tens = (value % 100) / 10
//ones = (value % 10) / 1
for (int digit = 0; digit <= maxPowOfTen; digit++) {
for (int p = maxPowOfTen - digit; p >= 1; p--) {
operand2 *= 10;
}
operand1 = operand2 * 10;
// don't blank digit where the dp and lower are
if (digit < minBlankDigit) {
// lead zero blanking
digitVal = value < operand2 ? 10 : (value % operand1) / operand2;
} else {
// no lead zero blanking
digitVal = (value % operand1) / operand2;
}
writeShiftDigit (digit, digitVal, ((dpPos - 1) == digit));
operand1 = 1; operand2 = 1;
}
}
void writeShiftDigit(uint8_t digit, uint8_t number, bool dp) {
uint8_t value = NUM_SEGS[number]; // invert (~) bits for common anode
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, dp ? (value | 0x80) : value);
digitalWrite(LATCH_PIN, HIGH);
// drive digit, reverse for common anode
digitalWrite(DIGIT_PINS[digit], LOW);
digitalWrite(DIGIT_PINS[digit], HIGH);
}
// for hardware test only
void testDisplay() {
writeShiftDigit(0, 1, false);
writeShiftDigit(1, 2, false);
writeShiftDigit(2, 3, true);
writeShiftDigit(3, 4, false);
}
void setup() {
Serial.begin(115200);
// set pin modes
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
for (int digit = 0; digit < MAX_DIGITS; digit++) {
pinMode(DIGIT_PINS[digit], OUTPUT);
digitalWrite(DIGIT_PINS[digit], HIGH); // start with digits off
}
}
void loop() {
if (millis() - prev_cnt_time >= CNT_INTERVAL) {
prev_cnt_time = millis();
countVal++;
if (countVal > 9999) countVal = 0;
}
updateDisplay(countVal, DP_POS);
//testDisplay();
}