新華 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
...
page revision: 0, last edited: 07 Jul 2010 01:26
Post preview:
Close preview