I have this function to read key press from a 4x3 key-board:
uint8_t GetKeyPressed()
{
uint8_t r,c;
KEYPAD_PORT|= 0X0F;
for(c=0;c<3;c++)
{
KEYPAD_DDR&=~(0X7F);
KEYPAD_DDR|=(0X40>>c);
for(r=0;r<4;r++)
{
if(!(KEYPAD_PIN & (0X08>>r)))
{
return (r*3+c);
}
}
}
return 0XFF;//Indicate No key pressed
}
Some macro, I missed:
#define KEYPAD A
#define KEYPAD_PORT PORT(KEYPAD)
#define KEYPAD_DDR DDR(KEYPAD)
#define KEYPAD_PIN PIN(KEYPAD)
But I don't understand this code, pretty well, because of those bit shifting operations.
Can anyone help me with this code?
Compiler : avr-gcc
Micro-controller : ATmega328
Answer
In an abstract manner the code does this:
for each pin PA6 to PA4 (column)
set pin as output, driving '0'
for each pin PA3 to PA0 (row)
if pin reads '0' then
return key code calculated as row*3+column
return 0xFF as key code, meaning "no key"
KEYPAD_PORT|= 0X0F;
should preset the output register of the port with '0's for PA6 to PA4. The other pins (bit 7 and bits 3 to 0) are not relevant. But here is an error because of the operator|=
: If any of the bits 7 to 4 is already 1, it will keep this value. The correct statement isKEYPAD_PORT &= 0x8F;
.The
KEYPAD_DDR
register selects the direction of the pins of your keypad port. Each bit corresponds to a pin. Setting a bit to 1 make the pin an output, 0 an input.The
KEYPAD_PIN
register is used to read the pins of your keypad port.
Now to the shifting operations:
KEYPAD_DDR|=(0X40>>c);
: The hex value 0x40
is shifted to the right by the value of c
. This results in values of 0x40
(0b01000000
), 0x20
(0b00100000
), and 0x10
(0b00010000
). This value is then ORed to KEYPAD_DDR
which was ANDed before with the complement of 0x7F
= 0x80
(0b10000000
). The results are 0xC0
(0b11000000
), 0xA0
(0b10100000
), and 0x90
(0b10010000
), resp.
!(KEYPAD_PIN & (0X08>>r))
: The hex value 0x08
is shifted to the right by the value of r
. This results in values of 0x08
(0b00001000
), 0x04
(0b00000100
), 0x02
(0b00000010
), and 0x01
(0b00000001
). The value read from KEYPAD_PIN
is ANDed with this value, giving zero if the "masked" pin is '0' and non-zero otherwise. By the unary operator !
a zero is converted to true
and a non-zero to false
. So the statement of the if
will be executed if the masked pin is '0'.
Note: I like a lowercase 'X'/'B' better than the uppercase for hex and binary constants. But this is a bit of personal taste.
Only you can tell about the pin PA7. That's why I ignored it.
No comments:
Post a Comment