u8glib and keypad library not playing well together

I have a project that is basically an extension of a devices' controls. It consists of serial to interface with the device, a 64x256 display driven with u8glib, a 5x5 keypad, and a volume pot sampled with analog read.

When the user presses a key it sends a hex array corresponding to the button pushed to the device via serial. The device returns the updated display information via serial then the sketch/arduino processes and displays that updated response. Pretty simple, and it works well except the keypad is very slow at times and appears to be suffering from "interference" from the u8glib display loop. If I comment the display loop out the keypad responds normally. With u8glib's (while do) loop in the sketch the keypad code will usually recognize a key PRESS but the event listener will almost always miss the RELEASE state and initiate a HELD state.

For testing purposes I stripped down the keypad size to a 2x2 and only used four keys.

Has anyone encountered a similar problem? Is there simply just too much going on to work effectively?

#include <Keypad.h>
#include "U8glib.h"
U8GLIB_NHD31OLED_2X_GR u8g(10, 9);
//#include <SoftwareSerial.h>
//SoftwareSerial mySerial(15, 16); // RX, TX

const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns
char keys[ROWS][COLS] = {
  {
    'X', 'arrowDown'
  }
  ,
  {
    'MENU', 'Enter'
  }

};
byte colPins[COLS] = {
  38, 40,
}; //connect to the column pinouts of the keypad
byte rowPins[ROWS] = {
  42, 44
}; //connect to the row pinouts of the keypad

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

char holdKey;
unsigned long t_hold;

byte X[20] = {
  0x24, 0x05, 0x18, 0x36, 0xFE, 0x7B, 0xEF, 0x01, 0xE0, 0x03
};
byte arrowDown[10] = {
  0x24, 0x05, 0x18, 0x36, 0xDF, 0x7B, 0xEF, 0x01, 0xC1, 0x03
};
byte buttonMENU[10] = {
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x00, 0xE0, 0x03
};
byte buttonEnter[10] = {
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xED, 0x01, 0xDF, 0x03
};
byte buttonRelease[10] = {
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x01, 0xE1, 0x03
};
byte specialReports[9] = {
  0x24, 0x04, 0x18, 0x29, 0x00, 0x01, 0x2E, 0x98, 0x03
};  // enable serial control

byte acknowledge[6] = {
  0x24, 0x01, 0x10, 0xF3, 0x28, 0x03
}; // acknowledge receipt of data from device, unitiate next data packet
boolean checkSumGood = false;
int8_t sum = 0;
int8_t a = 0;
int8_t sumCounter = 0;
char dataBuffer[49];
char dataBufferShifted[49];
char elevenCharacterString[12];
int8_t startOfMessage;
int8_t lengthOfMessage;
int8_t sourceDestination;
int8_t opCode;
int8_t subOpCode;
char controlHeadStringData_2;
uint8_t checkSum;
uint8_t checkSumByte;
uint8_t endOfMessage;
int8_t sumIndex = 0;
int8_t i = 0;


int8_t displayMessages = 0x2E;
int8_t elevenCharacterStringSubOpCode = 0x03;
int8_t elevenCharacterStringStart = 7;  //loop start
int8_t elevenCharacterStringEnd = 17;  //loop end
int8_t displayString = 0x02;
int8_t subOpCodeData_1;
int8_t subOpCodeData_2;
char fiveCharacterString_Line_0[5];


void setup(void) {
  Serial.begin(9600, SERIAL_8O1);
  Serial.write(specialReports, 9);
  keypad.setHoldTime(500);
  keypad.setDebounceTime(10);
  keypad.addEventListener(keypadEvent);

  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
  mySerial.begin(9600);
}


void loop() {
  //checkSumGood = false;
  char key = keypad.getKey();

  if (Serial.available() != 0) {

    for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }

  

    startOfMessage = dataBuffer[0]; //                     0x24
    lengthOfMessage = dataBuffer[1]; //                    variable
    sourceDestination = dataBuffer[2]; //                 0x81
    opCode = dataBuffer[3]; //                             variable
    subOpCode = dataBuffer[4]; //                          variable
    subOpCodeData_1 = dataBuffer[5]; //                             variable
    subOpCodeData_2 = dataBuffer[6]; //                             variable
    checkSumByte = dataBuffer[lengthOfMessage + 3]; //     variable
    endOfMessage = dataBuffer[lengthOfMessage + 4]; //     0x03

    //   strcpy( dataBufferShifted, dataBuffer );

    for (sumIndex = 0; sumIndex < lengthOfMessage + 3; sumIndex ++) //summing loop to add up packet data
    {
      checkSum += dataBuffer[sumIndex];
    }
    if (checkSum == checkSumByte) { 
      checkSumGood = true;
    }


    if (opCode == 0xF3 && subOpCodeData_2 == 0x24 ) {  // test for prependedACK and adjust display loop
      //Serial.write(acknowledge, 6);
      elevenCharacterStringStart = 13;
      elevenCharacterStringEnd = 23;
    }
    else if (opCode == displayMessages && checkSumGood == true ) {
      elevenCharacterStringStart = 7;
      elevenCharacterStringEnd = 17;
    }

    if (opCode != 0xF3 && checkSumGood == true ) {
      Serial.write(acknowledge, 6);
    }

  }

  //EXAMPLE MENU PACKET 24 09 81 2E 02 02 55 4D 45 4E 55 20 8A 03 (display 0, 0)

  if (opCode == displayMessages && subOpCode == elevenCharacterStringSubOpCode ) {

    for (int i = elevenCharacterStringStart, j = 0; i <= elevenCharacterStringEnd; i++, j++) { // 7 - 17
      elevenCharacterString[j] = dataBuffer[i];
      elevenCharacterString[j + 1] = '\0';

    }

  }

  u8g.firstPage();
  do {
    draw();
  }
  while ( u8g.nextPage() );
}




void draw(void) {

  u8g.setFont(u8g_font_fub25r);
  u8g.drawStr( 0, 45, elevenCharacterString);

}


void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      switch (key) {
        case 'X':

          Serial.write(X, 10);
          // mySerial.write(X, 10);

          break;

        case 'arrowDown':

          Serial.write(arrowDown, 10);


          break;
        case 'MENU':

          Serial.write(buttonMENU, 10);


          break;
        case 'Enter':

          Serial.write(buttonEnter, 10);


          break;
      }




      break;

    case HOLD:


      switch (key) {
        case 'X':

          Serial.write(X, 10);

          break;

        case 'arrowDown':

          Serial.write(arrowDown, 10);


          break;
        case 'MENU':

          Serial.write(buttonMENU, 10);


          break;
        case 'Enter':

          Serial.write(buttonEnter, 10);


          break;
      }
      break;

    case RELEASED:
      switch (key) {

        case 'X':

          Serial.write(buttonRelease, 10);
          //mySerial.write(buttonRelease, 10);




          break;
      }

  }

}
    'X', 'arrowDown'

Please post a picture of your keyboard with the ONE key circled that you pressed to get the ONE key in single quotes at the end of that statement.

PaulS:

    'X', 'arrowDown'

Please post a picture of your keyboard with the ONE key circled that you pressed to get the ONE key in single quotes at the end of that statement.

So, only one character can be used to define each key? I don't know why but I continue to struggle to get my mind around the concept of how the keyboard works in that regard. I feel like a dog scratching at a latch. I don't know how it works but I know something in that area needs to be manipulated.

I guess what I'm saying is how do I reference a key that is something beyond the standard 0-9 * #?

Thanks for the reply. I will start studying the keypad code again in an attempt to understand what is is that I obviously don't.

But, as literally requested here is a pic of the board (disregard the VFD). The same board design is adapted to the OLED currently. :wink:

I guess what I'm saying is how do I reference a key that is something beyond the standard 0-9 * #?

The keypad library is going to return a unique value for each of the keys on the keypad. That is usually char data.

But, you could make the values be 0 to 11, instead of '0' to '9' and a few others.

Then, the value could be used as an index into an array of strings. Or an array of floats. Or an array of MenFromMars pointers.

OK, I've since made the suggested changes. The PRESS state is reliable, as well as HOLD.

It is still missing the RELEASE state about 80 % of the time.

OK, I've since made the suggested changes.

And didn't post the code.

PaulS:
And didn't post the code.

Yes, I suppose that would have helped.

#include <Keypad.h>
#include "U8glib.h"
U8GLIB_NHD31OLED_2X_GR u8g(10, 9);
const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns
char keys[ROWS][COLS] = { 
  {'U', 'D'},
  {'M', 'E'},
};
byte colPins[COLS] = {
  38, 40,
}; //connect to the column pinouts of the keypad
byte rowPins[ROWS] = {
  42, 44
}; //connect to the row pinouts of the keypad

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

char holdKey;
unsigned long t_hold;

byte U[20] = { // UP
  0x24, 0x05, 0x18, 0x36, 0xFE, 0x7B, 0xEF, 0x01, 0xE0, 0x03
};
byte D[10] = { // DOWN
  0x24, 0x05, 0x18, 0x36, 0xDF, 0x7B, 0xEF, 0x01, 0xC1, 0x03
};
byte M[10] = { // MENU
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x00, 0xE0, 0x03
};
byte E[10] = { // ENTER
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xED, 0x01, 0xDF, 0x03
};
byte R[10] = { // RELEASE (tells the device any keypad button previously pressed has been released)
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x01, 0xE1, 0x03
};
byte S[9] = { // SPECIAL REPORTS (initiates serial comms for PC interface)
  0x24, 0x04, 0x18, 0x29, 0x00, 0x01, 0x2E, 0x98, 0x03
};  // enable serial control

byte A[6] = { // ACKNOWLEDGE
  0x24, 0x01, 0x10, 0xF3, 0x28, 0x03
}; // acknowledge receipt of data from device, unitiate next data packet
boolean checkSumGood = false;
int8_t sum = 0;
int8_t a = 0;
int8_t sumCounter = 0;
char dataBuffer[49];
char dataBufferShifted[49];
char elevenCharacterString[12];
int8_t startOfMessage;
int8_t lengthOfMessage;
int8_t sourceDestination;
int8_t opCode;
int8_t subOpCode;
char controlHeadStringData_2;
uint8_t checkSum;
uint8_t checkSumByte;
uint8_t endOfMessage;
int8_t sumIndex = 0;
int8_t i = 0;


int8_t displayMessages = 0x2E;
int8_t elevenCharacterStringSubOpCode = 0x03;
int8_t elevenCharacterStringStart = 7;  //loop start
int8_t elevenCharacterStringEnd = 17;  //loop end
int8_t displayString = 0x02;
int8_t subOpCodeData_1;
int8_t subOpCodeData_2;
char fiveCharacterString_Line_0[5];


void setup(void) {
  Serial.begin(9600, SERIAL_8O1);
  Serial.write(S, 9);
  keypad.setHoldTime(500);
  keypad.setDebounceTime(10);
  keypad.addEventListener(keypadEvent);

  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
 // mySerial.begin(9600);
}


void loop() {
  //checkSumGood = false;
  char key = keypad.getKey();

  if (Serial.available() != 0) {

    for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }

    //                         st lg dr op so d1 d2                                  cs em
    //                          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
    //EXAMPLE FREQUENCY PACKET 24 0F 81 2E 03 02 6E 46 20 20 38 2C 39 39 32 2E 39 38 82 03
    //                                               F        8  ,  9  9  2  .  9  8
    //                               |----------------length-----------------------|

    startOfMessage = dataBuffer[0]; //                     0x24
    lengthOfMessage = dataBuffer[1]; //                    variable
    sourceDestination = dataBuffer[2]; //                 0x81
    opCode = dataBuffer[3]; //                             variable
    subOpCode = dataBuffer[4]; //                          variable
    subOpCodeData_1 = dataBuffer[5]; //                             variable
    subOpCodeData_2 = dataBuffer[6]; //                             variable
    checkSumByte = dataBuffer[lengthOfMessage + 3]; //     variable
    endOfMessage = dataBuffer[lengthOfMessage + 4]; //     0x03

    //   strcpy( dataBufferShifted, dataBuffer );
  
    for (sumIndex = 0; sumIndex < lengthOfMessage + 3; sumIndex ++) //summing loop to add up packet data
    {
      checkSum += dataBuffer[sumIndex];
    }
    if (checkSum == checkSumByte) {  // checksumming test prior to ack is extremely slow
      checkSumGood = true;
    }


    if (opCode == 0xF3 && subOpCodeData_2 == 0x24 ) {  // test for prependedACK and adjust display loop
      //Serial.write(acknowledge, 6);
      elevenCharacterStringStart = 13;
      elevenCharacterStringEnd = 23;
    }
    else if (opCode == displayMessages && checkSumGood == true ) {
      elevenCharacterStringStart = 7;
      elevenCharacterStringEnd = 17;
    }

   if (opCode != 0xF3 && checkSumGood == true ) {
      Serial.write(A, 6);
    }

  }

  //EXAMPLE MENU PACKET 24 09 81 2E 02 02 55 4D 45 4E 55 20 8A 03 (display 0, 0)

  if (opCode == displayMessages && subOpCode == elevenCharacterStringSubOpCode ) {

    for (int i = elevenCharacterStringStart, j = 0; i <= elevenCharacterStringEnd; i++, j++) { // 7 - 17
      elevenCharacterString[j] = dataBuffer[i];
      elevenCharacterString[j + 1] = '\0';

    }

  }

  u8g.firstPage();
  do {
    draw();
  }
  while ( u8g.nextPage() );
  
 }

void draw(void) {

  u8g.setFont(u8g_font_fub25r);
  u8g.drawStr( 0, 45, elevenCharacterString);
  // u8g.setFont(u8g_font_04b_03r);

}

void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      switch (key) {
        case 'U':

          Serial.write(U, 10);
      
          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case HOLD:

      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case RELEASED:
      switch (key) {

        case 'U':

          Serial.write(R, 10);
      
          break;
        case 'D':

          Serial.write(R, 10);

          break;
        case 'M':

          Serial.write(R, 10);

          break;
        case 'E':

          Serial.write(R, 10);

          break;
      }
  }
}
  if (Serial.available() != 0) {

    for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }

Learning that there is at lease one character to read does NOT mean that you can read 48 characters.

PaulS:

  if (Serial.available() != 0) {

for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }



Learning that there is at lease one character to read does NOT mean that you can read 48 characters.

I thought that Serial.available returned the number of characters available in the buffer and as long as something was present (!=0) then the if would be satisfied and allow the loop to place them into dataBuffer.

I will change it to Serial.available() >0)

How about to
Serial.available() >47
so you know that at least 48 characters are available to be read.

CrossRoads:
How about to
Serial.available() >47
so you know that at least 48 characters are available to be read.

I will do that.

I always had it in my head that something similar, Serial.available>whatever number, meant that the amount of data had to exceed the number (let's say 47) before action would be initiated and therefore a smaller packet of 25 or 35 would remain in the buffer ignored.

I won't know exactly what the length of the packets will be and chose 46 just for extra room since they rarely exceed 40.

#include <Keypad.h>
#include "U8glib.h"
U8GLIB_NHD31OLED_2X_GR u8g(10, 9);
const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns
char keys[ROWS][COLS] = {
  {'U', 'D'},
  {'M', 'E'},
};
byte colPins[COLS] = {
  38, 40,
}; //connect to the column pinouts of the keypad
byte rowPins[ROWS] = {
  42, 44
}; //connect to the row pinouts of the keypad

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

char holdKey;
unsigned long t_hold;

byte U[20] = { // UP
  0x24, 0x05, 0x18, 0x36, 0xFE, 0x7B, 0xEF, 0x01, 0xE0, 0x03
};
byte D[10] = { // DOWN
  0x24, 0x05, 0x18, 0x36, 0xDF, 0x7B, 0xEF, 0x01, 0xC1, 0x03
};
byte M[10] = { // MENU
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x00, 0xE0, 0x03
};
byte E[10] = { // ENTER
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xED, 0x01, 0xDF, 0x03
};
byte R[10] = { // RELEASE (tells the device any keypad button previously pressed has been released)
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x01, 0xE1, 0x03
};
byte S[9] = { // SPECIAL REPORTS (initiates serial comms for PC interface)
  0x24, 0x04, 0x18, 0x29, 0x00, 0x01, 0x2E, 0x98, 0x03
};  // enable serial control

byte A[6] = { // ACKNOWLEDGE
  0x24, 0x01, 0x10, 0xF3, 0x28, 0x03
}; // acknowledge receipt of data from device, unitiate next data packet
boolean checkSumGood = false;
int8_t sum = 0;
int8_t a = 0;
int8_t sumCounter = 0;
char dataBuffer[49];
char dataBufferShifted[49];
char elevenCharacterString[12];
int8_t startOfMessage;
int8_t lengthOfMessage;
int8_t sourceDestination;
int8_t opCode;
int8_t subOpCode;
char controlHeadStringData_2;
uint8_t checkSum;
uint8_t checkSumByte;
uint8_t endOfMessage;
int8_t sumIndex = 0;
int8_t i = 0;


int8_t displayMessages = 0x2E;
int8_t elevenCharacterStringSubOpCode = 0x03;
int8_t elevenCharacterStringStart = 7;  //loop start
int8_t elevenCharacterStringEnd = 17;  //loop end
int8_t displayString = 0x02;
int8_t subOpCodeData_1;
int8_t subOpCodeData_2;
char fiveCharacterString_Line_0[5];


void setup(void) {
  Serial.begin(9600, SERIAL_8O1);
  Serial.write(S, 9);
  keypad.setHoldTime(500);
  keypad.setDebounceTime(10);
  keypad.addEventListener(keypadEvent);

  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
  // mySerial.begin(9600);
}


void loop() {
  char key = keypad.getKey();

  if (Serial.available() >0) {

    for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }

    //                         st lg dr op so d1 d2                                  cs em
    //                          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
    //EXAMPLE FREQUENCY PACKET 24 0F 81 2E 03 02 6E 46 20 20 38 2C 39 39 32 2E 39 38 82 03
    //                                               F        8  ,  9  9  2  .  9  8
    //                               |----------------length-----------------------|

    startOfMessage = dataBuffer[0]; //                     0x24
    lengthOfMessage = dataBuffer[1]; //                    variable
    sourceDestination = dataBuffer[2]; //                 0x81
    opCode = dataBuffer[3]; //                             variable
    subOpCode = dataBuffer[4]; //                          variable
    subOpCodeData_1 = dataBuffer[5]; //                             variable
    subOpCodeData_2 = dataBuffer[6]; //                             variable
    checkSumByte = dataBuffer[lengthOfMessage + 3]; //     variable
    endOfMessage = dataBuffer[lengthOfMessage + 4]; //     0x03

    //   strcpy( dataBufferShifted, dataBuffer );

    for (sumIndex = 0; sumIndex < lengthOfMessage + 3; sumIndex ++) //summing loop to add up packet data
    {
      checkSum += dataBuffer[sumIndex];
    }
    if (checkSum == checkSumByte) {  // checksumming test prior to ack is extremely slow
      checkSumGood = true;
    }


    if (opCode == 0xF3 && subOpCodeData_2 == 0x24 ) {  // test for prependedACK and adjust display loop
      //Serial.write(acknowledge, 6);
      elevenCharacterStringStart = 13;
      elevenCharacterStringEnd = 23;
    }
    else if (opCode == displayMessages && checkSumGood == true ) {
      elevenCharacterStringStart = 7;
      elevenCharacterStringEnd = 17;
    }

    if (opCode != 0xF3 && checkSumGood == true ) {
      Serial.write(A, 6);
    }

  }

  //EXAMPLE MENU PACKET 24 09 81 2E 02 02 55 4D 45 4E 55 20 8A 03 (display 0, 0)

  if (opCode == displayMessages && subOpCode == elevenCharacterStringSubOpCode ) {

    for (int i = elevenCharacterStringStart, j = 0; i <= elevenCharacterStringEnd; i++, j++) { // 7 - 17
      elevenCharacterString[j] = dataBuffer[i];
      elevenCharacterString[j + 1] = '\0';

    }

  }

  u8g.firstPage();
  do {
    draw();
  }
  while ( u8g.nextPage() );

}

void draw(void) {

  u8g.setFont(u8g_font_fub25r);
  u8g.drawStr( 0, 45, elevenCharacterString);
  // u8g.setFont(u8g_font_04b_03r);

}

void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case HOLD:

      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case RELEASED:
      switch (key) {

        case 'U':

          Serial.write(R, 10);

          break;
        case 'D':

          Serial.write(R, 10);

          break;
        case 'M':

          Serial.write(R, 10);

          break;
        case 'E':

          Serial.write(R, 10);

          break;
      }
  }
}

I have since made the the suggested edits to the serial portion. It is more reliable now but still misses the RELEASED state quite often. Again, if I comment out the do while u8glib function the keyboard responds much more rapidly and recognizes the RELEASED state every time.

I have since made the the suggested edits to t

But, again, failed to post the revised code.

Again, if I comment out the do while u8glib function the keyboard responds much more rapidly and recognizes the RELEASED state every time.

How many pages are there to draw()? Why are you drawing the same thing on each page? Why is it necessary to change the font (to the same thing) every time?

PaulS:
But, again, failed to post the revised code.
How many pages are there to draw()? Why are you drawing the same thing on each page? Why is it necessary to change the font (to the same thing) every time?

The code is in post #10. (that is, unless I misunderstood what the proper changes should be) I changed the keypad and changed serial to eliminate !=0.

#include <Keypad.h>
#include "U8glib.h"
U8GLIB_NHD31OLED_2X_GR u8g(10, 9);
const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns
char keys[ROWS][COLS] = {
  {'U', 'D'},
  {'M', 'E'},
};
byte colPins[COLS] = {
  38, 40,
}; //connect to the column pinouts of the keypad
byte rowPins[ROWS] = {
  42, 44
}; //connect to the row pinouts of the keypad

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

char holdKey;
unsigned long t_hold;

byte U[20] = { // UP
  0x24, 0x05, 0x18, 0x36, 0xFE, 0x7B, 0xEF, 0x01, 0xE0, 0x03
};
byte D[10] = { // DOWN
  0x24, 0x05, 0x18, 0x36, 0xDF, 0x7B, 0xEF, 0x01, 0xC1, 0x03
};
byte M[10] = { // MENU
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x00, 0xE0, 0x03
};
byte E[10] = { // ENTER
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xED, 0x01, 0xDF, 0x03
};
byte R[10] = { // RELEASE (tells the device any keypad button previously pressed has been released)
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x01, 0xE1, 0x03
};
byte S[9] = { // SPECIAL REPORTS (initiates serial comms for PC interface)
  0x24, 0x04, 0x18, 0x29, 0x00, 0x01, 0x2E, 0x98, 0x03
};  // enable serial control

byte A[6] = { // ACKNOWLEDGE
  0x24, 0x01, 0x10, 0xF3, 0x28, 0x03
}; // acknowledge receipt of data from device, unitiate next data packet
boolean checkSumGood = false;
int8_t sum = 0;
int8_t a = 0;
int8_t sumCounter = 0;
char dataBuffer[49];
char dataBufferShifted[49];
char elevenCharacterString[12];
int8_t startOfMessage;
int8_t lengthOfMessage;
int8_t sourceDestination;
int8_t opCode;
int8_t subOpCode;
char controlHeadStringData_2;
uint8_t checkSum;
uint8_t checkSumByte;
uint8_t endOfMessage;
int8_t sumIndex = 0;
int8_t i = 0;


int8_t displayMessages = 0x2E;
int8_t elevenCharacterStringSubOpCode = 0x03;
int8_t elevenCharacterStringStart = 7;  //loop start
int8_t elevenCharacterStringEnd = 17;  //loop end
int8_t displayString = 0x02;
int8_t subOpCodeData_1;
int8_t subOpCodeData_2;
char fiveCharacterString_Line_0[5];


void setup(void) {
  Serial.begin(9600, SERIAL_8O1);
  Serial.write(S, 9);
  keypad.setHoldTime(500);
  keypad.setDebounceTime(10);
  keypad.addEventListener(keypadEvent);

  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
  // mySerial.begin(9600);
}


void loop() {
  char key = keypad.getKey();

  if (Serial.available() >0) {

    for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }

    //                         st lg dr op so d1 d2                                  cs em
    //                          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
    //EXAMPLE FREQUENCY PACKET 24 0F 81 2E 03 02 6E 46 20 20 38 2C 39 39 32 2E 39 38 82 03
    //                                               F        8  ,  9  9  2  .  9  8
    //                               |----------------length-----------------------|

    startOfMessage = dataBuffer[0]; //                     0x24
    lengthOfMessage = dataBuffer[1]; //                    variable
    sourceDestination = dataBuffer[2]; //                 0x81
    opCode = dataBuffer[3]; //                             variable
    subOpCode = dataBuffer[4]; //                          variable
    subOpCodeData_1 = dataBuffer[5]; //                             variable
    subOpCodeData_2 = dataBuffer[6]; //                             variable
    checkSumByte = dataBuffer[lengthOfMessage + 3]; //     variable
    endOfMessage = dataBuffer[lengthOfMessage + 4]; //     0x03

    //   strcpy( dataBufferShifted, dataBuffer );

    for (sumIndex = 0; sumIndex < lengthOfMessage + 3; sumIndex ++) //summing loop to add up packet data
    {
      checkSum += dataBuffer[sumIndex];
    }
    if (checkSum == checkSumByte) {  // checksumming test prior to ack is extremely slow
      checkSumGood = true;
    }


    if (opCode == 0xF3 && subOpCodeData_2 == 0x24 ) {  // test for prependedACK and adjust display loop
      //Serial.write(acknowledge, 6);
      elevenCharacterStringStart = 13;
      elevenCharacterStringEnd = 23;
    }
    else if (opCode == displayMessages && checkSumGood == true ) {
      elevenCharacterStringStart = 7;
      elevenCharacterStringEnd = 17;
    }

    if (opCode != 0xF3 && checkSumGood == true ) {
      Serial.write(A, 6);
    }

  }

  //EXAMPLE MENU PACKET 24 09 81 2E 02 02 55 4D 45 4E 55 20 8A 03 (display 0, 0)

  if (opCode == displayMessages && subOpCode == elevenCharacterStringSubOpCode ) {

    for (int i = elevenCharacterStringStart, j = 0; i <= elevenCharacterStringEnd; i++, j++) { // 7 - 17
      elevenCharacterString[j] = dataBuffer[i];
      elevenCharacterString[j + 1] = '\0';

    }

  }

  u8g.firstPage();
  do {
    draw();
  }
  while ( u8g.nextPage() );

}

void draw(void) {

  u8g.setFont(u8g_font_fub25r);
  u8g.drawStr( 0, 45, elevenCharacterString);
  // u8g.setFont(u8g_font_04b_03r);

}

void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case HOLD:

      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case RELEASED:
      switch (key) {

        case 'U':

          Serial.write(R, 10);

          break;
        case 'D':

          Serial.write(R, 10);

          break;
        case 'M':

          Serial.write(R, 10);

          break;
        case 'E':

          Serial.write(R, 10);

          break;
      }
  }
}

How many pages are there to draw()?

Pages? I suppose it's just one. The page only needs redrawn when new changed data is presented that should be displayed to the user. Otherwise, it could remain static. I thought about it like an old printers type set. All the elements you want displayed are chosen by their size, font, location etc... and placed where you want them on the page inside the draw function just like type setting blocks then draw is called and "stamps" the image to the display. Changes are made dynamically between each call to draw just like someone moving the printers blocks between each stamp of newspaper page.

Why are you drawing the same thing on each page?

Because I thought that is how the u8glib library works. I thought it was similar to a TV screen in the sense that it continuously loops over and over. If I could freeze the image until some data is changed that needs updated on the display that would be ideal I suppose. That would free up the Arduino to handle other tasks.

I made some attempts in that regard but always fell short. I attempted to test against Serial.available status. It worked but was always sluggish with very long draw times once a stream of steady new data had appeared at the serial port which needed parsed and distributed among the variables that it will update.

Why is it necessary to change the font (to the same thing) every time?

My understanding is that if you don't indicate the font desired prior to what variable you want displayed the library will default to what was used last. Obviously, this isn't an issue with one object to display but if I decide to add another similar line of text below or above with a different font then that font size and type will need to be indicated prior.

Perhaps I'm misunderstanding how the u8glib loops functions and should be implemented.

Pages? I suppose it's just one.

You should add a Serial.print() statement before the dp, in draw(), and after the while, to see how many pages are draw()n. It may be just one. It may be more than that.

The page only needs redrawn when new changed data is presented that should be displayed to the user. Otherwise, it could remain static.

But, that is not what you are doing. You redraw all the pages every time through loop(), whether things change or not.

Changes are made dynamically between each call to draw just like someone moving the printers blocks between each stamp of newspaper page.

A reasonable analogy. But, what you are doing is like removing all the type from the room each time you call the function, and then returning the same type (same font, same style, same size letters) each time. Does that take time? My guess (and it is ONLY a guess) is that it does.

Because I thought that is how the u8glib library works. I thought it was similar to a TV screen in the sense that it continuously loops over and over.

If there were one page, I'd agree. We need to determine how many pages are actually drawn, though.

If they are like pages in a book, having every page the same does not make sense.

Obviously, this isn't an issue with one object to display but if I decide to add another similar line of text below or above with a different font then that font size and type will need to be indicated prior.

You need to determine if changing font's takes microseconds, milliseconds, or seconds. That information will help you decide when to change fonts, or whether to change at all.

Perhaps I'm misunderstanding how the u8glib loops functions and should be implemented.

I think it is more a matter of not having enough information, yet. How many pages are there? How long does it take to change fonts? I'm sure that there will be more things you need to learn before you are done.

Thanks for taking the time to help. I will do some of those tests and see where it leads when I'm home.

What I find interesting from what I've gathered so far is that it's always the RELEASE that seems most negatively effected.

If I eliminate the do draw loop entirely everything keypad wise is happy. It's as if the keypad event listener is blocked by the draw loop and it "forgets" to keep track of the release status.

I have a serial sniffer program that worked fairly well when I was first sniffing out the command set. I might connect it through that to see what is going on in relation to the keys and the loop as suggested.

It's as if the keypad event listener is blocked by the draw loop and it "forgets" to keep track of the release status.

The keypad is not using interrupts. It actually has to poll the pins often, to know when one becomes released.

While the Arduino is busy drawing, polling doesn't happen.

PaulS:
The keypad is not using interrupts. It actually has to poll the pins often, to know when one becomes released.

While the Arduino is busy drawing, polling doesn't happen.

The keypad library uses a state machine which means it must reach the RELEASED state. There should be no way to get past it .

There are two sequences that the state machine can follow:
IDLE-->PRESSED-->RELEASED-->IDLE
and
IDLE-->PRESSED-->HOLD-->RELEASED-->IDLE

Imagine a key being in the PRESSED state which is then followed by a really long delay, say 5 minutes. When the polling begins again then you will either get a RELEASED state or a HOLD followed by RELEASED no matter when the user let go of the key.

Without being able to dig into the code my first guess is that something in the keypad memory is getting overwritten.

mstanley:
The keypad library uses a state machine which means it must reach the RELEASED state. There should be no way to get past it .

There are two sequences that the state machine can follow:
IDLE-->PRESSED-->RELEASED-->IDLE
and
IDLE-->PRESSED-->HOLD-->RELEASED-->IDLE

Imagine a key being in the PRESSED state which is then followed by a really long delay, say 5 minutes. When the polling begins again then you will either get a RELEASED state or a HOLD followed by RELEASED no matter when the user let go of the key.

Without being able to dig into the code my first guess is that something in the keypad memory is getting overwritten.

That's what it seems like. I moved the u8g.firstPage(); portion of the display loop to the beginning of the sketch and things improved quite a bit but I am still missing keypresses occasionally. At times it will fail to send the key release and thus the device will start free running as if the tune button is held. There is the resulting incoming stream of display data from the device and then subsequent key presses are blocked unless I rapidly punch it over and over. Then it's as if something breaks through and the key release is recognized and the activity stops.

If I reset the Mega board the very first key press always misses the button RELEASE state. So, like you said it seems keypad memory is overwritten somehow.

Could it be a RAM issue?

#include <Keypad.h>
#include "U8glib.h"
U8GLIB_NHD31OLED_2X_GR u8g(10, 9);
const byte ROWS = 2; //four rows
const byte COLS = 2; //four columns
char keys[ROWS][COLS] = {
  {'U', 'D'},
  {'M', 'E'},
};
byte colPins[COLS] = {
  38, 40,
}; //connect to the column pinouts of the keypad
byte rowPins[ROWS] = {
  42, 44
}; //connect to the row pinouts of the keypad

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

char holdKey;
unsigned long t_hold;

byte U[10] = { // UP
  0x24, 0x05, 0x18, 0x36, 0xFE, 0x7B, 0xEF, 0x01, 0xE0, 0x03
};
byte D[10] = { // DOWN
  0x24, 0x05, 0x18, 0x36, 0xDF, 0x7B, 0xEF, 0x01, 0xC1, 0x03
};
byte M[10] = { // MENU
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x00, 0xE0, 0x03
};
byte E[10] = { // ENTER
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xED, 0x01, 0xDF, 0x03
};
byte R[10] = { // RELEASE (tells the device any keypad button previously pressed has been released)
  0x24, 0x05, 0x18, 0x36, 0xFF, 0x7B, 0xEF, 0x01, 0xE1, 0x03
};
byte S[9] = { // SPECIAL REPORTS (initiates serial comms for interface)
  0x24, 0x04, 0x18, 0x29, 0x00, 0x01, 0x2E, 0x98, 0x03
};
byte A[6] = { // ACKNOWLEDGE
  0x24, 0x01, 0x10, 0xF3, 0x28, 0x03
}; // acknowledge receipt of data from device, unitiate next data packet

boolean checkSumGood = false;
int8_t sum = 0;
int8_t a = 0;
int8_t sumCounter = 0;
char dataBuffer[49];
char dataBufferShifted[49];
char elevenCharacterString[12];
int8_t startOfMessage;
int8_t lengthOfMessage;
int8_t sourceDestination;
int8_t opCode;
int8_t subOpCode;
char controlHeadStringData_2;
uint8_t checkSum;
uint8_t checkSumByte;
uint8_t endOfMessage;
int8_t sumIndex = 0;
int8_t i = 0;


int8_t displayMessages = 0x2E;
int8_t elevenCharacterStringSubOpCode = 0x03;
int8_t elevenCharacterStringStart = 7;  //loop start
int8_t elevenCharacterStringEnd = 17;  //loop end
int8_t displayString = 0x02;
int8_t subOpCodeData_1;
int8_t subOpCodeData_2;
char fiveCharacterString_Line_0[5];
//                         st lg dr op so d1 d2                                  cs em
//                          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
//EXAMPLE FREQUENCY PACKET 24 0F 81 2E 03 02 6E 46 20 20 38 2C 39 39 32 2E 39 38 82 03
//                                               F        8  ,  9  9  2  .  9  8
//                               |----------------length-----------------------|

//EXAMPLE MENU PACKET      24 09 81 2E 02 02 55 4D 45 4E 55 20 8A 03 (display 0, 0)
//   strcpy( dataBufferShifted, dataBuffer );
// u8g.firstPage();
// draw();
//( u8g.nextPage() );
void setup(void) {
  Serial.begin(9600, SERIAL_8O1);
  Serial.write(S, 9);
  keypad.setHoldTime(1000);
  keypad.setDebounceTime(10);
  keypad.addEventListener(keypadEvent);

  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255, 255, 255);
  }
}


void loop() {

  u8g.firstPage();
  //char key = keypad.getKey();

  if (Serial.available() > 0) {

    for (i = 0; i < 48; i++) {
      dataBuffer[i] = Serial.read();
      dataBuffer[i + 1] = '\0';
      delay(1);
    }
    if (startOfMessage == 0x24 && endOfMessage == 0x03 ) {
      Serial.write(A, 6);
    }
  }

  startOfMessage = dataBuffer[0]; //                     0x24
  lengthOfMessage = dataBuffer[1]; //                    variable
  sourceDestination = dataBuffer[2]; //                 0x81
  opCode = dataBuffer[3]; //                             variable
  subOpCode = dataBuffer[4]; //                          variable
  subOpCodeData_1 = dataBuffer[5]; //                             variable
  subOpCodeData_2 = dataBuffer[6]; //                             variable
  checkSumByte = dataBuffer[lengthOfMessage + 3]; //     variable
  endOfMessage = dataBuffer[lengthOfMessage + 4]; //     0x03

  for (sumIndex = 0; sumIndex < lengthOfMessage + 3; sumIndex ++) //summing loop to add up packet data
  {
    checkSum += dataBuffer[sumIndex];
  }
  if (checkSum == checkSumByte) {  // checksumming test prior to ack is extremely slow
    checkSumGood = true;
  }
  else if (checkSum != checkSumByte) {
    checkSumGood = false;
  }



  do {

    draw();


  }


  while ( u8g.nextPage() );
  //char key = keypad.getKey();
}

void draw (void) {


  char key = keypad.getKey();


  if (opCode == 0xF3 && subOpCodeData_2 == 0x24 ) {  // test for prependedACK and adjust display loop
    //Serial.write(acknowledge, 6);
    elevenCharacterStringStart = 13;
    elevenCharacterStringEnd = 23;
  }
  else if (opCode == displayMessages && checkSumGood == true ) {
    elevenCharacterStringStart = 7;
    elevenCharacterStringEnd = 17;
  }

  if (opCode == displayMessages && subOpCode == elevenCharacterStringSubOpCode ) {

    for (int i = elevenCharacterStringStart, j = 0; i <= elevenCharacterStringEnd; i++, j++) { // 7 - 17
      elevenCharacterString[j] = dataBuffer[i];
      elevenCharacterString[j + 1] = '\0';

    }
  }

  u8g.setFont(u8g_font_fub25r);
  u8g.drawStr( 0, 45, elevenCharacterString);



}


void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case HOLD:

      switch (key) {
        case 'U':

          Serial.write(U, 10);

          break;

        case 'D':

          Serial.write(D, 10);

          break;
        case 'M':

          Serial.write(M, 10);

          break;
        case 'E':

          Serial.write(E, 10);

          break;
      }
      break;

    case RELEASED:
      //delay(10);
      switch (key) {
        case 'U':
          // delay(50);
          Serial.write(R, 10);

          break;
      }
  }
}

So, like you said it seems keypad memory is overwritten somehow.

Have you looked at the library? What memory is it using?