7-Seg LED Display Addressing Question (HT16K33)

Hello all!

EDIT: Solution posted in reply #6. Mystery solved. Many thanks!

I've been swimming around in these forums for a while now learning as I go, but I've recently hit a wall, and I'm hoping someone might be able to help me out or point me in the right direction.

I'm new to coding and programming as of mid-April, and am writing this program in stages, tackling one goal/issue at a time. I've taken several different programs, from different people, and spliced them together to create what you see below. Source links for the original programs are included in the comments.

EDIT: The full program has too many lines of code to include in its entirety, and I know how much everyone loves program snip-its, so I hope that the file I've attached works. The code posted below is the section where I'm having some trouble, for what it's worth.

// Print the time to the seven-segment LED display.
void DisplayTime() {

  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  ReadRTCTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

  hours = hour;
  minutes = minute;
  seconds = second;

  // Show the time on the display by turning it into a numeric value,
  // like 3:30 turns into 330, by multiplying the hour by 100 and then adding the minutes.
  int TimeValue = hours * 100 + minutes;

  // Set PM flag. <-- This is the code that is presenting issues/not working properly.
  // I'm not sure if maybe I have it in the wrong spot, or if it's conflicting with other code.
  if (!TIME_24_HOUR && hours >=12) {
    ClockDisplay.writeDigitRaw(2, 0x04);
  }

  // 24-hour to 12-hour conversion.
  if (!TIME_24_HOUR) {
    if (hours > 12) {                      // 00:00 = midnight.
      TimeValue -= 1200;
    }
    else if (hours == 0) {                 // 12:00 = noon.
      TimeValue += 1200;
    }
  }
  
  // Print the time value to the seven-segment LED display.
  ClockDisplay.print(TimeValue, DEC);

 // Add zero padding when in 24-hour mode and it's midnight.
  if (TIME_24_HOUR && hours < 10) {
    ClockDisplay.writeDigitNum(0, 0);      // Pad ten's hour zero.
    if (hours == 0) {
      ClockDisplay.writeDigitNum(1, 0);    // Pad one's hour zero.
    }
  }
  if (TIME_24_HOUR && minutes < 10) {
    ClockDisplay.writeDigitNum(3, 0);      // Pad ten's minute zero.
  }

  // Blink the center colon. <-- Not sure if this part is giving issues for the PM flag.
  if ((seconds % 2) == 0) {
    ClockDisplay.drawColon(true);
  }
  else if ((seconds % 2) == 1) {
    ClockDisplay.drawColon(false);
  }

  // Now push out to the display the new values that were set above.
  ClockDisplay.writeDisplay();
}

What I'm trying to do right now is create a PM flag for the 12-hour setting, which should be pretty simple. I've created a condition for which the LED in question should light only for PM time. The issue I'm having is that when I incorporate this code into the DisplayTime function, the LED (lower left dot) does not light, and nothing else changes.

EDIT: If I place the code in the DisplayTime function, followed by writeDisplay(); to force the code to the display, the center colon flashes as intended while the PM LED flickers on and off seemingly randomly.

EDIT: If I place the code in a different function, the opposite happens, with the PM LED lit correctly and the colon flickering on and off in rhythm.

I think there may be an addressing conflict within the LED display module/backpack, but I a haven't figured it out yet. I'm calling drawColon(true/false); with a set of conditions to trigger the blinking center colon.

I've consulted Adafruit's 1.2" seven-segment display guide and many different sites and forum threads, but I'm clearly missing something. Everything else in this program works perfectly. I've not yet trimmed the fat, so there are most certainly superfluous lines of code here and there. But the program as it exists does everything else that I've wanted it to do up until this point.

I am using an Arduino Nano (running IDE 1.8.9) with Adafruit's DS3231 RTC breakout and 1.2" seven-segment display w/backpack (HT16K33).

This is just a fun exercise for me, and I've been doing a lot of Googling to figure out what I could be missing. Any help would be greatly appreciated!

My apologies for the super long post, and if this is not the appropriate sub-forum (I saw a similar post here before).

  • JB

Clock_Version_2.4.ino (12.3 KB)

Probably, instead of using writeDigitRaw() to add the PM dot, you should write the dot with the writeDigitNum() you use to output the hours digit number 2. The dot is the third parameter, set to true if you want the dot displayed.
It is possible that your attempt to add the dot with the writeDigitRaw() function is being superseded by the writeDigitNum() function with the dot parameter set to its default false value.

6v6gt:
Probably, instead of using writeDigitRaw() to add the PM dot, you should write the dot with the writeDigitNum() you use to output the hours digit number 2.

Thanks for the suggestion, 6v6gt. Unfortunately, it didn’t resolve the issue. I also switched drawColon to writeDigitNum, and I’m getting slightly different results.

Currently, the LED turns on after 12PM but the colon stops blinking (but is on with no flickering). Before 12PM, the LED is off as expected, and the colon blinks normally.

I’ll elaborate more when I get home tonight and have access to the setup.

The problem appears to be the sequence in which you are updating the various parts of the display. Later updates are over-writing some parts of the earlier updates. Looking at how the library works, is not clear that there is any sequence of those updates will work. Something will always over-write something else...

But using 6v6gt's suggestion should have fixed it, I think, because it avoids over-writing. So post your updated code. I don't think you can have done it as 6v6gt imagined.

Thank you for the response, PaulRB. It's certainly possible that I've implemented 6v's suggestion incorrectly. I've attached the updated program file, plus the more relevant code below.

// Print the time to the seven-segment LED display.
void DisplayTime() {

  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  ReadRTCTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);

  hours = hour;
  minutes = minute;
  seconds = second;

  // Show the time on the display by turning it into a numeric value,
  // like 3:30 turns into 330, by multiplying the hour by 100 and then adding the minutes.
  int TimeValue = hours * 100 + minutes;

  // Print the time value to the seven-segment LED display.
  ClockDisplay.print(TimeValue, DEC);

  // Blink the center colon.
  if ((seconds % 2) == 0) {
    ClockDisplay.drawColon(true);
  }
  else if ((seconds % 2) == 1) {
    ClockDisplay.drawColon(false);
  }

/////////////////////////////////////////// 24-HOUR TIME //////////////////////////////////////////

// Add zero padding when in 24-hour mode.
  if (TIME_24_HOUR && hours < 10) {
    ClockDisplay.writeDigitNum(0, 0);       // Pad ten's hour zero.
    if (hours == 0) {
      ClockDisplay.writeDigitNum(1, 0);     // Pad one's hour zero.
    }
  }
  if (TIME_24_HOUR && minutes < 10) {
    ClockDisplay.writeDigitNum(3, 0);       // Pad ten's minute zero.
  }

/////////////////////////////////////////// 12-HOUR TIME //////////////////////////////////////////

  // Display PM flag.
  if (!TIME_24_HOUR && hours >= 12) {
    //ClockDisplay.writeDigitNum(2, 0x04, true);  // <-- This does not work.
    ClockDisplay.writeDigitNum(3, 1);             // <-- This does work.
  }

  // 24-hour to 12-hour conversion.
  if (!TIME_24_HOUR) {
    if (hours > 12) {                       // (Midnight = 00:00.)
      TimeValue -= 1200;
    }
    else if (hours == 0) {                  // (Noon = 12:00.)
      TimeValue += 1200;
    }
  }
  
  // Now push out to the display the new values that were set above.
  ClockDisplay.writeDisplay();
}

I tested the program without the PM flag code included, and everything still works perfectly. When added, the PM code either doesn't have an affect, or it exhibits the behavior I mentioned above.

Joebob105:
Currently, the LED turns on after 12PM but the colon stops blinking (but is on with no flickering). Before 12PM, the LED is off as expected, and the colon blinks normally.

You'll notice that the commented line in the PM code is the intended line, while the line underneath that is a test. This obviously doesn't debunk your theories that some of the code is overwriting/taking precedence over previous code. But it does work, and makes me feel like less of an idiot. When implemented, a 1 is written to the ten's place of the minutes, only in 12-hour time, and stays that way while the clock increments past 12PM, as expected.

If you're able to spot the conflict I would love to know what I'm missing, genuinely. I don't doubt that it might be something simple or stupid, I'm just almost at the point where I need to move on and revisit this at a later date. There's a lot more to add, and this is not a crucial element.

EDIT: I've just run another test, successfully depending on the POV. Instead of trying to blink the center colon with the PM flag triggered, I set the blinking code's output to alternate writing a "1" to positions 1 and 3 (00:00) once per second, using the same conditions. This works, with the PM LED lit for PM time, while the "1" trades back and forth regardless of the time. I can't seem to replicate this behavior for the colon.

Thanks again for your time!

Clock_Version_2.4.1.ino (11.9 KB)

So this is the display?
led_matrix_2013_04_12_IMG_1606-1024.jpg
From the guide,

If you need more control, you can call writeDigitNum(location, number) - this will write the number (0-9) to a single location. Location #0 is all the way to the left, location #2 is the colon dots so you probably want to skip it, location #4 is all the way to the right.

To control the colon and decimal points, use the writeDigitRaw(location, bitmap) function. (Note that both dots of the center colon are wired together internal to the display, so it is not possible to address them separately.) Specify 2 for the location and the bits are mapped as follows:

0x02 - center colon (both dots)
0x04 - left colon - lower dot
0x08 - left colon - upper dot
0x10 - decimal point

And it's the lower dot of the left hand colon you want to use as the pm indicator?

led_matrix_2013_04_12_IMG_1606-1024.jpg

Here's the problem, it's the library code:

void Adafruit_7segment::drawColon(boolean state) {
  if (state)
    displaybuffer[2] = 0x2;
  else
    displaybuffer[2] = 0;
}

When you use drawColon(), it over-writes the other bits in digit 2 which control the other dots. This is why your pm indicator gets over-written.

Stop using drawColon(). Instead, use

ClockDisplay.writeDigitRaw(2, pm | colon);

after you have set "pm" to 0x04 or zero and "colon" to 0x02 or zero.

I can’t thank you enough, for taking the time to look into this and for finding a solution. It worked perfectly, and I feel like a real idiot for not finding the conflict in the library file.

Good to know that in some of my attempts I was close. I didn’t know this was an option:

ClockDisplay.writeDigitRaw(2, pm | colon);

I’m still learning the ropes, slowly.

I'll probably be back with other questions in the future, but a huge thanks for now!

I didn't know this was an option...

No problem, glad to help. It's not magic, the "|" is simply the C operator for binary bit-wise OR.