4x3 multiplexed keypad issue.

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have spent several days researching and modifying code to be able to read the keypresses on a 4x3 matrix keypad. I see that it has been done a gazillion times and I guess there is something that I am just not grasping. I have downloaded several different versions, modified them for the microcontroler I am using, ATMega168A, and I have not been sucessful in getting any of them to work. After trying several modifications on each one to get one to work without success, I decided to pick one and just move forward with that method. I selected a version posted by Bob Gardner as he seems pretty knowlegable and his code looked like it would be fairly easy to modify to work as I needed. If there are others, I am open to suggestion.

So my process was to get the code from Bob to work first. I modified the code to address the correct port for the keypad and then set up an LED to toggle each time a key was identified for testing purposes. I loaded the code and then applied a jumper from PIND0 to PIND3 (which should correspond to C0 and R0 which is #0 ??) The LED should toggle each time the jumper is applied but I didn't get any response. So then I went to the debugger (Atmel Studio 6) and stepped through the code. Watching PINB1, it kept toggling on and off without supplying any input.

So I don't know where the problem is. Here is the modified code:

#include<avr/io.h>

char keytab[16]={
 // 0   1   2   3 <-col
 'C','D','E','F', //3
 '8','9','A','B', //2
 '4','5','6','7', //1
 '0','1','2','3'  //0 <-row
};

char getkp(void){
 //return key pressed on pad     outs lo nib, in hi nib
 unsigned char c,row,col,rowcode,keyndx;

 for(col=0; col < 4; col++){
  PORTD &= ~(0x80 >> col);   //out 0,1,2,3 lo
  asm volatile("nop");
  asm volatile("nop");
  rowcode=PIND & 0x0F;       //7,b,d,e=row 0,1,2,3
  PORTD |= 0xff;             //all outs off
  //   cprintf("     % 02x\n",rowcode);
  if(rowcode != 0x0F) break; //this col has a row lo
 }
 if(rowcode == 0x0F){
  c=0xff;
  }else{
  switch(rowcode){
   case 0x07: row=3; break;
   case 0x0b: row=2; break;
   case 0x0d: row=1; break;
   case 0x0e: row=0; break;
  }//switch
  keyndx=col*4 + row;
  c=keytab[keyndx];
 }
 //  cprintf("% 02x % 02x % 02x % 02x\n",rowcode,row,col,keyndx);
 return(c);
}

int main (void){
 DDRB=0xFF;
 PORTB=0xFF;
 for(;;){
  char keyCode=getkp();
  switch(keyCode){
   case 0:
   PORTB ^=1<<PINB1;
   break;
   case 1:
   PORTB ^=1<<PINB2;
   break;
  }
 }
 
}

When stepping through the code I noticed a couple strange issues.

These lines

rowcode=PIND & 0x0F;       //7,b,d,e=row 0,1,2,3
if(rowcode != 0x0F) break; //this col has a row lo 

So if I understand correctly, without any buttons being pressed, the value of PIND will be 0x00 and then PIND & 0x0F (to check for a value on PIND0-PIND3?) will make PIND still 0x00. Then the if statement is testing for rowcode (0x00) == 0x0F seems to pass the test. Maybe I am not understanding the degugger as it jumps around.

and if I type in the immediate window to print getkp() I get an error...Call to unknown function:getkp

 

What do I need to do to get this working?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

without any buttons being pressed, the value of PIND will be 0x00

No one can possibly know until you show a diagram of how the switches are wired, but as you have PORTB as all outputs and high I would say no.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js, thanks.

The switches are a matrix style where the switches are connected in a row and column. something like:

Do you see anything wrong in the code as to why it isn't working?

PORTB is not used for the keypad...was this a typo?

Last Edited: Fri. Jan 30, 2015 - 09:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nowhere can i see where you initialise DDRD. It should be set to 0xF0

This code has an issue as it drives the columns high and low. This is bad as combinations of keypresses may short the output pins causing high current. Instead the colums should be all inputs except the one selected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

Instead the colums should be all inputs except the one selected.

Or, they can be open drain.  Sometimes more than one may be driven.

There is one class of KeyScan that holds 4 lines low, and then uses a pin-change interrupt to Alert the MCU to run the scan-one- at-a-time code to decide which key.

 

For lowest power, the pins are LOW drive (no pullups) when in 4 low mode, and then Pullups are enabled during scan mode.

 

If you scan by removing a Drive line, and checking for change, you can decode 20 buttons on 8 pins (or use 7 pins for 16 buttons)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yikes. Looks like a program I wrote. Is it working? I hope?

 

Imagecraft compiler user