/********************************************************************
* Keypad.c
* This module will be a altered version of the uCOSKey we used in ETEC 454
* A keypad module that runs under MicroC/OS for a 2x4 matrix keypad.
* This version allows for multiple column keys to be pressed and
* mapped to a different code by changing ColTable[] in KeyScan().
* Multiple rows can not be resolved. The top most button will be used.
* The KeyCodeTable[] is currently set to generate ASCII codes.
* 02/20/2001 TDM Original key.c for 9S12
* 01/14/2013 TDM Modified for K70 custom tower board.
* 02/12/2013 TDM Modified to run under MicroC/OS-III
* 04/05/2015 Dylan and Josh editing for use with 2x4 tactile switch keypad
*********************************************************************
* Project master header file
********************************************************************/
#include "includes.h"
/********************************************************************
* Module Defines
* This version is designed for the custom LCD/Keypad board, which
* has the following mapping:
*  COL1->PTA14, COL2->PTA15, COL3->PTA16, COL4->PTA17
*  ROW1->PTA12, ROW2->PTA13
********************************************************************/
typedef enum{KEY_OFF,KEY_EDGE,KEY_VERF} KEYSTATES;
#define KEY_PORT_OUT   GPIOA_PDOR
#define KEY_PORT_DIR   GPIOA_PDDR
#define KEY_PORT_IN    GPIOA_PDIR
#define COLS_MASK 0x3C000  //0x0078 Change for PORT A 0x0003C000
#define ROWS_MASK 0x03000  //0x0780 change for Port A 0x00003000
#define DC1 (INT8U)0x11     /*ASCII control code for the A button */
#define DC2 (INT8U)0x12     /*ASCII control code for the B button */
#define DC3 (INT8U)0x13     /*ASCII control code for the C button */
#define DC4 (INT8U)0x14     /*ASCII control code for the D button */
typedef struct{
    INT8U buffer;
    OS_SEM flag;
}KEY_BUFFER;
/********************************************************************
* Public Resources
********************************************************************/
INT8U KeyPend(INT16U tout, OS_ERR *err);
void KeyInit(void);

/********************************************************************
* Private Resources
********************************************************************/
static INT8U KeyScan(void);         /* Makes a single keypad scan  */
static const INT8U KeyCodeTable[8] = {'1','2','3',DC1,'4','5','6',DC2};
static void KeyDly(void);  /* Added for GPIO to settle before read */
static void uCOSKeyTask(void *p_arg);
static KEY_BUFFER Key;
/**********************************************************************************
* Allocate task control blocks
**********************************************************************************/
static OS_TCB uCOSKeyTaskTCB;
/*************************************************************************
* Allocate task stack space.
*************************************************************************/
static CPU_STK uCOSKeyTaskStk[APP_CFG_KEY_TASK_STK_SIZE];
/********************************************************************
* KeyPend() - A function to provide access to the key buffer via a
*             semaphore.
*    - Public
********************************************************************/
INT8U KeyPend(INT16U tout, OS_ERR *os_err){
	OSSemPend(&(Key.flag),tout, OS_OPT_PEND_BLOCKING, (CPU_TS *)0, os_err);
	return(Key.buffer);
}
/********************************************************************
* KeyInit() - Initialization routine for the keypad module
*             The columns are normally set as inputs and, since they
*             are pulled high, they are one. Then to pull a row low
*             during scanning, the direction for that pin is changed
*             to an output.
********************************************************************/
void KeyInit(void){

    OS_ERR os_err;
	/* Key port init */
    PORTA_PCR14 =(0|PORT_PCR_MUX(1)|PORT_PCR_PS_MASK|PORT_PCR_PE_MASK);
    PORTA_PCR15 =(0|PORT_PCR_MUX(1)|PORT_PCR_PS_MASK|PORT_PCR_PE_MASK);
    PORTA_PCR16 =(0|PORT_PCR_MUX(1)|PORT_PCR_PS_MASK|PORT_PCR_PE_MASK);  //(GPIO|0x1u|0x2u)
    PORTA_PCR17 =(0|PORT_PCR_MUX(1)|PORT_PCR_PS_MASK|PORT_PCR_PE_MASK);
    PORTA_PCR12 = (0|PORT_PCR_MUX(1));
	PORTA_PCR13 = (0|PORT_PCR_MUX(1));
    KEY_PORT_OUT &= ~ROWS_MASK;            /* Preset all rows to zero    */
    // Initialize the Key Buffer and semaphore
    Key.buffer = 0x00;           /* Init KeyBuffer      */
    OSSemCreate(&(Key.flag),"Key Semaphore",0,&os_err);
    while(os_err != OS_ERR_NONE){           /* Error Trap                        */
    }
    //Create the key task
    OSTaskCreate((OS_TCB     *)&uCOSKeyTaskTCB,
                (CPU_CHAR   *)"uCOS Key Task ",
                (OS_TASK_PTR ) uCOSKeyTask,
                (void       *) 0,
                (OS_PRIO     ) APP_CFG_KEY_TASK_PRIO,
                (CPU_STK    *)&uCOSKeyTaskStk[0],
                (CPU_STK     )(APP_CFG_KEY_TASK_STK_SIZE / 10u),
                (CPU_STK_SIZE) APP_CFG_KEY_TASK_STK_SIZE,
                (OS_MSG_QTY  ) 0,
                (OS_TICK     ) 0,
                (void       *) 0,
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                (OS_ERR     *)&os_err);
    while(os_err != OS_ERR_NONE){           /* Error Trap                     */
    }
}
/********************************************************************
* KeyTask() - Read the keypad and updates KeyBuffer.
*             A task decomposed into states for detecting and
*             verifying keypresses. This task should be called
*             periodically with a period greater than the worst case
*             switch bounce time and less than the shortest switch
*             activation time minus the bounce time. The switch must
*             be released to have multiple acknowledged presses.
* (Public)
********************************************************************/
static void uCOSKeyTask(void *p_arg) {

    OS_ERR os_err;
    INT8U cur_key;
    INT8U last_key = 0;
    KEYSTATES KeyState = KEY_OFF;
    (void)p_arg;
    while(1){
    	OSTimeDly(8,OS_OPT_TIME_PERIODIC,&os_err);
        while(os_err != OS_ERR_NONE){           /* Error Trap                 */
        }
        cur_key = KeyScan();
        if(KeyState == KEY_OFF){    /* Key released state */
            if(cur_key != 0){
                KeyState = KEY_EDGE;
            }else{ /* wait for key press */
            }
        }else if(KeyState == KEY_EDGE){     /* Keypress detected state*/
            if(cur_key == last_key){        /* Keypress verified */
                KeyState = KEY_VERF;
                Key.buffer = KeyCodeTable[cur_key - 1]; /*update buffer */
                (void)OSSemPost(&(Key.flag), OS_OPT_POST_1, &os_err);   /* Signal new data in buffer */
                while(os_err != OS_ERR_NONE){           /* Error Trap                        */
                }
            }else if( cur_key == 0){        /* Unvalidated, start over */
                KeyState = KEY_OFF;
            }else{                          /*Unvalidated, diff key edge*/
            }
        }else if(KeyState == KEY_VERF){     /* Keypress verified state */
            if((cur_key == 0) || (cur_key != last_key)){
                KeyState = KEY_OFF;
            }else{ /* wait for release or key change */
            }
        }else{ /* In case of error */
            KeyState = KEY_OFF;             /* Should never get here */
        }
        last_key = cur_key;                 /* Save key for next time */
    }
}
/********************************************************************
* KeyScan() - Scans the keypad and returns a keycode.
*           - Designed for 2x4 keypad with columns pulled high.
*           - Current keycodes follow:
*               1->0x01,2->0x02,3->0x03,A->0x04
*               4->0x05,5->0x06,6->0x07,B->0x08
*           - Returns zero if no key is pressed.
*           - ColTable[] can be changed to distinguish multiple keys
*             pressed in the same row.
* (Private)
********************************************************************/
static INT8U KeyScan(void) {

    INT8U kcode;
    INT8U roff;
    INT32U rbit;
    const INT8U ColTable[9] = {0,1,2,2,3,3,3,3,4};
    rbit = 0x1000;
    roff = 0x00;
    while(rbit != 0){ /* Until all rows are scanned */
        KEY_PORT_OUT &= ~ROWS_MASK;
        KEY_PORT_DIR = (KEY_PORT_DIR & ~ROWS_MASK)|rbit;    /* Pull row low */
        KeyDly();	// wait for direction and col inputs to settle
        kcode = (INT8U)(((~KEY_PORT_IN) & COLS_MASK)>>14);  /*Read columns */
        KEY_PORT_DIR = (KEY_PORT_DIR &~ROWS_MASK);
        if(kcode != 0){        /* generate key code if key pressed */
            kcode = roff + ColTable[kcode];
            break;
        }
        rbit = ROWS_MASK & (rbit<<1);       /* setup for next row */
        roff += 4;							
    }
    return (kcode);
}
/********************************************************************
 * KeyDly() a software delay for KeyScan() to wait until port row
 * bit direction and column inputs are settled .
 * With debug bits included and a 120Mhz bus the delay is
 * 	Tdly = (83.2ns)i + 128ns
 * Currently set to ~830ns with i=10.
 * TDM 01/20/2013
 *******************************************************************/
static void KeyDly(void){
	INT32U i;
	for(i=0;i<10;i++){
	}
}

Previous Page