Scan code for parallel read on matrix keypad

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.





+++
Reactions: dmathis1

Comments

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

[COLOR="#FF0000"]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_);[/COLOR]

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
   
   [COLOR="#FF0000"]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_);[/COLOR]

   return ( ReadingKey )                               ;
   }
   else return ( NO_KEY )                              ;  // ...otherwise, returns "0"
}

What do you think?

Regards
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…