Wednesday 13 February 2019

microcontroller - avr-gcc keypad interfacing code problem



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 is KEYPAD_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

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...