1

First off, I'm not really sure if it belongs here on on electronics stackexchange, since it involves an Arduino, some code and a small circuit.

I'm trying to create a simple countdown timer using a 7 segment display and two 74HC595N shift registers. The shift register connected to DATA_PIN should set a HIGH value for those segments enabled for a given digit position, while the second one in line enabled one common pin at a time (it's a common cathode display btw)

Here's my code:

#define LATCH_PIN 4
#define CLOCK_PIN 5
#define DATA_PIN 6

#define MILLIS_PER_SECOND 1000
#define SECONDS_PER_MINUTE 60

// Visual feedback when digit encoding goes wrong
#define INVALID_INDICATOR 0b11001001

int remainingSeconds = 128;
int enabledCommonPin = 0; // Ranges 0-4
unsigned long lastElapsedSecond;

void setup() {
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);
}

byte getSegmentsForDigit(int digit) {
  // Segments are encoded [Dp, G, F, E, D, C, B, A]
  switch (digit) {
    case 0: return 0b00111111;
    case 1: return 0b00000110;
    case 2: return 0b01011011;
    case 3: return 0b01001111;
    case 4: return 0b01100110;
    case 5: return 0b01101101;
    case 6: return 0b01111101;
    case 7: return 0b00000111;
    case 8: return 0b01111111;
    case 9: return 0b01101111;
    default: return INVALID_INDICATOR;
  }
}

byte getSegments() {
  int seconds = remainingSeconds % SECONDS_PER_MINUTE;
  int minutes = remainingSeconds / SECONDS_PER_MINUTE;
  switch (enabledCommonPin) {
    case 0: return getSegmentsForDigit(minutes / 10);
    case 1: return getSegmentsForDigit(minutes % 10);
    case 2: return remainingSeconds % 2 == 0 ? 0b10000000 : 0b00000000;
    case 3: return getSegmentsForDigit(seconds % 10);
    case 4: return getSegmentsForDigit(seconds / 10);
    default: return INVALID_INDICATOR;
  }
}

void loop() {
  // subtract a second if at least 1000ms passed since lastElapsedMillis
  if (millis() - lastElapsedSecond >= MILLIS_PER_SECOND) {
    remainingSeconds = remainingSeconds == 0 ? 0 : (remainingSeconds - 1);
    lastElapsedSecond += MILLIS_PER_SECOND;
  }

  // Use the 5 most significant bits for enabled digit
  byte enabledDigit = 1<<(7 - enabledCommonPin);
  byte enabledSegments = getSegments();

  digitalWrite(LATCH_PIN, LOW);
  // Bit-flip enabledDigits since display is common cathode
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, ~enabledDigit);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, enabledSegments);
  digitalWrite(LATCH_PIN, HIGH);

  // Set next commonPin
  enabledCommonPin = (enabledCommonPin + 1) % 5;
}

For completeness, I drew a schematic of my setup. To reduce space, I left out the segment display. All common pins are connected to SR2 through a 510Ohm resistor. My display has a pin for the Dp segment and one to enable the time separator/colon. I connected those two, so should I accidentally enable the time separator on the wrong position, the decimal point should light up.

schematic

simulate this circuit – Schematic created using CircuitLab

When I power up the Arduino, the display shows an unexpected composition of segments (i.e. all decimal points are enabled) I would at least expect to see a change every second, but even that is not happening. I double checked the wires on my breadboard, both clocks and latches are in sync.

I noticed the unused pins on SR2 are not connected. The datasheet suggested I should either connect them to Gnd or Vcc, but that didn't help.

Is there something wrong with my code or circuit perhaps? I'm trying to learn how this would work, so please don't advice me to use libraries or ICs like the MAX7219.

Thanks in advance.

EDIT

I've tried Juraj's suggestion and swapped the lines calling shiftOut(). The result was that none of the segments were enabled.

I did some experiment with writing to Serial what values were shifted out in combination with the value of remainingSeconds. Both the enabledDigit and segments values matched with what I expected.

I also tried to shiftOut some hard-coded values for segments, but I still saw the same segments enabled. I thought maybe the IC could be damaged inside, so I replaced both with two other SN74HC595N's. The result was, unfortunately, no difference.

Could this mean there is something wrong with my Arduino?

  • upvote for well presented question – jsotola Jan 11 at 0:27
  • send segments first – Juraj Jan 11 at 6:22
  • @Juraj That could explain why for each digit I see the same segments enabled, but I thought the data I shiftOut() first gets shifted down the chain of registers? I'll give it a try – gatukok Jan 11 at 9:12
  • a set register sends the data to the next – Juraj Jan 11 at 9:36
  • try all zeros or all 1 for enabledDigit – Juraj Jan 12 at 19:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.