Number 1 can be destructive for your controller. If you would use push-pull outputs for the columns, and the rows as inputs, then pressing two keys on the same row will short circuit the power supply through the microcontroller's outputs. If the microcontroller's outputs can be configured as open-drain, then there's no problem, but the outputs must have pull-up resistors as well. Then you basically have number 2, but with the pull-ups integrated.
Number 2. Same story if you would use the rows as outputs. Using the columns as outputs makes more sense, since R1-R3 avoid a short-circuit of the outputs. Note that a low output level will see the series/pull-up resistor as a voltage divider, so that the input will be 0.1 Vcc, though that's usually not a problem.
Number 3 avoids the divider, but the resistors on the inputs don't serve any function. A variant without the series resistor will do.
So 1) may be an absolute no-no. 3) is a bit better than 2) because it doesn't have the voltage divider, but can do without the series resistor.
The switch statement looks overly complicated, and at least to me wasn't immediately obvious what it was doing. I would go with a more straightforward implementation.
Like Abdullah said, delays after you set TRISD
and PORTD
registers may help, as well as debouncing the input.
Finally, I would get a o-scope and/or multimeter to probe on these pins to make sure everything is connected properly, toggling as expected, and make sure the keypad behaves as expected.
EDIT:
I noticed that there are internal Schmitt Triggers on PORTD
inputs that are enabled by default. This will inject some latency, though I'm not sure how much, as the datasheet doesn't say.
EDIT2 :
Added hard delays before sampling and capacitive charge removal
int getKey(void)
{
// Like Abdullah said, these can be bytes
// Also, you can save image space by not initializing these
unsigned char toRet;
unsigned char firstHalf, secHalf;
// Clear lines (attempt to get rid of capacitive charge)
TRISD = 0xff; // Hop off
PORTD = 0x00; // Prepare to drive low
TRISD = 0x00; // Drive all lines
__delay_us(10000);// Wait arbitrary about of time
TRISD = 0xff; // Stop driving while we change values
// Drive first half
PORTD = 0xf0;
TRISD = 0x0f; // Hex makes things easier to read
__delay_us(10000);
firstHalf = (PORTD & 0x0f) >> 0; // Mask only the stuff we care about
TRISD = 0xff;
// Clear lines
PORTD = 0x00;
TRISD = 0x00;
__delay_us(10000);
TRISD = 0xff;
// Drive second half
PORTD = 0x0f;
TRISD = 0xf0;
__delay_us(10000);
secHalf = (PORTD & 0xf0) >> 4; // Mask only the stuff we care about
// and shift the nibble we care about down
TRISD = 0xff;
// Simple selection logic
// Keep in mind that if multiple keys are pressed, this function will return "null"
switch (firstHalf) {
case 0x1:
switch (secHalf) {
case 0x1: toRet = 7; break; //1
case 0x2: toRet = 8; break; //2
case 0x4: toRet = 9; break; //3
default: toRet = 255; break; //null
}
break;
case 0x2:
switch (secHalf) {
case 0x1: toRet = 4; break; //4
case 0x2: toRet = 5; break; //5
case 0x4: toRet = 6; break; //6
default: toRet = 255; break; //null
}
break;
case 0x4:
switch (secHalf) {
case 0x1: toRet = 1; break; //7
case 0x2: toRet = 2; break; //8
case 0x4: toRet = 3; break; //9
default: toRet = 255; break; //null
}
break;
case 0x8:
switch (secHalf) {
case 0x1: toRet = 10; break; //*
case 0x2: toRet = 0; break; //9
case 0x4: toRet = 11; break; //#
default: toRet = 255; break; //null
}
break;
default: toRet = 255; break; //null
}
return toRet;
}
Best Answer
Using the following keywords in a search engine> 4x4 keyboard 10 pin One quickly finds several solutions.
Confirm that it matches your pinout using an ohm-meter or by following traces.
Located here with software http://www.mikroe.com/eng/downloads/get/1215/keypad_manual_v100.pdf