www.pudn.com > ucosii_block.rar > KEY.C


/* 
********************************************************************************************************* 
*                                    Embedded Systems Building Blocks 
*                                 Complete and Ready-to-Use Modules in C 
* 
*                                         Matrix Keyboard Driver 
* 
*                            (c) Copyright 1999, Jean J. Labrosse, Weston, FL 
*                                           All Rights Reserved 
* 
* Filename   : KEY.C 
* Programmer : Jean J. Labrosse 
********************************************************************************************************* 
*                                             DESCRIPTION 
* 
*    The keyboard is assumed to be a matrix having 4 rows by 6 columns.  However, this code works for any 
* matrix arrangements up to an 8 x 8 matrix.  By using from one to three of the column inputs, the driver 
* can support "SHIFT" keys.  These keys are: SHIFT1, SHIFT2 and SHIFT3. 
* 
*    Your application software must declare (see KEY.H): 
* 
*    KEY_BUF_SIZE            Size of the KEYBOARD buffer 
* 
*    KEY_MAX_ROWS            The maximum number of rows    on the keyboard 
*    KEY_MAX_COLS            The maximum number of columns on the keyboard 
* 
*    KEY_RPT_DLY             Number of scan times before auto repeat executes the function again 
*    KEY_RPT_START_DLY       Number of scan times before auto repeat function engages 
* 
*    KEY_SCAN_TASK_DLY       The number of milliseconds between keyboard scans 
*    KEY_SCAN_TASK_PRIO      Sets the priority of the keyboard scanning task 
*    KEY_SCAN_TASK_STK_SIZE  The size of the keyboard scanning task stack 
* 
*    KEY_SHIFT1_MSK          The mask which determines which column input handles the SHIFT1 key 
*                                (A 0x00 indicates that a SHIFT1 key is not present) 
*    KEY_SHIFT1_OFFSET       The scan code offset to add when the SHIFT1 key is pressed 
* 
*    KEY_SHIFT2_MSK          The mask which determines which column input handles the SHIFT2 key 
*                                (A 0x00 indicates that an SHIFT2 key is not present) 
*    KEY_SHIFT2_OFFSET       The scan code offset to add when the SHIFT2 key is pressed 
* 
*    KEY_SHIFT3_MSK          The mask which determines which column input handles the SHIFT3 key 
*                                (A 0x00 indicates that a SHIFT3 key is not present) 
*    KEY_SHIFT3_OFFSET       The scan code offset to add when the SHIFT3 key is pressed 
* 
* 
*    KEY_PORT_ROW            The port address of the keyboard matrix ROWs 
*    KEY_PORT_COL            The port address of the keyboard matrix COLUMNs 
*    KEY_PORT_CW             The port address of the keyboard I/O ports control word 
* 
*    KeyInitPort, KeySelRow() and KeyGetCol() are the only three hardware specific functions.  This has 
*    been done to localize the interface to the hardware in only these two functions and thus make is 
*    easier to adapt to your application. 
********************************************************************************************************* 
*/ 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                              INCLUDE FILES 
********************************************************************************************************* 
*/ 
 
#include "includes.h" 
 
/* 
********************************************************************************************************* 
*                                            LOCAL CONSTANTS 
********************************************************************************************************* 
*/ 
 
#define KEY_STATE_UP                 1      /* Key scanning states used in KeyScan()                   */ 
#define KEY_STATE_DEBOUNCE           2 
#define KEY_STATE_RPT_START_DLY      3 
#define KEY_STATE_RPT_DLY            4 
 
/* 
********************************************************************************************************* 
*                                            GLOBAL VARIABLES 
********************************************************************************************************* 
*/ 
 
static  INT8U     KeyBuf[KEY_BUF_SIZE];     /* Keyboard buffer                                         */ 
static  INT8U     KeyBufInIx;               /* Index into key buf where next scan code will be inserted*/ 
static  INT8U     KeyBufOutIx;              /* Index into key buf where next scan code will be removed */ 
static  INT16U    KeyDownTmr;               /* Counts how long key has been pressed                    */ 
static  INT8U     KeyNRead;                 /* Number of keys read from the keyboard                   */ 
 
static  INT8U     KeyRptStartDlyCtr;        /* Number of scan times before auto repeat is started      */ 
static  INT8U     KeyRptDlyCtr;             /* Number of scan times before auto repeat executes again  */ 
 
static  INT8U     KeyScanState;             /* Current state of key scanning function                  */ 
 
static  OS_STK    KeyScanTaskStk[KEY_SCAN_TASK_STK_SIZE];  /* Keyboard scanning task stack             */ 
 
static  OS_EVENT *KeySemPtr;                               /* Pointer to keyboard semaphore            */ 
 
/* 
********************************************************************************************************* 
*                                       LOCAL FUNCTION PROTOTYPES 
********************************************************************************************************* 
*/ 
 
static  void      KeyBufIn(INT8U code);     /* Insert scan code into keyboard buffer                   */ 
static  INT8U     KeyDecode(void);          /* Get scan code from current key pressed                  */ 
static  BOOLEAN   KeyIsKeyDown(void);       /* See if key has been pressed                             */ 
static  void      KeyScanTask(void *data);  /* Keyboard scanning task                                  */ 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                INSERT KEY CHARACTER INTO KEYBOARD BUFFER 
* 
* Description : This function inserts a key character into the keyboard buffer 
* Arguments   : code    is the keyboard scan code to insert into the buffer 
* Returns     : none 
********************************************************************************************************* 
*/ 
 
static  void  KeyBufIn (INT8U code) 
{ 
    OS_ENTER_CRITICAL();                         /* Start of critical section of code, disable ints    */ 
    if (KeyNRead < KEY_BUF_SIZE) {               /* Make sure that we don't overflow the buffer        */ 
        KeyNRead++;                              /* Increment the number of keys read                  */ 
        KeyBuf[KeyBufInIx++] = code;             /* Store the scan code into the buffer                */ 
        if (KeyBufInIx >= KEY_BUF_SIZE) {        /* Adjust index to the next scan code to put in buffer*/ 
            KeyBufInIx = 0; 
        } 
        OS_EXIT_CRITICAL();                      /* End of critical section of code                    */ 
        OSSemPost(KeySemPtr);                    /* Signal sem if scan code inserted in the buffer     */ 
    } else {                                     /* Buffer is full, key scan code is lost              */ 
        OS_EXIT_CRITICAL();                      /* End of critical section of code                    */ 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                           DECODE KEYBOARD 
* 
* Description : This function is called to determine the key scan code of the key pressed. 
* Arguments   : none 
* Returns     : the key scan code 
********************************************************************************************************* 
*/ 
 
static  INT8U  KeyDecode (void) 
{ 
    INT8U   col; 
    INT8U   row; 
    INT8U   offset; 
    BOOLEAN done; 
    INT8U   col_id; 
    INT8U   msk; 
 
 
    done = FALSE; 
    row  = 0; 
    while (row < KEY_MAX_ROWS && !done) {             /* Find out in which row key was pressed         */ 
        KeySelRow(row);                               /* Select a row                                  */ 
        if (KeyIsKeyDown()) {                         /* See if key is pressed in this row             */ 
            done = TRUE;                              /* We are done finding the row                   */ 
        } else { 
            row++;                                    /* Select next row                               */ 
        } 
    } 
    col    = KeyGetCol();                             /* Read columns                                  */ 
    offset = 0;                                       /* No SHIFT1, SHIFT2 or SHIFT3 key pressed       */ 
    if (col & KEY_SHIFT1_MSK) {                       /* See if SHIFT1 key was also pressed            */ 
        offset += KEY_SHIFT1_OFFSET; 
    } 
    if (col & KEY_SHIFT2_MSK) {                       /* See if SHIFT2 key was also pressed            */ 
        offset += KEY_SHIFT2_OFFSET; 
    } 
    if (col & KEY_SHIFT3_MSK) {                       /* See if SHIFT3 key was also pressed            */ 
        offset += KEY_SHIFT3_OFFSET; 
    } 
    msk    = 0x01;                                    /* Set bit mask to scan for the column           */ 
    col_id =    0;                                    /* Set column value (0..7)                       */ 
    done   = FALSE; 
    while (col_id < KEY_MAX_COLS && !done) {          /* Go through all columns                        */ 
        if (col & msk) {                              /* See if key was pressed in this columns        */ 
            done  = TRUE;                             /* Done, i has column value of the key (0..7)    */ 
        } else { 
            col_id++; 
            msk <<= 1; 
        } 
    } 
    return (row * KEY_MAX_COLS + offset + col_id);    /* Return scan code                              */ 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                         FLUSH KEYBOARD BUFFER 
* 
* Description : This function clears the keyboard buffer 
* Arguments   : none 
* Returns     : none 
********************************************************************************************************* 
*/ 
 
void  KeyFlush (void) 
{ 
    while (KeyHit()) {                           /* While there are keys in the buffer...              */ 
        KeyGetKey(0);                            /* ... extract the next key from the buffer           */ 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                                 GET KEY 
* 
* Description : Get a keyboard scan code from the keyboard driver. 
* Arguments   : 'to'     is the amount of time KeyGetKey() will wait (in number of ticks) for a key to be 
*                        pressed.  A timeout of '0' means that the caller is willing to wait forever for 
*                        a key to be pressed. 
* Returns     : != 0xFF  is the key scan code of the key pressed 
*               == 0xFF  indicates that there is no key in the buffer within the specified timeout 
********************************************************************************************************* 
*/ 
 
INT8U  KeyGetKey (INT16U to) 
{ 
    INT8U code; 
    INT8U err; 
 
 
    OSSemPend(KeySemPtr, to, &err);              /* Wait for a key to be pressed                       */ 
    OS_ENTER_CRITICAL();                         /* Start of critical section of code, disable ints    */ 
    if (KeyNRead > 0) {                          /* See if we have keys in the buffer                  */ 
        KeyNRead--;                              /* Decrement the number of keys read                  */ 
        code = KeyBuf[KeyBufOutIx];              /* Get scan code from the buffer                      */ 
        KeyBufOutIx++; 
        if (KeyBufOutIx >= KEY_BUF_SIZE) {       /* Adjust index into the keyboard buffer              */ 
            KeyBufOutIx = 0; 
        } 
        OS_EXIT_CRITICAL();                      /* End of critical section of code                    */ 
        return (code);                           /* Return the scan code of the key pressed            */ 
    } else { 
        OS_EXIT_CRITICAL();                      /* End of critical section of code                    */ 
        return (0xFF);                           /* No scan codes in the buffer, return -1             */ 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                  GET HOW LONG KEY HAS BEEN PRESSED 
* 
* Description : This function returns the amount of time the key has been pressed. 
* Arguments   : none 
* Returns     : key down time in 'milliseconds' 
********************************************************************************************************* 
*/ 
 
INT32U  KeyGetKeyDownTime (void) 
{ 
    INT16U tmr; 
 
 
    OS_ENTER_CRITICAL(); 
    tmr = KeyDownTmr; 
    OS_EXIT_CRITICAL(); 
    return (tmr * KEY_SCAN_TASK_DLY); 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                        SEE IF ANY KEY IN BUFFER 
* 
* Description : This function checks to see if a key was pressed 
* Arguments   : none 
* Returns     : TRUE   if a key has been pressed 
*               FALSE  if no key pressed 
********************************************************************************************************* 
*/ 
 
BOOLEAN  KeyHit (void) 
{ 
    BOOLEAN hit; 
 
 
    OS_ENTER_CRITICAL(); 
    hit = (BOOLEAN)(KeyNRead > 0) ? TRUE : FALSE; 
    OS_EXIT_CRITICAL(); 
    return (hit); 
} 
 
/* 
********************************************************************************************************* 
*                                       KEYBOARD INITIALIZATION 
* 
* Description: Keyboard initialization function.  KeyInit() must be called before calling any other of 
*              the user accessible functions. 
* Arguments  : none 
* Returns    : none 
********************************************************************************************************* 
*/ 
 
void  KeyInit (void) 
{ 
    KeySelRow(KEY_ALL_ROWS);                     /* Select all row                                     */ 
    KeyScanState = KEY_STATE_UP;                 /* Keyboard should not have a key pressed             */ 
    KeyNRead     = 0;                            /* Clear the number of keys read                      */ 
    KeyDownTmr   = 0; 
    KeyBufInIx   = 0;                            /* Key codes inserted at  the beginning of the buffer */ 
    KeyBufOutIx  = 0;                            /* Key codes removed from the beginning of the buffer */ 
    KeySemPtr    = OSSemCreate(0);               /* Initialize the keyboard semaphore                  */ 
    KeyInitPort();                               /* Initialize I/O ports used in keyboard driver       */ 
    OSTaskCreate(KeyScanTask, (void *)0, &KeyScanTaskStk[KEY_SCAN_TASK_STK_SIZE], KEY_SCAN_TASK_PRIO); 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                           SEE IF KEY PRESSED 
* 
* Description : This function checks to see if a key is pressed 
* Arguments   : none 
* Returns     : TRUE   if a key is     pressed 
*               FALSE  if a key is not pressed 
* Note        : (1 << KEY_MAX_COLS) - 1   is used as a mask to isolate the column inputs (i.e. mask off 
*                                         the SHIFT keys). 
********************************************************************************************************* 
*/ 
 
static  BOOLEAN  KeyIsKeyDown (void) 
{ 
    if (KeyGetCol() & ((1 << KEY_MAX_COLS) - 1)) {         /* Key not pressed if 0                     */ 
        OS_ENTER_CRITICAL(); 
        KeyDownTmr++;                                      /* Update key down counter                  */ 
        OS_EXIT_CRITICAL(); 
        return (TRUE); 
    } else { 
        return (FALSE); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                         KEYBOARD SCANNING TASK 
* 
* Description : This function contains the body of the keyboard scanning task.  The task should be 
*               assigned a low priority.  The scanning period is determined by KEY_SCAN_TASK_DLY. 
* Arguments   : 'data'   is a pointer to data passed to task when task is created (NOT USED). 
* Returns     : KeyScanTask() never returns. 
* Notes       : - An auto repeat of the key pressed will be executed after the key has been pressed for 
*                 more than KEY_RPT_START_DLY scan times.  Once the auto repeat has started, the key will 
*                 be repeated every KEY_RPT_DLY scan times as long as the key is pressed.  For example, 
*                 if the scanning of the keyboard occurs every 50 mS and KEY_RPT_START_DLY is set to 40 
*                 and KEY_RPT_DLY is set to 2, then the auto repeat function will engage after 2 seconds 
*                 and will repeat every 100 mS (10 times per second). 
********************************************************************************************************* 
*/ 
 
/*$PAGE*/ 
static  void  KeyScanTask (void *data) 
{ 
    INT8U code; 
 
 
    data = data;                                           /* Avoid compiler warning (uC/OS-II req.)   */ 
    for (;;) { 
        OSTimeDlyHMSM(0, 0, 0, KEY_SCAN_TASK_DLY);         /* Delay between keyboard scans             */ 
        switch (KeyScanState) { 
            case KEY_STATE_UP:                             /* See if need to look for a key pressed    */ 
                 if (KeyIsKeyDown()) {                     /* See if key is pressed                    */ 
                     KeyScanState = KEY_STATE_DEBOUNCE;    /* Next call we will have debounced the key */ 
                     KeyDownTmr   = 0;                     /* Reset key down timer                     */ 
                 } 
                 break; 
 
            case KEY_STATE_DEBOUNCE:                       /* Key pressed, get scan code and buffer    */ 
                 if (KeyIsKeyDown()) {                     /* See if key is pressed                    */ 
                     code              = KeyDecode();      /* Determine the key scan code              */ 
                     KeyBufIn(code);                       /* Input scan code in buffer                */ 
                     KeyRptStartDlyCtr = KEY_RPT_START_DLY;/* Start delay to auto-repeat function      */ 
                     KeyScanState      = KEY_STATE_RPT_START_DLY; 
                 } else { 
                     KeySelRow(KEY_ALL_ROWS);              /* Select all row                           */ 
                     KeyScanState      = KEY_STATE_UP;     /* Key was not pressed after all!           */ 
                 } 
                 break; 
 
            case KEY_STATE_RPT_START_DLY: 
                 if (KeyIsKeyDown()) {                     /* See if key is still pressed              */ 
                     if (KeyRptStartDlyCtr > 0) {          /* See if we need to delay before auto rpt  */ 
                         KeyRptStartDlyCtr--;              /* Yes, decrement counter to start of rpt   */ 
                         if (KeyRptStartDlyCtr == 0) {     /* If delay to auto repeat is completed ... */ 
                             code         = KeyDecode();   /* Determine the key scan code              */ 
                             KeyBufIn(code);               /* Input scan code in buffer                */ 
                             KeyRptDlyCtr = KEY_RPT_DLY;   /* Load delay before next repeat            */ 
                             KeyScanState = KEY_STATE_RPT_DLY; 
                         } 
                     } 
                 } else { 
                     KeyScanState = KEY_STATE_DEBOUNCE;    /* Key was not pressed after all            */ 
                 } 
                 break; 
 
            case KEY_STATE_RPT_DLY: 
                 if (KeyIsKeyDown()) {                     /* See if key is still pressed              */ 
                     if (KeyRptDlyCtr > 0) {               /* See if we need to wait before repeat key */ 
                         KeyRptDlyCtr--;                   /* Yes, dec. wait time to next key repeat   */ 
                         if (KeyRptDlyCtr == 0) {          /* See if it's time to repeat key           */ 
                             code         = KeyDecode();   /* Determine the key scan code              */ 
                             KeyBufIn(code);               /* Input scan code in buffer                */ 
                             KeyRptDlyCtr = KEY_RPT_DLY;   /* Reload delay counter before auto repeat  */ 
                         } 
                     } 
                 } else { 
                     KeyScanState = KEY_STATE_DEBOUNCE;    /* Key was not pressed after all            */ 
                 } 
                 break; 
        } 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                              READ COLUMNS 
* 
* Description : This function is called to read the column port. 
* Arguments   : none 
* Returns     : the complement of the column port thus, ones are keys pressed 
********************************************************************************************************* 
*/ 
 
#ifndef CFG_C 
INT8U  KeyGetCol (void) 
{ 
    return (~inp(KEY_PORT_COL));                 /* Complement columns (ones indicate key is pressed)  */ 
} 
#endif 
 
 
/* 
********************************************************************************************************* 
*                                         INITIALIZE I/O PORTS 
********************************************************************************************************* 
*/ 
 
#ifndef CFG_C 
void  KeyInitPort (void) 
{ 
    outp(KEY_PORT_CW, 0x82);                     /* Initialize 82C55: A=OUT, B=IN (COLS), C=OUT (ROWS) */ 
} 
#endif 
 
 
/* 
********************************************************************************************************* 
*                                            SELECT A ROW 
* 
* Description : This function is called to select a row on the keyboard. 
* Arguments   : 'row'  is the row number (0..7) or KEY_ALL_ROWS 
* Returns     : none 
* Note        : The row is selected by writing a LOW. 
********************************************************************************************************* 
*/ 
 
#ifndef CFG_C 
void  KeySelRow (INT8U row) 
{ 
    if (row == KEY_ALL_ROWS) { 
        outp(KEY_PORT_ROW, 0x00);                /* Force all rows LOW                                 */ 
    } else { 
        outp(KEY_PORT_ROW, ~(1 << row));         /* Force desired row LOW                              */ 
    } 
} 
#endif