A function to display a number 0-342 in a (semi?) human readable format

Features:

  • Numbers up to 7 are instantly readable
  • Numbers up to 50 can be read by a human with a little head math (or practice)
  • Numbers up to 342 can be read by a human with a little calculation
  • Can be read at any orientation (don’t need to know which face is 0)
  • Number is shown instantly and atomically - no animations
  • Uses only fully saturated primary colors (no guessing “is that magenta or fuchsia?”)
  • Straightforward code
  • Possible to visually see changing values for patterns and direction

Try the included demo to get a feel for how the numbers count up. You get used to it pretty quick.

LMK if you use it or if you have any questions or suggestions or problems!

-josh

// Display a number 0-342 on the LEDs
// The number is shown in base 7 format with red, green, 
// and blue being the 1's, 7's, and 49's places respecitively
// A 0 digit is shown as OFF. Digits 1-6 are shown as 1-6 LEDs
// lit with the place color. 
//
//   0 = All Off
//   1 = 1 RED
//   2 = 2 RED
//   ...
//   6 = 6 RED
//   7 = 0 RED, 1 GREEN
//   8 = 1 RED, 1 GREEN         (both on LED 0 so you see yellow)
//   9 = 2 RED, 1 GREEN         (you see 1 yellow, 1 red)
//   ...
//  48 = 6 RED, 6 GREEN         (you see 6 yellow)
//  49 = 0 RED, 0 GREEN, 1 BLUE 
//  50 = 1 RED, 0 GREEN, 1 BLUE (you see 1 purpule)
//   ...
// 341 = 5 RED, 6 GREEN, 6 BLUE (you see 1 purpule, 5 white) 
// 342 = 6 RED, 6 GREEN, 6 BLUE (6 white) 
// 
// #fin#

void showNumber( unsigned x ) {
  
    // We are the root, so display the accumulated tile count

    // Deconstruct the count "digits" into base 7 for display on our 6 LED screen (0 digit=0 LEDs on) 
    // This also just happens to look nice since we always count ourselves, so count never 0, so screen never totally blank

    const unsigned DISPLAY_BASE = FACE_COUNT+1;

/*
    byte high   = count / (DISPLAY_BASE^2); 
    byte medium = ( count - (high * (DISPLAY_BASE^2)) ) / DISPLAY_BASE;
    byte low    = ( count - (high * (DISPLAY_BASE^2)) - (medium * DISPLAY_BASE ) ); 
*/

    byte high   =  x / (DISPLAY_BASE*DISPLAY_BASE);
    byte medium =  (x - (high * DISPLAY_BASE*DISPLAY_BASE)) / DISPLAY_BASE;
    byte low    =  x % DISPLAY_BASE; 

/*    
    setColorOnFace( BLUE , medium );
    setColorOnFace( RED  , low );
*/
    FOREACH_FACE( f ) {

      byte r=0;
      byte g=0;
      byte b=0;

      // Low 1-6 maps to faces 0-5
      // When low==0 then no red
      // Note that count never is 0 becuase we always count ourselves
      // but count can be FACE_COUNT in when case no red, but green with have 1 
      if ( (f+1) <= low ) {
        r = MAX_BRIGHTNESS_5BIT;
      }
      
      // Medium 1-6 maps to faces 0-5
      // We do not show any medium when count < FACE_COUNT
      if ( (f+1) <= medium ) {    // Only show G when we go around at least one time
        g = MAX_BRIGHTNESS_5BIT;
      }

      // High 1-6 maps to faces 0-5
      // When do not show any high when count < FACE_COUNT^2
      if ( (f+1) <= high ) {           // Only show blue when it is more than 0 (count>=36)
        b = MAX_BRIGHTNESS_5BIT;
      }

      setColorOnFace( MAKECOLOR_5BIT_RGB( r , g , b ) , f );
    
    }   
  
}

void setup() {

}

// DEMO
// Press button to count up 1
// Longpress button to clear back to 0

unsigned x=0;

void loop() {

  if (buttonPressed()) {
    x++;
  }

  if (buttonLongPressed()) {
    x=0;
  }

  showNumber(x);

}

or link to original gist

2 Likes

Tempted to call this technique RGB trinary :slight_smile:

Definitely for those that can quickly read binary clocks and the sort. Or a nice way to train your brain to learn about additive color mixing.

1 Like