Neopixel scoreboard count up via keypad

Hello there,
As i am not the professional in coding, i am seeking for help.

I can sit for weeks every evening behind my laptop, trying to change just 1 piece of code. If i get tired of it, i just walk away and try again the next day, but this one is bugging me for months now...

I am really struggling with my scoreboard, trying to count up numbers with a keypad. I am allmost shure it is just a few lines of code i need to change/add, but i am at a dead end really.

I made a basketball scoreboard with 560 ws2812b LED's. Hooked up a home made controller with 30 buttons via Keypad matrix.

I can set a number on the board with the press of a button, but for the life of me, i can't figure out how to count up from 0 to 5 with that button.

The code i show here, is just for the setting of the Period. The complete code is for score home, score guests, faults home, faults guests, period and timer.
For testing (the timer works, thanks to another thread here), i removed all irrelevant code.

If i can figure out how to count up the numbers for period, i can allso do this for the rest.

#include <FastLED.h>
#define LED_PIN1     7          // pin for score, faults, periods#define NUM_LEDS1    332        // leds for score, faults, periods
#define NUM_LEDS1    332        // leds for score, faults, periods
#define BRIGHTNESS  50          // overall brightness for scoreboard
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
#define ROWS 6                  // number of rows for controller    
#define COLS 5                  // number of cols for controller
#include <Keypad.h>

uint8_t rowPins[ROWS] = {22, 24, 26, 28, 30, 32};
uint8_t colPins[COLS] = {23, 25, 27, 29, 31};

char keys[ROWS][COLS] = {
  {'1','2','3','4','5'},
  {'6','7','8','9','0'},
  {'a','b','c','d','e'},
  {'f','g','h','i','j'},
  {'k','l','m','n','o'},
  {'p','q','r','s','t'}
};

bool lit[ROWS*COLS] = {0};
CRGB leds1[NUM_LEDS1];

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// Structure of a number in segments
#define SegmentA 8
#define SegmentB 16
#define SegmentC 48
#define SegmentD 40
#define SegmentE 32
#define SegmentF 0
#define SegmentG 24

// What LED segments are needed for numbers?
//    Segments orientation: H V V H V V H                         
//           Segments used: A B C D E F G      For number:
byte SegmentNumbers[10][7] = { { 1,1,1,1,1,1,0 },   // 0
                               { 0,1,1,0,0,0,0 },   // 1
                               { 1,1,0,1,1,0,1 },   // 2
                               { 1,1,1,1,0,0,1 },   // 3
                               { 0,1,1,0,0,1,1 },   // 4
                               { 1,0,1,1,0,1,1 },   // 5
                               { 1,0,1,1,1,1,1 },   // 6
                               { 1,1,1,0,0,0,0 },   // 7
                               { 1,1,1,1,1,1,1 },   // 8
                               { 1,1,1,1,0,1,1 } };   // 9

// Horizontal/Vertical number of LEDs per segment
#define SegmentHSize 8
#define SegmentVSize 8 

// Total number of LEDs per number
#define TotalSegmentSize (3*SegmentHSize)+(4*SegmentVSize)
      
#define StartLEDPeriod           266

void SetPeriod(int StartLED, CRGB PeriodColor, int Period) {
  for (int SetPeriod=0; SetPeriod<5; SetPeriod++) {
      }
    SetDigit1(StartLED, PeriodColor, Period);
    FastLED.show();
}

void SetDigit1(int StartLED, CRGB DigitColor, int DigitValue) {
  //SetDigitDark(StartLED); // set LED to dark, do not make this change visible yet (avoid flicker)
  
  if( SegmentNumbers[DigitValue][0]==1 ) { SetSegment(StartLED+SegmentA, SegmentHSize, DigitColor); } // A = horizontal
  if( SegmentNumbers[DigitValue][1]==1 ) { SetSegment(StartLED+SegmentB, SegmentVSize, DigitColor); } // B = vertical
  if( SegmentNumbers[DigitValue][2]==1 ) { SetSegment(StartLED+SegmentC, SegmentVSize, DigitColor); } // C = vertical
  if( SegmentNumbers[DigitValue][3]==1 ) { SetSegment(StartLED+SegmentD, SegmentHSize, DigitColor); } // D = horizontal
  if( SegmentNumbers[DigitValue][4]==1 ) { SetSegment(StartLED+SegmentE, SegmentVSize, DigitColor); } // E = vertical
  if( SegmentNumbers[DigitValue][5]==1 ) { SetSegment(StartLED+SegmentF, SegmentVSize, DigitColor); } // F = vertical
  if( SegmentNumbers[DigitValue][6]==1 ) { SetSegment(StartLED+SegmentG, SegmentHSize, DigitColor); } // G = horizontal
}

void SetSegment(int StartLED, int LEDCount, CRGB SegmentColor) {
  for(int i=0; i<LEDCount; i++) {
    leds1[StartLED+i] =SegmentColor;
  }
}

void setup() {
  FastLED.addLeds<LED_TYPE, LED_PIN1, COLOR_ORDER>(leds1, NUM_LEDS1).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(  BRIGHTNESS );      // Set overall brightness
}

void loop() {
    char key = keypad.getKey();
  if (key == 'g') {
    for (int Period=0; Period<5; Period++) {
    SetPeriod(266, CRGB::Blue, (Period));
    }
  }
     FastLED.show();
 
}
    

If i push button "g" with the above code, an "8" lights up, what i do not understand.

If i change the code to :

void loop() {
    char key = keypad.getKey();
  if (key == 'g') {
    for (int Period=0; Period<5; Period++) {
    SetPeriod(266, CRGB::Blue, 4);
    }
  }


a "4" lights up (what i understand!)

If i change the code to :

void SetPeriod(int StartLED, CRGB PeriodColor, int Period) {
    SetDigit1(StartLED, PeriodColor, Period);
    FastLED.show();
}

void loop() {
    char key = keypad.getKey();
  if (key == 'g') {
    SetPeriod(266, CRGB::Blue, 4);
    }
     FastLED.show();

still it shows a "4".

As far as i think, i have to tell the code to add a number via a for loop, but whatever i try (and i tried a lot) it won't work.

Lots of examples on the internet, but they all use button-pins, not a keypad.
Is there someone who can set me in the right direction? If i understand this piece of code, i think i can work it out for the rest of my scoreboard too.

I am not asking for THE solution, but a guidance in the right direction.
I tried NoiascaNeopixelDisplay, but this allso uses button-pins.
If the complete code is desired, i will add it.
Thanks for helping out.

void loop() {
  char key = keypad.getKey();
  if (key == 'g') {
    for (int Period = 0; Period < 5; Period++) {
      SetPeriod(266, CRGB::Blue, (Period));
    }
  }
  FastLED.show();
}

You need to call FastLED.show() for each value of Period, and in this code add a call to delay() so you have time to see each number. The way you have it written, for each value of Period you are changing the pattern in the LED buffer, but only displaying the last value.

I was trying to avoid using delay, as it affects the time pressing the keypad too. I may have to start over again to change the code in something more simple then.

Admirable and important. Sometimes, however, even the heaviest of the heavies will throw a delay on into a simple sketch just to check on the logic.

So try it. If you display a new number, and show it, then delay for 500 or 1000 milliseconds, you can check that logic.

Once that works, you have a different problem, getting rid of the delay.

Was it needed in the full,program where your counting stuff will go?

a7

I was only using the delay() for the purpose of your test code. The way you have this sketch written, you are counting from 0 to 4 before doing another read of the keypad, if you want to be able to detect a key press between numbers, and perform some action based on that key press, the code would need to be heavily modified.

@fredrossi046, take a look at this tutorial


Its *loop*() function has two parts.

One to reliably do something once per button press. here it just counts them.

The other to do something with the count of the button presses.

If your digit display thing works, you shoudd be able to exploit the programming patterns to count and display button presses.

There is one short delay() in the code, used in some algorithms for debouncing switch contacts. If even that short delay is objectionable. which it might well be in some use cases, it can be eliminated using a different debounce scheme.

a7

Tried with delay, now i indeed can see what happens if i press. I can get the logic to work, but it would involve a whole lot of extra code in the end i guess. In the original code it is not needed, and hope to keep it that way, but i get your point.

I think this is going to be the right way to do it, starting over. I think it can be simplified, but not with the way i have it written right now. Changing my code will probably give me more problems than solutions.

I was just rereading the code you posted

void SetPeriod(int StartLED, CRGB PeriodColor, int Period) {
    SetDigit1(StartLED, PeriodColor, Period);
    FastLED.show();
}

void loop() {
    char key = keypad.getKey();
  if (key == 'g') {
    SetPeriod(266, CRGB::Blue, 4);
    }
     FastLED.show();
//... 

This will display '4' because you pass 4 to the SetPeriod(). I think you did the same thing elsewhere.

The third parameter is the number to display, it should be the variable used in the for loop if you were wanting 0,1,2 &c. to appear.

Of course you still have to show() the strip, and give humans some time to see the new pixels before stepping along. As you have found.

a7

I understand, that is part of my headache. First i thought i could change the numbers with something like "if" and "else", but without luck. Looking at your link now, it makes me think even more i can better start over. Not giving up, but i do not think it is doable to make a functional code. This is just a testing code, after this there are a whole lot of extra functions to add with the keypad, not the best idea i think.

Fortunately the Keypad library handles the debounce and state change detection itself. getKey() will only return a keypress once for each key press, although if you do have a long delay the key needs to actually be pressed when getKey() is called.

If what you want is to increment the number once for each press of the 'g' key, then you need a variable that will persist past the end of loop, and just add 1 to it each time the 'g' is pressed.

byte period = 0;

void loop() {
  char key = keypad.getKey();
  if (key == 'g') {
    period++;
    if (period > 5) { //resets period to 0 when the value exceeds 5
      period = 0;
    }
    SetPeriod(266, CRGB::Blue, period);
  }
  FastLED.show();
}

This will be a little unbelievable, but i tried this quite a lot of times to no avail.
I don't know exactly what i changed in code at the time, but i am sure i did not include the byte period.

Started this journey allmost 2 years ago, and not willing to give up.
This is exactly what i want, just have to add a FastLED.clear after period++, else it will add the numbers, but not clear after each press, so the display gets "filled".

You probably won't believe how happy this makes me!
I wanted a hint, not the solution, but now i went from 50% finishing my board to 90%!

Gonna make some changes to the original complete code, then show it here so you helpers can see what i want to achieve. Just for reference.

There is a lot more coding to do to get the rules of the game in the code, but keeps me from the streets...

Not yet saying i am done, but this helps a freaking lot!
THANKS!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.