Go Down

Topic: Editing a Library (Read 1 time) previous topic - next topic

euphoricnoise

So I just found out there were just some syntax errors from the code I got from the link (that was really silly of me).

However, the problem now is that no output is coming out. What I'm trying to achieve is outputting multiple keypresses at the same time.

Here is the original code:
Code: [Select]
bool Keypad::scanKeys() {
boolean anyKey=false;

// Scan keypad once every XX mS. This makes the loop() count
// go from about 4,000 loops per second to about 40,000.
if ( (millis()-startTime)>debounceTime ) {

// When sharing row pins with other hardware they may need to be re-intialized.
for (byte r=0; r<sizeKpd.rows; r++) {
pin_mode(rowPins[r],INPUT_PULLUP);
pin_write(rowPins[r],HIGH); // Enable the internal 20K pullup resistors. (Arduino<101)
}

// Scan the entire keypad/keyboard and provide a key pressed status to
// setKeyState().  Also, determine which keys are being pressed.
for (byte c=0; c<sizeKpd.columns; c++) {
pin_mode(columnPins[c],OUTPUT);
pin_write(columnPins[c], LOW); // Begin column pulse output.
for (byte r=0; r<sizeKpd.rows; r++) {
bitWrite(bitMap[r], c, !pin_read(rowPins[r]));  // keypress is active low but invert to high.
if (bitRead(bitMap[r], c) == 1)
anyKey = true;
}
// Set pin to high impedance input. Effectively ends column pulse.
pin_write(columnPins[c],HIGH);
pin_mode(columnPins[c],INPUT);
}
updateList(); // Manage the Active-Key list. Adding/Removing active keys.

// Reset debounceTime delay.
startTime = millis();
}
return anyKey; // Report if any keys are active.
}


Now here's the new code:
Code: [Select]
bool Keypad::scanKeys() {
static unsigned int allKeys = 0;
byte curKey = 0;
boolean anyKey;

// Scan keypad once every XX mS. This makes the loop() count
// go from about 4,000 loops per second to about 40,000.
initializePins();

for (int c = 0; c < sizeKpd.columns; c++) {
pinMode(columnPins[c], OUTPUT);
digitalWrite(columnPins[c], LOW);
for (int r = 0; r <sizeKpd.rows; r++) {
curKey = digitalRead(rowPins[r]);
allKeys += curKey;
if (curKey == 0) curKey = keymap[c+(r*sizeKpd.columns)];

if (r==(sizeKpd.rows-1) && c==(sizeKpd.columns-1)) {
if (allKeys == (sizeKpd.rows*sizeKpd.columns))
anyKey = OPEN;
else
anyKey = CLOSED;
}
}
pinMode(columnPins[c], INPUT);
digitalWrite(columnPins[c], HIGH);
}
allKeys = 0;
return anyKey;
}

pylon

Post the whole code, this doesn't work if you have changed just this bit.

Quote
However, the problem now is that no output is coming out.


Define what that means. For which input you get what output.

euphoricnoise


Post the whole code, this doesn't work if you have changed just this bit.

Quote
However, the problem now is that no output is coming out.


Define what that means. For which input you get what output.



Alright, sorry for not posting the right stuff for you guys to work with, I'm just not thinking straight right now.
MY INTENTIONS:
-I am trying to build a 16 buttonpad MIDI controller using the sparkfun 4x4 board (https://www.sparkfun.com/products/7835?)
-Right now, the controller can take in one button input and output one thing (monophonic)
-I am trying to program the arduino so more than one button input can be taken in (polyphonic)
-With the new code for the library, nothing is coming out correctly

Here's the whole original code (library):
Code: [Select]
#include <Keypad.h>

// <<constructor>> Allows custom keymap, pin configuration, and keypad sizes.
Keypad::Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols) {
   rowPins = row;
   columnPins = col;
   sizeKpd.rows = numRows;
   sizeKpd.columns = numCols;

   begin(userKeymap);

   setDebounceTime(10);
   setHoldTime(500);
keypadEventListener = 0;

   initializePins();

startTime = 0;
}

// Let the user define a keymap - assume the same row/column count as defined in constructor
void Keypad::begin(char *userKeymap) {
   keymap = userKeymap;
}

// Returns a single key only. Retained for backwards compatibility.
char Keypad::getKey() {
if (scanKeys() && (key[0].kstate==PRESSED) && key[0].stateChanged)
return key[0].kchar;
return NO_KEY;
}

bool Keypad::getKeys() {
if (scanKeys()) {
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].stateChanged) {
return true;
}
}
}
return false;
}

// Private
// Scan the keypad.  Return whether a key has been pressed or not.
bool Keypad::scanKeys() {
boolean anyKey=false;

// Scan keypad once every XX mS. This makes the loop() count
// go from about 4,000 loops per second to about 40,000.
if ( (millis()-startTime)>debounceTime ) {

// When sharing row pins with other hardware they may need to be re-intialized.
for (byte r=0; r<sizeKpd.rows; r++) {
pin_mode(rowPins[r],INPUT_PULLUP);
pin_write(rowPins[r],HIGH); // Enable the internal 20K pullup resistors. (Arduino<101)
}

// Scan the entire keypad/keyboard and provide a key pressed status to
// setKeyState().  Also, determine which keys are being pressed.
for (byte c=0; c<sizeKpd.columns; c++) {
pin_mode(columnPins[c],OUTPUT);
pin_write(columnPins[c], LOW); // Begin column pulse output.
for (byte r=0; r<sizeKpd.rows; r++) {
bitWrite(bitMap[r], c, !pin_read(rowPins[r]));  // keypress is active low but invert to high.
if (bitRead(bitMap[r], c) == 1)
anyKey = true;
}
// Set pin to high impedance input. Effectively ends column pulse.
pin_write(columnPins[c],HIGH);
pin_mode(columnPins[c],INPUT);
}
updateList(); // Manage the Active-Key list. Adding/Removing active keys.

// Reset debounceTime delay.
startTime = millis();
}
return anyKey; // Report if any keys are active.
}

// Manage the key list. Any keys already on the list stay in their current slot
// and empty slots get filled with new keys.
void Keypad::updateList() {

// Delete Idle keys
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kstate==IDLE) {
key[i].kchar = NO_KEY;
key[i].stateChanged = false;
}
}

// Fill the empty slots in key[] list with new CLOSED keys.
for (byte r=0; r<sizeKpd.rows; r++) {
for (byte c=0; c<sizeKpd.columns; c++) {
boolean button = bitRead(bitMap[r],c);
char keyChar = keymap[r * sizeKpd.columns + c];
int idx = findInList (keyChar); // -1 = not on list, else returns key index
// Update any key that was found on the list.
if (idx>=0)
setKeyState (idx, button);
// Add a key to the list when the button is CLOSED.
if ((idx==-1) && button) {
// Check the whole list for an empty key slot and put it there.
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kchar==NO_KEY) {
key[i].kchar = keyChar;
key[i].kstate = IDLE;
// All keys not on the list are considered IDLE. Using setKeyState
// on new key will transition the key to the PRESSED state as expected.
setKeyState (i, button);
break; // only fill the first empty slot.
}
}
}
}
}
}

// Private
void Keypad::setKeyState(byte idx, boolean button) {
// Clear stateChanged.
key[idx].stateChanged = false;

switch (key[idx].kstate) {
case IDLE: // Waiting for a keypress.
if (button==CLOSED) {
transitionTo (idx, PRESSED);
holdTimer = millis(); } // Get ready for next HOLD state.
break;
case PRESSED:
if ((millis()-holdTimer)>holdTime) // Waiting for a key HOLD...
transitionTo (idx, HOLD);
else if (button==OPEN) // or for a key to be RELEASED.
transitionTo (idx, RELEASED);
break;
case HOLD:
// Waiting for a key to be RELEASED.
if (button==OPEN)
transitionTo (idx, RELEASED);
break;
case RELEASED:
transitionTo (idx, IDLE);
break;
}
}

// New in 2.1
bool Keypad::isPressed(char keyChar) {
for (byte i=0; i<LIST_MAX; i++) {
if ( (key[i].kchar == keyChar) && (key[i].kstate == PRESSED) )
return true;
}
return false; // Not pressed.
}

// New in 2.0
char Keypad::waitForKey() {
char waitKey = NO_KEY;
while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress.
return waitKey;
}

KeyState Keypad::getState() {
return key[0].kstate;
}

// The end user can test for any changes in state before deciding
// if any variables, etc. needs to be updated in their code.
// Useful for keypads/keyboards returning a single key only.
bool Keypad::keyStateChanged() {
return key[0].stateChanged;
}

// The number of keys on the key list, key[LIST_MAX], equals the number
// of bytes in the key list divided by the number of bytes in a key.
byte Keypad::numKeys() {
return sizeof(key)/sizeof(Key);
}

// Minimum debounceTime is 10 mS. Any lower *will* slow down the loop().
void Keypad::setDebounceTime(uint debounce) {
debounce<1 ? debounceTime=1 : debounceTime=debounce;
}

void Keypad::setHoldTime(uint hold) {
   holdTime = hold;
}

void Keypad::addEventListener(void (*listener)(char)){
keypadEventListener = listener;
}

void Keypad::transitionTo(byte n, KeyState nextState) {
key[n].kstate = nextState;
key[n].stateChanged = true;

if (keypadEventListener!=NULL)
keypadEventListener(key[0].kchar);
}

void Keypad::initializePins() {
   // Configure column pin modes and states. Row pins get configured
   // in scanKeys(). See explanation there.
   // See http://arduino.cc/forum/index.php/topic,95027.0.html for an explanation
   // of why changing the column pins to INPUTs prevents inter-column shorts.
   for (byte C=0; C<sizeKpd.columns; C++) {
       pin_mode(columnPins[C],INPUT);
       pin_write(columnPins[C],HIGH);
   }
}

// Search for a key in the list of active keys.
// Returns -1 if not found or the index into the list of active keys.
int Keypad::findInList (char keyChar) {
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kchar == keyChar) {
return i;
}
}
return -1; // No matching key in list.
}




euphoricnoise

Here's the new code (library):
Code: [Select]
#include <Keypad.h>

// <<constructor>> Allows custom keymap, pin configuration, and keypad sizes.
Keypad::Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols) {
   rowPins = row;
   columnPins = col;
   sizeKpd.rows = numRows;
   sizeKpd.columns = numCols;

   begin(userKeymap);

   setDebounceTime(10);
   setHoldTime(500);
keypadEventListener = 0;

   initializePins();

startTime = 0;
}

// Let the user define a keymap - assume the same row/column count as defined in constructor
void Keypad::begin(char *userKeymap) {
   keymap = userKeymap;
}

// Returns a single key only. Retained for backwards compatibility.
char Keypad::getKey() {
if (scanKeys() && (key[0].kstate==PRESSED) && key[0].stateChanged)
return key[0].kchar;
return NO_KEY;
}

bool Keypad::getKeys() {
if (scanKeys()) {
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].stateChanged) {
return true;
}
}
}
return false;
}

// Private
// Scan the keypad.  Rerturn whether a key has been pressed or not.
bool Keypad::scanKeys() {
static unsigned int allKeys = 0;
byte curKey = 0;
boolean anyKey;

// Scan keypad once every XX mS. This makes the loop() count
// go from about 4,000 loops per second to about 40,000.
initializePins();

for (int c = 0; c < sizeKpd.columns; c++) {
pinMode(columnPins[c], OUTPUT);
digitalWrite(columnPins[c], LOW);
for (int r = 0; r <sizeKpd.rows; r++) {
curKey = digitalRead(rowPins[r]);
allKeys += curKey;
if (curKey == 0) curKey = keymap[c+(r*sizeKpd.columns)];

if (r==(sizeKpd.rows-1) && c==(sizeKpd.columns-1)) {
if (allKeys == (sizeKpd.rows*sizeKpd.columns))
anyKey = OPEN;
else
anyKey = CLOSED;
}
}
pinMode(columnPins[c], INPUT);
digitalWrite(columnPins[c], HIGH);
}
allKeys = 0;
return anyKey;
}

// Manage the key list. Any keys already on the list stay in their current slot
// and empty slots get filled with new keys.
void Keypad::updateList() {

// Delete Idle keys
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kstate==IDLE) {
key[i].kchar = NO_KEY;
key[i].stateChanged = false;
}
} =

// Fill the empty slots in key[] list with new CLOSED keys.
for (byte r=0; r<sizeKpd.rows; r++) {
for (byte c=0; c<sizeKpd.columns; c++) {
boolean button = bitRead(bitMap[r],c);
char keyChar = keymap[r * sizeKpd.columns + c];
int idx = findInList (keyChar); // -1 = not on list, else returns key index
// Update any key that was found on the list.
if (idx>=0)
setKeyState (idx, button);
// Add a key to the list when the button is CLOSED.
if ((idx==-1) && button) {
// Check the whole list for an empty key slot and put it there.
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kchar==NO_KEY) {
key[i].kchar = keyChar;
key[i].kstate = IDLE;
// All keys not on the list are considered IDLE. Using setKeyState
// on new key will transition the key to the PRESSED state as expected.
setKeyState (i, button);
break; // only fill the first empty slot.
}
}
}
}
}
}

// Private
void Keypad::setKeyState(byte idx, boolean button) {
// Clear stateChanged.
key[idx].stateChanged = false;

switch (key[idx].kstate) {
case IDLE: // Waiting for a keypress.
if (button==CLOSED) {
transitionTo (idx, PRESSED);
holdTimer = millis(); } // Get ready for next HOLD state.
break;
case PRESSED:
if ((millis()-holdTimer)>holdTime) // Waiting for a key HOLD...
transitionTo (idx, HOLD);
else if (button==OPEN) // or for a key to be RELEASED.
transitionTo (idx, RELEASED);
break;
case HOLD:
// Waiting for a key to be RELEASED.
if (button==OPEN)
transitionTo (idx, RELEASED);
break;
case RELEASED:
transitionTo (idx, IDLE);
break;
}
}

// New in 2.1
bool Keypad::isPressed(char keyChar) {
for (byte i=0; i<LIST_MAX; i++) {
if ( (key[i].kchar == keyChar) && (key[i].kstate == PRESSED) )
return true;
}
return false; // Not pressed.
}

// New in 2.0
char Keypad::waitForKey() {
char waitKey = NO_KEY;
while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress.
return waitKey;
}

KeyState Keypad::getState() {
return key[0].kstate;
}

// The end user can test for any changes in state before deciding
// if any variables, etc. needs to be updated in their code.
// Useful for keypads/keyboards returning a single key only.
bool Keypad::keyStateChanged() {
return key[0].stateChanged;
}

// The number of keys on the key list, key[LIST_MAX], equals the number
// of bytes in the key list divided by the number of bytes in a key.
byte Keypad::numKeys() {
return sizeof(key)/sizeof(Key);
}

// Minimum debounceTime is 10 mS. Any lower *will* slow down the loop().
void Keypad::setDebounceTime(uint debounce) {
debounce<1 ? debounceTime=1 : debounceTime=debounce;
}

void Keypad::setHoldTime(uint hold) {
   holdTime = hold;
}

void Keypad::addEventListener(void (*listener)(char)){
keypadEventListener = listener;
}

void Keypad::transitionTo(byte n, KeyState nextState) {
key[n].kstate = nextState;
key[n].stateChanged = true;

if (keypadEventListener!=NULL)
keypadEventListener(key[0].kchar);
}

void Keypad::initializePins() {
for (byte r = 0; r < sizeKpd.rows; r++) {
pinMode(rowPins[r], INPUT);
digitalWrite(rowPins[r], HIGH);
}
for (byte c = 0; c < sizeKpd.columns; c++) {
pinMode(columnPins[c], INPUT);
digitalWrite(columnPins[c], HIGH);
}
}


// Search for a key in the list of active keys.
// Returns -1 if not found or the index into the list of active keys.
int Keypad::findInList (char keyChar) {
for (byte i=0; i<LIST_MAX; i++) {
if (key[i].kchar == keyChar) {
return i;
}
}
return -1; // No matching key in list.
}



Here's my own code (which calls from the libraries):
Code: [Select]
//extend Keypad class
#include <Keypad.h>

//initialize rows and columns
const byte ROWS = 4;
const byte COLS = 4;

//define the symbols on the buttons
char hexaKeys[ROWS][COLS] = {
  {'0','1','2','3'},
  {'4','5','6','7'},
  {'8','9','A','B'},
  {'C','D','E','F'}
};

//row pinouts
byte rowPins[ROWS] = {5, 4, 3, 2};
//column pinouts
byte colPins[COLS] = {9, 8, 7, 6};

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

int MIDInotes[16] = {60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83, 84, 86};

//SOME METHODS:
//MIDIiu noteON
void noteOn(int channel, int pitch, int velocity) {
  Serial.write(channel);
  Serial.write(pitch);
  Serial.write(velocity);
  delay(1);
}
 
void setup() {
   
  Serial.begin(31250);
  }
 
void loop() {
 
  char customKey = customKeypad.getKey();
 
  if (customKey){

    char testChar = customKey;
    int someInt;
    if (testChar >= 'A' && testChar <= 'F')
    {
      someInt = 10 + (int)(testChar- 'A');
    }
    else
    {
      someInt = (int)(customKey - '0');
    }

  noteOn(144, MIDInotes[someInt], 127);
  delay(100);
}
}

pylon

I would say the original code is doing more what you're expecting from the library. The problem is that you cannot use getKey() when you wanna get a multi-key stroke. Use the is_pressed() method instead.

Go Up