View RSS Feed

andre_teprom

Scan code for parallel read on matrix keypad

Rate this Entry
Requests for sample C code to deal with a matrix keypad is a recurrent question, what motivated me to share here some tips on an alternative implementation, not so widely employed.

This code brings some benefits:
  • Allows reading combinations of multiple keys pressed at same row: 8(4 keys), 32(3keys), 48(2keys), 16(1key)
  • A little faster, due just 2 nibble scans are performed, instead 16 bit scan, performed on the classical approach.


Find bellow its implementation, fully tested on a 51 core, with a single adaptation for PIC core:

Code:
/* ********************************************************************** */
#define ROW_MASK        0x0F
#define COLUMN_MASK     0xF0
#define NO_KEY          0x00
/* ********************************************************************** */
unsigned int ScanKey ( void )
{
unsigned int ReadingKey                                ;
TRISx = COLUMN_MASK                                    ;  // Set high nible as Input and low nible as Output ( not tested )
PORTx = ROW_MASK                                       ;  // Output "1" value for low nible
Delay ( STEADY_OUTPUT )                                ;  // wait a few for charging parasitic capacitance on Port
ReadingKey = (~( PORTx | COLUMN_MASK ))                ;  // Read only high nible at "ReadingKey"
if ( ReadingKey )                                      ;  // If some key were pressed...
   {
   TRISx = ~COLUMN_MASK                                ;  // Set low nible as Input and high nible as Output ( not tested )
   PORTx =  COLUMN_MASK                                ;  // Output "1" value for high  nible
   Delay ( STEADY_OUTPUT )                             ;  // wait a few for charging parasitic capacitance on Port
   ReadingKey |= (~( PORTx | ROW_MASK ))               ;  // Read only low  nible at "ReadingKey" ( but now, add to previous read  )
   return ( ReadingKey )                               ;
   }
   else return ( NO_KEY )                              ;  // ...otherwise, returns "0"
}
/* ********************************************************************** */
//            KEY DEFINITIONS
//            ---------------
//
//          Px.4 Px.5 Px.6 Px.7
//                          
// Px.0    --0----1----2----3-                        
//           |    |    |    |
// Px.1    --4----5----6----7-
//           |    |    |    |     ROW_MASK ( 00001111 )
// Px.2    --8----9----A----B-
//           |    |    |    |
// Px.3    --C----D----E----F-
//
//             COLUMN_MASK ( 11110000 )
//
//
//
//           KEY MAPPING 
//           -----------
//
//   "0"    [ BIT0 + 0    + 0    + 0    + BIT4 + 0    + 0    + 0    ]
//   "1"    [ BIT0 + 0    + 0    + 0    + 0    + BIT5 + 0    + 0    ]
//   "2"    [ BIT0 + 0    + 0    + 0    + 0    + 0    + BIT6 + 0    ]
//   ...    [                        ...                            ]
//   "E"    [ 0    + 0    + 0    + BIT3 + 0    + 0    + BIT6 + 0    ]
//   "F"    [ 0    + 0    + 0    + BIT3 + 0    + 0    + 0    + BIT7 ]
//   ...
//   "0|3"  [ BIT0 + 0    + 0    + 0    + BIT4 + 0    + 0    + BIT7 ]
//   "4|6"  [ 0    + BIT1 + 0    + 0    + BIT4 + 0    + BIT6 + 0    ]
//
//    BITn = ( 1 << n )
Important advice that presented code merely performs kernel scan feature, so that additional features ( e.g debounce ) must be performed for functions which instantiate it.





+++

Comments

  1. rusty81's Avatar
    Very smart, good job man! ;)
    I'm wondering abount a nobounce check, it could be a simple compare after each ReadingKey, something like:

    Code:
    unsigned int ScanKey ( void )
    {
    unsigned int ReadingKey, ReadingKey_                ;
    TRISx = COLUMN_MASK                                    ;  // Set high nible as Input and low nible as Output ( not tested )
    PORTx = ROW_MASK                                       ;  // Output "1" value for low nible
    Delay ( STEADY_OUTPUT )                                ;  // wait a few for charging parasitic capacitance on Port
    
    do
    {
    ReadingKey = (~( PORTx | COLUMN_MASK ))                ;  // Read only high nible at "ReadingKey"
    Delay (10 to 15 ms)                                                      ; // After a while time
    ReadingKey_ = (~( PORTx | COLUMN_MASK ))                ;  // perform read check
    }
    while (ReadingKey~=ReadingKey_);
    
    if ( ReadingKey )                                      ;  // If some key were pressed...
       {
       TRISx = ~COLUMN_MASK                                ;  // Set low nible as Input and high nible as Output ( not tested )
       PORTx =  COLUMN_MASK                                ;  // Output "1" value for high  nible
       Delay ( STEADY_OUTPUT )                             ;  // wait a few for charging parasitic capacitance on Port
       
       do
       {
       ReadingKey |= (~( PORTx | ROW_MASK ))               ;  // Read only low  nible at "ReadingKey" ( but now, add to previous read  )
       Delay(10 to 15 ms)                                                  ; // After a while time 
       ReadingKey_ |= (~( PORTx | ROW_MASK ))              ; // perform read check
       }
       while (ReadingKey~=ReadingKey_);
    
       return ( ReadingKey )                               ;
       }
       else return ( NO_KEY )                              ;  // ...otherwise, returns "0"
    }
    What do you think?

    Regards
  2. nick703's Avatar
    nice one bro !!!!!!
  3. andre_teprom's Avatar
    Quote Originally Posted by rusty81
    Very smart, good job man! ;)
    I'm wondering abount a nobounce check, it could be a simple compare after each ReadingKey, something like...
    Hi rusty81,

    That´s a nice improvement you gave, thanks.
    Anyway, due there are numerous methods for achieving debouncing ( someones even external to scan routine ), the objective was to present a "clean" code just for instructive purpose.