I'm using an MCP23017 IO Expander to make a button matrix (4×4).
//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:
- Rows set to output, Columns set to input
- Set one row high, and read the columns.
- 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.
Best Answer
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)