Large keyboard with individual led for each button

Hello, I have keypad with 98 buttons and 98 leds. Buttons connected as a matrix 14x7, leds as well. Led should be HIGH the appropriate pressed button.

I’m going to use Keyboard library MultiKey example as a core. This one:

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the kpd

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

unsigned long loopCount;
unsigned long startTime;
String msg;


void setup() {
    Serial.begin(9600);
    loopCount = 0;
    startTime = millis();
    msg = "";
}


void loop() {
    loopCount++;
    if ( (millis()-startTime)>5000 ) {
        Serial.print("Average loops per second = ");
        Serial.println(loopCount/5);
        startTime = millis();
        loopCount = 0;
    }

    // Fills kpd.key[ ] array with up-to 10 active keys.
    // Returns true if there are ANY active keys.
    if (kpd.getKeys())
    {
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                    case PRESSED:
                    msg = " PRESSED.";
                break;
                    case HOLD:
                    msg = " HOLD.";
                break;
                    case RELEASED:
                    msg = " RELEASED.";
                break;
                    case IDLE:
                    msg = " IDLE.";
                }
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.println(msg);
            }
        }
    }
}  // End loop

First question is how I can declare 98 keys? It seams that I haven’t enough unique symbols.

And the second one is how I can identify leds to its buttons? I have driver for leds, wich means that I need just send the Serial.print(“comand”); with current led witch should be HIGH for a 3 seconds.

Thanks!

First question is how I can declare 98 keys? It seams that I haven't enough unique symbols.

Hmm isn't the first question how are you going to connect 98 inputs to the Arduino? Have you already solved this issue?

If not then looks like you may have to read them in using a few shift registers.

As for mapping, once you have all the inputs coming in, it should be relatively trivial to map inputs to outputs.

not really, its 21 inputs for buttons and 3 pins for leds driver.

thanks for issue!

t_serkov:
Buttons connected as a matrix 14x7…

First question is how I can declare 98 keys? It seams that I haven’t enough unique symbols.

And the second one is how I can identify leds to its buttons?

First, find the line in the Keypad.h file that says:

#define MAPSIZE 10        // MAPSIZE is the number of rows (times 16 columns)

and change it to:

#define MAPSIZE 14        // MAPSIZE is the number of rows (times 16 columns)

to support more than 10 rows.

Supporting 98 keys can be accomplished by using key codes instead of trying to find unique symbols. In the MultiKey example you would change the line that tests for unique symbols:

Serial.print(kpd.key[i].kchar);

and make it use key codes instead:

Serial.print(kpd.key[i].kcode);

kcode is a unique number (16 bit signed int) assigned to each key starting with 0 at the top-left and increasing to the right and down with the bottom-right key having the highest keycode. For example, a 4x3 keypad would have the keycodes:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

Finally, I would need to see the command that turns on each LED before I can tell you how to associate each key with its LED. But if the LED command uses a number then you can just use the kcode as the LED number.

Let me know if that helps?

wow thanks! i'll try it and get back with result!

I thought that I could make an array with 98 leds states and call the procedure witch turn led for a three seconds and of. And send impuls to driver comething like Serial.print("Tern led nember " + numLed +"for a three seconds");

your solution works perfectly! thank you very much!

but I have problem with turn the led on and off. It channged states after clicks but not after 3 seconds

/* @file MultiKey.ino
|| @version 1.0
|| @author Mark Stanley
|| @contact mstanley@technologist.com
||
|| @description
|| | The latest version, 3.0, of the keypad library supports up to 10
|| | active keys all being pressed at the same time. This sketch is an
|| | example of how you can get multiple key presses from a keypad or
|| | keyboard.
|| #
*/

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
signed int keys[ROWS][COLS] = {
  {0, 1, 2, 3},
  {4, 5, 6, 7},
  {8, 9, 10, 11},
  {12, 13, 14, 15}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the kpd

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

unsigned long loopCount;
unsigned long startTime;
String msg;
bool ledFlag = false;
//int ledState = LOW;
long previousMillis = 0;


void setup() {
  Serial.begin(9600);
  loopCount = 0;
  startTime = millis();
  msg = "";
}

int ledState[] = {
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW,
  LOW
};



void loop() {

  /*
    loopCount++;
    if ( (millis() - startTime) > 5000 ) {
      Serial.print("Average loops per second = ");
      Serial.println(loopCount / 5);
      startTime = millis();
      loopCount = 0;
    }
  */
  // Fills kpd.key[ ] array with up-to 10 active keys.
  // Returns true if there are ANY active keys.
  if (kpd.getKeys())
  {
    for (int i = 0; i < LIST_MAX; i++) // Scan the whole key list.
    {
      if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
      {
        switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
          case RELEASED:
            msg = " RELEASED.";
            myLedFunction(kpd.key[i].kcode);
            Serial.println(kpd.key[i].kcode);
            //ledFlag = true;
        }
        break;
        Serial.print("Key ");
        Serial.print(kpd.key[i].kcode);
        Serial.println(msg);
      }
    }
  }


void myLedFunction(int ledNum) 
  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis > 500) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState[ledNum] == LOW) {
      ledState[ledNum] = HIGH;
      Serial.print("high");
    }
    else {
      ledState[ledNum] = LOW;
      Serial.print("low");
    }
    //ledFlag = false;
    // set the LED with the ledState of the variable:
    //digitalWrite(ledPin, ledState);
    Serial.println(ledNum, ledState[ledNum]);
  }
}  // End loop

All your LEDs are sharing the same previousMillis, so if you press one button, then press another it will reset the previousMillis back to current millis. Surely you want separate timers for each?

no, I don't)

I understood what the problem is but still can't figure out how to do this

Yo're not really giving me any helpful feedback, so not sure what its doing or not doing that it should be doing.

I do know that you check time passed in a function that appears to only be hit when the key state is changed. So looks like it will never elapse that time.

Sorry, well I need that each specifik led was HIGH when the appropriate button is pressed.And it shouldn't turn of if I pressed another button, so each led should be HIGH for a 3 seconds. So I think that i should check time in a loop maybe?

Try something like this, I don’t have the hardware to test it. Also you’ll need to change it to use whatever command your led driver expects, the one that is copied into buffer variable.

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
signed int keys[ROWS][COLS] = {
  {0, 1, 2, 3},
  {4, 5, 6, 7},
  {8, 9, 10, 11},
  {12, 13, 14, 15}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the kpd

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

unsigned long loopCount;
unsigned long startTime;
String msg;
long previousMillis = 0;

#define NUM_LEDS 16
unsigned long led_time[NUM_LEDS];


void setup() {
  Serial.begin(9600);
  loopCount = 0;
  startTime = millis();
  msg = "";
  memset( led_time, NULL, sizeof( led_time ));
}

void update_leds();

void loop()
{
  if (kpd.getKeys())
  {
    for (int i = 0; i < LIST_MAX; i++) // Scan the whole key list.
    {
      if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
      {
        switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
          case RELEASED:
            {
              msg = " RELEASED.";
              led_time[kpd.key[i].kcode] = 3000;  // 3 seconds ...
            }
        }
        break;
        Serial.print("Key ");
        Serial.print(kpd.key[i].kcode);
        Serial.println(msg);
      }
    }
  }

  update_leds();
}

void update_leds()
{
  unsigned long time_passed = millis() - previousMillis;
  char buffer[32];

  for ( int i = 0; i < NUM_LEDS; i++ )
  {
    led_time[i] -= time_passed;

    if ( led_time[i] > 0 )
    {
      sprintf( buffer, "%d HIGH" );   // or whatever the command is to turn them on.
      Serial.println( buffer );
    }
    else
    {
      led_time[i] = 0;
      sprintf( buffer, "%d LOW" );    // or whatever the command is to turn them off.
      Serial.println( buffer );
    }
  }
}

thank you!! but it does't work(
It's send me LOW several times and then HIGH forever and doesn't react on buttons

Sorry, missed out a very much needed line, replace your function with this one:

void update_leds()
{
  unsigned long time_passed = millis() - previousMillis;
  char buffer[32];

  for ( int i = 0; i < NUM_LEDS; i++ )
  {
    led_time[i] -= time_passed;

    if ( led_time[i] > 0 )
    {
      sprintf( buffer, "%d HIGH" );   // or whatever the command is to turn them on.
      Serial.println( buffer );
    }
    else
    {
      led_time[i] = 0;
      sprintf( buffer, "%d LOW" );    // or whatever the command is to turn them off.
      Serial.println( buffer );
    }
  }

  previousMillis = millis();
}

same thing(

Have a read through these and tell me if any are true or false:

If you press no button, no light comes on.

If you press a button, a light comes on, and stays on for 3 seconds before turning off.

Also have you got the led driver taking commands or are you just reading the serial monitor? Because it will be printing out 16 values of HIGH/LOW each loop.

True

True

I have no driver for now, so I use serial monitor.

True

True

I have no driver for now, so I use serial monitor.

So pressing one button works perfectly well then?

Is the issue when you press another/more buttons?