新華 ARM9 S3C2410 實驗版 - 鍵盤程式追蹤

原理

1. 首先利用 void Initial_TIMER0(void) 中的 register_irq(IRQ_TIMER0, TIMER0_ISR, "Timer ISR")
   註冊 TIMER0_ISR 函數,該函數即會在 void CIrqHandler(void) 函數中被呼叫如下
    ..
    irq_table[IRQindex].handler();
    ..
   CirqHandler 乃為中斷向量處理函數,因此、只要時間計數器一觸發,就會被執行
    ..
    b        IrqHnd
    b        FiqHnd
    ...
    IrqHnd:
        stmdb    sp!,{r0-r12,lr}
        bl    CIrqHandler
        ldmia    sp!,{r0-r12,lr}
        subs    pc,lr,#4
    ...

2. void  TIMER0_ISR(void) 函數中,藉由掃描的方式,掃描四次後即可解出按鍵碼
     Keypad 功能主要藉由程式對 IO_REG2 的位元 0-3 代表的 SCAN_Ox 輸出 0 後,接著藉由 IO_REG1 
     的位元 8-11 代表的 SCAN_Ix 所讀入的資料,來判斷該列中 4 個 key 的哪一個 key 被按下了,
     (參考 : 課本 (實作版) 5-5 頁), 然後將 key 放入 scan_key_buf[16] 陣列中暫存。

3. 使用者可以藉由呼叫 KEYPAD_get_key(UC *ch) 函數以取出按鍵值,或藉由 UC KEYPAD_chk_key(UC *ch)
   以檢查按鍵值。

程式追蹤片段

===========================/7SEG/demo.c==========================
int main(void)
{
    int i;    
         irq_init();    
        Initial_Creator();    
        enable_irq();        

     while (1)
         {   
               UC ch;

           while(KEYPAD_get_key(&ch) != OK);
        for (i=0;i<80;i++)
        {
               IO_REG0 = 0x0e00+LED_tb5[ch];
        Delay(2);

             IO_REG0 = 0x0d00+LED_tb5[ch];
         Delay(2);       

             IO_REG0 = 0x0b00+LED_tb5[ch];
        Delay(2);      

             IO_REG0 = 0x0700+LED_tb5[ch];
        Delay(2);          
              }
         }        

        disable_irq();
        return(0);
}

==========================/7SEG/driver.c ===============================

/* KEY_PAD */
UI scan_led=0x5500;
UC scan_key, scan_idx, scan_key_in_idx, scan_key_out_idx;
UI scan_key_buf[16], last_scan_key;
UC key_assigned;

/*************************************************************************
4X4 KEY PAD
*************************************************************************/
#define KEY_0         0xdfff
#define KEY_1         0xfffe
#define KEY_2         0xfffd
#define KEY_3         0xfffb
#define KEY_4         0xffef
#define KEY_5         0xffdf
#define KEY_6         0xffbf
#define KEY_7         0xfeff
#define KEY_8         0xfdff
#define KEY_9         0xfbff
#define KEY_A         0xfff7
#define KEY_B         0xff7f
#define KEY_C         0xf7ff
#define KEY_D         0x7fff
#define KEY_STAR     0xefff
#define KEY_POND     0xbfff

UC Creator_key2num(UI ch);

void Initial_KEYPAD(void)
{
        UC i;

        last_scan_key = 0xffff;
        scan_key_in_idx = 0;
        scan_key_out_idx = 0;
        key_assigned = UM;
        for(i=0; i<16; i++)    scan_key_buf[i] = 0xffff;

}

UC KEYPAD_get_key(UC *ch)
{
        UI temp;

        if(scan_key_out_idx != scan_key_in_idx) {
            temp = scan_key_buf[scan_key_out_idx++];
            scan_key_out_idx &= 0xf;
            *ch = Creator_key2num(temp);
            return(OK);
        }
        return(UM);
}

UC KEYPAD_chk_key(UC *ch)
{
        UI temp;

        if(scan_key_out_idx != scan_key_in_idx) {
            temp = scan_key_buf[scan_key_out_idx];
            *ch = Creator_key2num(temp);
            return(OK);
        }
        return(UM);
}

UI key2num_tbl[16] = {
        KEY_0, KEY_1, KEY_2, KEY_3,
        KEY_4, KEY_5, KEY_6, KEY_7,
        KEY_8, KEY_9, KEY_A, KEY_B,
        KEY_C, KEY_D, KEY_STAR, KEY_POND
        };

UC Creator_key2num(UI ch)
{
        UC idx;
        for(idx=0; idx<16; idx++) {
            if(ch == key2num_tbl[idx]) return(idx);
        }
        return(0xff);
}

==========================================================================
/*************************************************************************
System TICK (TIMER0)
*************************************************************************/
void  TIMER0_ISR(void) 
{
        UN_CVT cvt;        

        tick_ms++;

        //IOPDATA ^= 0x20000;    //Test
        if((tick_ms & 3) == 0) {    //scan time = 4 * 3ms;  for 7_SEG LED 
            seven_seg_idx++;
            seven_seg_idx &= 3;
            IO_REG0 = io_reg0 | tbl_7seg_com[seven_seg_idx] | seven_seg_buf[seven_seg_idx];
        }
        if((tick_ms & 0xf) == 0) { // 每 16 個 tick 秒取得輸入一次.
            if((scan_key_in_idx+1) == scan_key_out_idx) {    //Key_Pad Overfllow
                //TODO
            }
            else {
                if(FPGA_ON == OK) {
                    IO_REG2 = scan_led | 0xff;
                    SCAN_OUT = 0xfe;
                    cvt.b[0] = (UC)(FPGA_STATUS & 0xf);
                    SCAN_OUT = 0xfd;
                    cvt.b[0] |= (UC)((FPGA_STATUS & 0xf) << 4);
                    SCAN_OUT = 0xfb;
                    cvt.b[1] = (UC)(FPGA_STATUS & 0xf);
                    SCAN_OUT = 0xf7;
                    cvt.b[1] |= (UC)((FPGA_STATUS & 0xf) << 4);
                }
                else {
                // Keypad 功能主要藉由程式對 IO_REG2 的位元 0-3 代表的 SCAN_Ox 輸出 0 後,
                                // 接著藉由 IO_REG1 的位元 8-11 代表的 SCAN_Ix 所讀入的資料,來判斷該列中
                                // 4 個 key 的哪一個 key 被按下了,參考 : 課本 (實作版) 5-5 頁.
                    IO_REG2 = scan_led | 0xfe;
                    cvt.b[0] = (UC)((IO_REG1 & 0x0f00) >> 8);
                    IO_REG2 = scan_led | 0xfd;
                    cvt.b[0] |= (UC)((IO_REG1 & 0x0f00) >> 4);
                    IO_REG2 = scan_led | 0xfb;
                    cvt.b[1] = (UC)((IO_REG1 & 0x0f00) >> 8);
                    IO_REG2 = scan_led | 0xf7;
                    cvt.b[1] |= (UC)((IO_REG1 & 0x0f00) >> 4);
                }
                if(last_scan_key == cvt.w[0]) {
                    if(key_assigned == UM) {  // UM = 0, flag.
                        if(cvt.w[0] != 0xffff) {
                            scan_key_buf[scan_key_in_idx++] = cvt.w[0];
                            scan_key_in_idx &= 0xf;
                        }
                        key_assigned = OK;
                    }
                }
                else {
                    key_assigned = UM;
                }
                last_scan_key = cvt.w[0];
            }
        }
        if((tick_ms % 1000) == 0) {
            //tick_ms = 0;
            tick_on = OK;
            tick_sec++;
            if(tick_sec >= 60) {
                tick_sec = 0;
                tick_min++;
                if(tick_min >= 60) {
                    tick_min = 0;
                    tick_hour++;
                }
            }
        }    
        ClearPending(BIT_TIMER0);
}

==============================def.h========================================
#define IO_REG0            (*(volatile unsigned short *)(IO_BASE+0x0C00))  // 七段顯示器
#define IO_REG1         (*(volatile unsigned short *)(IO_BASE+0x0C02))    // DIP SWITCH 和 Keypad 鍵盤讀入
#define IO_REG2         (*(volatile unsigned short *)(IO_BASE+0x0C04))    // LED 和 Keypad scan 輸出
...

/***********************************************************************
        union reference size
************************************************************************/
#define BYTE1   3
#define BYTE2   2
#define BYTE3   1
#define BYTE4   0
#define WORD1   1
#define WORD2   0

// 注意,重要 ! 
//   CVT 是聯集,因此、設定了 l, w[2], b[4] 中的任一組,就等於設定了
//   全部三個.

typedef union   CVT {
        UL  l ;
        UI  w[2] ;
        UC  b[4] ;
} UN_CVT;

================================driver.c=====================================
/* keywoard : ClockParameter */
/***************  Clock Parameter  **********/
void Initial_TIMER0(void)
{
        rTCFG0 = (rTCFG0 & ~(0xff)) | SYS_TIMER01_PRESCALER;
        rTCFG1 = (rTCFG1 &~(0xf)) | (SYS_TIMER0_MUX);
        rTCNTB0  = (TIMER0_RESCHED_PERIOD*PCLK)/
                ((SYS_TIMER01_PRESCALER +1)*(SYS_TIMER1_DIVIDER)*1000);
        rTCMPB0 = 0;
        //Auto reload, Inverter off, Manual update, Stop, Dead zone disable
        rTCON   = rTCON & ~(0xffffff) | 0x6aaa0a;  
        //Auto reload, Inverter off, No operation, Start, Dead zone disable
        rTCON   = rTCON & ~(0xffffff) | 0x599909;  

        tick_on = UM;
        tick_ms = 0;
        tick_sec = 0;
        tick_min = 0;
        tick_hour = 0;
        register_irq(IRQ_TIMER0, TIMER0_ISR, "Timer ISR"); // 重要 !
        ClearPending(BIT_TIMER0);
        EnableInterrupt(BIT_TIMER0);               
}

/*************************************************************************
System TICK (TIMER0)
*************************************************************************/
void  TIMER0_ISR(void) 
{
        UN_CVT cvt;        

        tick_ms++;

        //IOPDATA ^= 0x20000;    //Test
        if((tick_ms & 3) == 0) {    //scan time = 4 * 3ms;  for 7_SEG LED 
            seven_seg_idx++;
            seven_seg_idx &= 3;
            IO_REG0 = io_reg0 | tbl_7seg_com[seven_seg_idx] | seven_seg_buf[seven_seg_idx];
        }
        if((tick_ms & 0xf) == 0) {
            if((scan_key_in_idx+1) == scan_key_out_idx) {    //Key_Pad Overfllow
                //TODO
            }
            else {
                if(FPGA_ON == OK) {
                    IO_REG2 = scan_led | 0xff;
                    SCAN_OUT = 0xfe;
                    cvt.b[0] = (UC)(FPGA_STATUS & 0xf);
                    SCAN_OUT = 0xfd;
                    cvt.b[0] |= (UC)((FPGA_STATUS & 0xf) << 4);
                    SCAN_OUT = 0xfb;
                    cvt.b[1] = (UC)(FPGA_STATUS & 0xf);
                    SCAN_OUT = 0xf7;
                    cvt.b[1] |= (UC)((FPGA_STATUS & 0xf) << 4);
                }
                else {
                    // 重要:設定 b[0..1] 的同時,也就設定了 cvt.w[0].
                    IO_REG2 = scan_led | 0xfe;
                    cvt.b[0] = (UC)((IO_REG1 & 0x0f00) >> 8); 
                    IO_REG2 = scan_led | 0xfd;
                    cvt.b[0] |= (UC)((IO_REG1 & 0x0f00) >> 4);
                    IO_REG2 = scan_led | 0xfb;
                    cvt.b[1] = (UC)((IO_REG1 & 0x0f00) >> 8);
                    IO_REG2 = scan_led | 0xf7;
                    cvt.b[1] |= (UC)((IO_REG1 & 0x0f00) >> 4);
                }
                if(last_scan_key == cvt.w[0]) {
                    if(key_assigned == UM) {
                        if(cvt.w[0] != 0xffff) {
                            scan_key_buf[scan_key_in_idx++] = cvt.w[0];
                            scan_key_in_idx &= 0xf;
                        }
                        key_assigned = OK;
                    }
                }
                else {
                    key_assigned = UM;
                }
                last_scan_key = cvt.w[0];
            }
        }
        if((tick_ms % 1000) == 0) {
            //tick_ms = 0;
            tick_on = OK;
            tick_sec++;
            if(tick_sec >= 60) {
                tick_sec = 0;
                tick_min++;
                if(tick_min >= 60) {
                    tick_min = 0;
                    tick_hour++;
                }
            }
        }    
        ClearPending(BIT_TIMER0);
}

=====================================irq.c=====================================
static struct irq_entry irq_table[IRQ_INT_NO];

void irq_init (void)
{
    int        i;

    for(i=0; i < IRQ_INT_NO; i++){
        irq_table[i].handler = NULL;        
    }        
}

void register_irq(unsigned int Id, void (*handler)(void), char *name)
{
    if ((Id >= 0) && (Id < IRQ_INT_NO)){
        if (!irq_table[Id].handler){
            irq_table[Id].handler = handler;        
            strncpy(irq_table[Id].name, name, IRQ_NAME_SIZE);
            //INT_MASK_SET = 1<<id;
        }else{
            //printf("Error %s: irq %d already claimed by %s\n\r",name,id,irq_table[priority].name);        
        }
    }
}

void unregister_irq(unsigned int id, char* name)
{
    /* check for owneship of the irq and then unregister it */
    if(!strncmp(irq_table[id].name, name, sizeof(irq_table[id].name))){
        //INT_MASK_CLEAR = 1<<id;
        irq_table[id].handler=NULL;
        irq_table[id].name[0]='\0';
    }else{
        //printf("Error %s: not owner of irq %d \n\r",name,id);
    }
}

void CIrqHandler(void)
{
    int IRQindex;

    IRQindex = rINTOFFSET ;
    if ((IRQindex >= 0) && (IRQindex < IRQ_INT_NO)) {
        if(irq_table[IRQindex].handler){
            irq_table[IRQindex].handler();
        } else {
            printf("Error, no irq registered for irq %d\n\r",irq_table[IRQindex].id);
        }            
    }
}

void CFiqHandler(void)
{
    /* This shouldn't happen, but let's trap it just in case */
    //printf("Unexpected FIQ\r\n");
    return;
}

========================================head.s================================
stext:
    b        ResetHandler
    b        UdefHnd
    b        SwiHnd
    b        PabtHnd
    b        DabtHnd
    b        Unexpected
    b        IrqHnd
    b        FiqHnd

...
IrqHnd:
    stmdb    sp!,{r0-r12,lr}
    bl        CIrqHandler
    ldmia    sp!,{r0-r12,lr}
    subs    pc,lr,#4
...
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License