3
\$\begingroup\$

I'm using an MCP23017 IO Expander to make a button matrix (4x4). Button Matrix IO Expander

//Defines for Matrix Rows/Columns
#define ROW0    0x10
#define ROW1    0x20
#define ROW2    0x40
#define ROW3    0x80
#define COL0    0x01
#define COL1    0x02
#define COL2    0x04
#define COL3    0x08

void bRead(){
    mcp_send_command(IObut1, MCP_GPIOB,ROW0); //Row0 High
    mcp_read_command(IObut1,MCP_GPIOB); //Read the Port, state stored in 'receive' variable
    k1 = (receive&COL0); //If the Col0 bit is set, then K1 was pressed
    k2 = (receive&COL1);
    k3 = (receive&COL2);
    k4 = (receive&COL3);
    mcp_send_command(IObut1, MCP_GPIOB,ROW1);
    mcp_read_command(IObut1,MCP_GPIOB);
    k5 = (receive&COL0);
    k6 = (receive&COL1);
    k7 = (receive&COL2);
    k8 = (receive&COL3);
    mcp_send_command(IObut1, MCP_GPIOB,ROW2);
    mcp_read_command(IObut1,MCP_GPIOB);
    k9 = (receive&COL0);
    k10 = (receive&COL1);
    k11 = (receive&COL2);
    k12 = (receive&COL3);
    mcp_send_command(IObut1, MCP_GPIOB,ROW3);
    mcp_read_command(IObut1,MCP_GPIOB);
    k13 = (receive&COL0);
    k14 = (receive&COL1);
    k15 = (receive&COL2);
    k16 = (receive&COL3);
}

Just to run through the logic, in case I'm missing something obvious:

  1. Rows set to output, Columns set to input
  2. Set one row high, and read the columns.
  3. If a column is high, then the key in that column, on that row, is pressed.

The problem I'm having at the moment is that when I press a key, then any key in that column will read as pressed when I go through the rows. Eg: If I hold down Key1 and set Row0 high, then I read the key without issue. But if I keep Key1 pressed, then Key5 reads as pressed when I set Row0 high, then Key9 on Row2, and Key13 on Row3 (likewise for the other columns).

The previous row is set low when I move onto a new row, so there aren't two rows high at any given time. I've tried setting all rows to zero, adding a 10ms delay, then setting the next row high to ensure it's not just catching the result before the previous row goes low. I've also tried setting the internal pullups on/off for rows/columns/both.

Any help would be greatly appreciated - hopefully I'm missing something obvious.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Post the code and schematics so we can comment if it is something obvious. \$\endgroup\$
    – Justme
    Feb 25, 2021 at 5:11
  • 1
    \$\begingroup\$ This Rpi SE Q&A might help: Multiple GPIO Buttons vs Matrix Keypad, Viewed 5k times raspberrypi.stackexchange.com/questions/98440/…. Have a great project. Cheers. \$\endgroup\$
    – tlfong01
    Feb 25, 2021 at 5:15
  • 1
    \$\begingroup\$ @Justme I added the relevant portions of the schematic and code. The micro is communicating with the IO expander without any issues (through mcp_send/read_command). I'm polling every 5ms and it seems to pick up key presses without issue, it just reads all the keys on the column. \$\endgroup\$
    – Cros Dude
    Feb 25, 2021 at 5:28
  • 1
    \$\begingroup\$ @tlfong01 Thanks, I'll take a look \$\endgroup\$
    – Cros Dude
    Feb 25, 2021 at 5:28
  • 2
    \$\begingroup\$ set rows as inputs, columns as outputs ... connect pullup resistors to the row pins ... ground column pins one at a time ... read the state of row pins \$\endgroup\$
    – jsotola
    Feb 25, 2021 at 5:50

1 Answer 1

4
\$\begingroup\$

The columns need a pull down, I see no evidence of that above.

The way you have the diodes facing the buttons will pull the column upwards, so you need to counter that with a pull-down (so you can see a low signal when the button is inactive).

Alternatively you could swap the signal directions and polarities and send a low signal on the columns and receive it on the rows. (with pull-up on the rows)

\$\endgroup\$
5
  • \$\begingroup\$ Is there some reason it would need pull-downs rather than pull-ups? The IO Expander has internal pullups that you can toggle. I originally had pullups for all the rows, but I tried it with columns, both, and neither having pullups. \$\endgroup\$
    – Cros Dude
    Mar 1, 2021 at 3:12
  • \$\begingroup\$ the way you have the diodes facing the buttons will pull the column upwards, so you need to counter that with a pull-down. or you could swap the signal directions and polarities and send low signal on the columns and receive it on the rows. (with pull-up on the rows) \$\endgroup\$ Mar 1, 2021 at 5:04
  • \$\begingroup\$ Ah okay, that makes sense. I think I'll try swapping the polarity first, as that's just some small changes to the code. \$\endgroup\$
    – Cros Dude
    Mar 1, 2021 at 6:24
  • 1
    \$\begingroup\$ Just tested it and it worked out fine: I set the columns to outputs and rows to inputs, enabled pullups on the rows, set one column low at a time (making sure to set the other columns high again), and checked for which row was reading 0 - no hardware changes needed. Thanks for your help. \$\endgroup\$
    – Cros Dude
    Mar 3, 2021 at 1:52
  • 1
    \$\begingroup\$ Cool! Thanks for telling me that it worked. \$\endgroup\$ Mar 3, 2021 at 2:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.