3

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.

Cros Dude
  • 33
  • 4
  • 1
    Post the code and schematics so we can comment if it is something obvious. – Justme Feb 25 '21 at 05:11
  • 1
    This Rpi SE Q&A might help: Multiple GPIO Buttons vs Matrix Keypad, Viewed 5k times https://raspberrypi.stackexchange.com/questions/98440/multiple-gpio-buttons-vs-matrix-keypad. Have a great project. Cheers. – tlfong01 Feb 25 '21 at 05:15
  • 1
    @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. – Cros Dude Feb 25 '21 at 05:28
  • 1
    @tlfong01 Thanks, I'll take a look – Cros Dude Feb 25 '21 at 05:28
  • 1
    where is the receive variable defined? it appears to hold your GPIOB register readout values but I dont see where it is defined or modified. – gcr Feb 25 '21 at 05:39
  • 2
    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 – jsotola Feb 25 '21 at 05:50

1 Answers1

4

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)

  • 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. – Cros Dude Mar 01 '21 at 03:12
  • 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) – Jasen Слава Україні Mar 01 '21 at 05:04
  • Ah okay, that makes sense. I think I'll try swapping the polarity first, as that's just some small changes to the code. – Cros Dude Mar 01 '21 at 06:24
  • 1
    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. – Cros Dude Mar 03 '21 at 01:52
  • 1
    Cool! Thanks for telling me that it worked. – Jasen Слава Україні Mar 03 '21 at 02:01