I2C Port expander and 74C923 Keypad Decoder and 20 key keypad

I've connected a 20-key keypad to a 74C923 keypad decoder, which itself is connected to a PCF8574 i2c port expander. Although I'm not using column#4.

I'm using the code written by Andrew Davison who used a 16-key keypad with the 74C922 keypad decoder. I have modified Andrews code here, to map the keypad keys to (note I'm not using column 4 hence the spaces):

char I2CDecodedKeypad::charSet[21]="CMN 789 456 123 *0- ";

and here:

char I2CDecodedKeypad::getKeyStroke()
{
	int tmpKey;

	tmpKey = i2cRead();

	if ((decoderDataAvailable == 1) && (tmpKey > -1 && tmpKey < 20))
//    if ((decoderDataAvailable == 1)&&((tmpKey & 0x10) == 0))
	{
//        tmpKey &= 0x0F;
		// OK. A key has been pressed and released, so return the value.
		
		beep(25, 00, 1);
		
		decoderDataAvailable = 0;
		return charSet[tmpKey];
	}
	else if ((tmpKey & 0x10) > 0)
	{
		decoderDataAvailable = 1;
	}
	// Otherwise nothing happened...
	return 0;
}

But, I still can't get the code to recognise keys 17, 18, 19, and 20. Andrew has the test condition of checking the value in tmpKey with logical AND 16 [0x10] to filter out anything other than keys [0..15], but changing this to say 32 does not solve my problem. I was wondering if anyone else has used the 74C923 with a 20-key keypad and what they did to recognise all the keys?

There is the 74C923, the PCF8574, the code in the Playground by Andrew Davison, your code and your hardware. That are five unknown things.

Did you connect the DataReady (or DataAvailable) to P7 ?
And the extra signal to P4 ?

That is why you test with 0x10 to see if data is ready ?
You should mask the data with 0x1F. Get four bits with 0x0F and get five bits with 0x1F.

Koepel:
Did you connect the DataReady (or DataAvailable) to P7 ?

Yes

Koepel:
And the extra signal to P4 ?

Yes

Koepel:
That is why you test with 0x10 to see if data is ready ?
You should mask the data with 0x1F. Get four bits with 0x0F and get five bits with 0x1F.

I've tried masking the test for data ready with logical AND 0x10, but this masks out the keys >= 16

[/quote]

In the playground is this:

tmpKey&=0x0F;

That selects the 4 lower bits, and removes the other bits. You have commented it out, but the DataReady will not be removed and perhaps there is noise on a open input ?

Can you make 0x1F of that ?

It will be a lot easier of you send a lot of data (for example tmpKey) to the serial monitor.

I put the Serial.print etc in as below:

char I2CDecodedKeypad::getKeyStroke()
{
	int tmpKey;

	tmpKey = i2cRead();

    if (temp != tmpKey)
    {
        temp = tmpKey;
        Serial.print("i2cRead: ");
        Serial.println(temp);
    }

    if ((decoderDataAvailable == 1)&&((tmpKey & 0x20) == 0))
   {
        tmpKey &= 0x1F;
	// OK. A key has been pressed and released, so return the value.
	Serial.print("Key: ");
        Serial.println(tmpKey);
	beep(25, 00, 1);
		
	decoderDataAvailable = 0;
	return charSet[tmpKey];
   }
    else if ((tmpKey ^ 0xFF) == 0)
   {
	decoderDataAvailable = 1;
   }
	// Otherwise nothing happened...
	return 0;
}

As I found that the keydown event generated a value of 255. My data-available is now indicating, and I can normally read the index of the key pressed for each key [0..19].

This all works up to a point, when suddenly the I will start to get the output:

Key: 31

and I then get this on any key pressed!

DataReady to bit P7, that is 0x80.
Data to P0, P1, P2, P3, P4, those are the bits 0x1F.

In the code you have tmpKey & 0x20. That would be okay of the the DataReady would be connected to P5.
Use 0x80 everywhere 0x10 was used, because the DataReady is now P7.
Replace 0x0F with 0x1F because now also P5 is used for data.
Remove the '< 20', and use the original line.

I'm sorry for not giving a clear answer right away in my Reply #1, I'm confused by the code.

There is also a ^ with 0xFF, that is a XOR. Are all the lines high when no key is pressed ? I still don't understand everything.

A huge thank you for your help. I changed the code to as below, ensuring that the Data Available from the 74C923 is going to P7 of the 8574, and P5 and P7 are connected to ground.

char I2CDecodedKeypad::getKeyStroke()
{
   int tmpKey;

   tmpKey = i2cRead();

    if (temp != tmpKey)
    {
        temp = tmpKey;
        Serial.print("i2cRead: ");
        Serial.println(temp);
    }

    if ((decoderDataAvailable == 1) && ((tmpKey & 0x80) == 0))
   {
        tmpKey &= 0x1F;
	// OK. A key has been pressed and released, so return the value.
	Serial.print("Key: ");
        Serial.println(tmpKey);
	beep(25, 00, 1);
		
	decoderDataAvailable = 0;
	return charSet[tmpKey];
   }
    else if ((tmpKey & 0x80) > 0)
   {
	decoderDataAvailable = 1;
   }

   // Otherwise nothing happened...
   return 0;
}

I now get:

Key index Key down Key up
0 128 0
1 129 1
2 130 2
...
18 146 18

Working perfectly now. Thank you.