/******************************************************************************************/ /* KeyScan.c Example of keypad interfacing */ /* */ /* By: J. Winpenny */ /* Date: 4/8/2000 */ /* */ /* */ /* */ /* */ /* */ /* */ /* See the schematic: Keypadex.pdf */ /* */ /* */ /* Notes: */ /* Files required: */ /* LCD873.c */ /* keyhead.h */ /* */ /* */ /* Revision: */ /* */ /* */ /******************************************************************************************/ #include #pragma CLOCK_FREQ 3579450 // LCD Functions void WaitBusyFlag(void); void LCDSetup(void); void FunctionMode(void); void DataMode(void); void Write_8_Bit(char); void Write_4_Bit(char); void Delay(void); void Clear(void); void SetPos(char); void Line1(void); void Line2(void); void ClearLine1(void); void ClearLine2(void); void WriteString( const char * ); char CheckKeyHit(void); char ScanKeys(void); void ProcessKey(void); void Setup(void); // Rows // 3 |--|--|--| // 2 |--|--|--| // 1 |--|--|--| // 0 |--|--|--| // Cols 0 1 2 3 #define KEYROWS PORTB #define KEYCOLS PORTC #define KEYCOL_BITS 0x0f // Columns on lower 4 bits of port C // Number of rows & columns #define N_ROWS 4 #define N_COLS 4 // Port bits of keyboard rows #define ROW0 0 #define ROW1 2 #define ROW2 3 #define ROW3 4 // Port bits of keyboard columns #define COL0 0 #define COL1 1 #define COL2 2 #define COL3 3 #define INVALID_KEY 255 char MyTimer; // Interrupt timer char KeyHit; // > 0 if key hit char Key; // key value char ScanRate; char cWidth; // For LCD width // Keyboard "layout" // --------- // 1 2 3 A // 4 5 6 B // 7 8 9 C // 0 F E D // --------- char KeyValues[] = { '0', 'F', 'E', 'D', '7', '8', '9', 'C', '4', '5', '6', 'B', '1', '2', '3', 'A' }; //*********************************** // Interrupt Handler //********************************** void interrupt( void ) { if ( ( INTCON & 0x04 ) != 0 ) // If the TIMER0 times-out { if ( ++MyTimer == ScanRate ) { MyTimer = 0; //********************************* // Insure we do not process the // same key hit twice ! //********************************* if ( KeyHit == False ) { if ( CheckKeyHit() ) { // If any key down KeyHit = True; // Get the key Key = ScanKeys(); } } } TMR0 = 0; // Reset TMR0 clear_bit( INTCON, T0IF ); } } //************************** // Main //************************** void main(void) { char c; char FirstTime; Setup(); KeyHit = False; ScanRate = 10; ClearLine1(); WriteString("Keypad Example"); ClearLine2(); WriteString("Press any key"); c = '0'; cWidth = 0; FirstTime = True; while(1) { //********************* // If any key hit then // process the key //********************* if ( KeyHit ) { // Clear line 2 of LCD on first keyhit if ( FirstTime ) { ClearLine2(); FirstTime = False; } // Process the key pressed ProcessKey(); } } } //****************************************** // Process the key last pressed //****************************************** void ProcessKey(void) { // If the key number is valid if ( Key != INVALID_KEY ) { //*********************************** // Get the key value from the array // and display on LCD //*********************************** if ( cWidth == LCD_WIDTH ) { ClearLine2(); cWidth = 0; } Write_4_Bit( KeyValues[Key] ); cWidth++; //******************************** // Wait for key to be released //******************************** while ( CheckKeyHit() == True ) { delay_ms(10); // Debounce delay } KeyHit = False; } } //****************************************** // Test for any key pressed // // Return True if any keys down //****************************************** char CheckKeyHit( void ) { //***************************** // Ground all keyboard rows //***************************** clear_bit( KEYROWS, ROW0 ); clear_bit( KEYROWS, ROW1 ); clear_bit( KEYROWS, ROW2 ); clear_bit( KEYROWS, ROW3 ); //****************************** // Are any columns grounded ? //****************************** if ( ( KEYCOLS & KEYCOL_BITS ) != KEYCOL_BITS ) { //******************************************* // Scan the keys to determine which key down //******************************************* return True; } else { return False; } } //********************************************** // Scan the keyboard and return the key number //********************************************** char ScanKeys(void) { char l_key; // The key number char a; // Temporary storage char scan_mask; // Yep ! The scan mask char count; // Counter for number of columns l_key = 255; // No key yet count = N_ROWS; scan_mask = 11111110b; while ( count != 0 ) { //****************************** // Ground row with scan mask //****************************** KEYROWS = scan_mask; // DANGER affects upper bits of PORT //****************************** // Are any columns grounded //****************************** a = KEYCOLS; if ( ( a & KEYCOL_BITS ) != KEYCOL_BITS ) { while( 1 ) { l_key = l_key + 1; //********************* // if column grounded //********************* if ( ( a & 0x01 ) == 0 ) { // exit with the key number ( 0 - NumberOfKeys ) return l_key; } a = a >> 1; } } //************************** // Shift scan pattern left //************************** scan_mask <<= 1; //******************* // Next key number //******************* l_key = l_key + N_COLS; count--; } //***************** // No key was hit //***************** return INVALID_KEY; } /*****************************************************/ /* Setup PIC16F873 options,ports,interrupts */ /*****************************************************/ void Setup(void) { // bit 2-0: PS2:PS0: Prescaler Rate Select bits // Bit Value TMR0 Rate WDT Rate //----------------------------------------- // 000 1 : 2 1 : 1 // 001 1 : 4 1 : 2 // 010 1 : 8 1 : 4 // 011 1 : 16 1 : 8 // 100 1 : 32 1 : 16 // 101 1 : 64 1 : 32 // 110 1 : 128 1 : 64 // 111 1 : 256 1 : 128 OPTION_REG = 10000011b; // pullups,prescailer = TMR0 , rate = 16:1; // set_bit( INTCON, PEIE ); // Enable all Peripheral Interrupts set_bit( INTCON, T0IE ); // Enable TMR0 Interrupt clear_bit( INTCON, T0IF ); // Clear TRMR0 Interrupr flag set_bit( INTCON, GIE ); // Enable Global Interrupts //PCON = 0x03; // Reset Power up status flags TRISA = PortAConfig; TRISB = PortBConfig; TRISC = PortCConfig; set_bit( STATUS, RP0 ); ADCON1 = 0x07; // Disable ADC clear_bit( STATUS, RP0 ); PORTC = 0xff; TMR0 = 0; PIR1 = 0; clear_wdt(); LCDSetup(); // Setup the LCD }