s3c2440裸機-電阻觸控式螢幕程式設計(4.isr設計_4.2支援長按和滑動)
1.改進定時器
五. irq之定時器中斷這記一節中,是在handle_irq_c()中去區分中斷源,執行不同的isr。那現在通過register_timer註冊對應的定時器中斷服務程式,timer_irq進行執行不同的定時器中斷服務程式。
#define TIMER_NUM 32 #define NULL ((void *)0) typedef void(*timer_func)(void); typedef struct timer_desc { char *name; timer_func fp; }timer_desc, *p_timer_desc;
timer_desc timer_array[TIMER_NUM];int register_timer(char *name, timer_func fp) { int i; for (i = 0; i < TIMER_NUM; i++) { if (!timer_array[i].fp) { timer_array[i].name = name; timer_array[i].fp = fp; return 0; } } return -1; } void unregister_timer(char *name) { int i; for (i = 0; i < TIMER_NUM; i++) {if (!strcmp(timer_array[i].name, name)) { timer_array[i].name = NULL; timer_array[i].fp = NULL; return 0; } } return -1; } void timer_irq(void) { int i; for (i = 0; i < TIMER_NUM; i++) { if (timer_array[i].fp) { timer_array[i].fp(); } } }
舉個列子:
我們想要用timer來進行進行流水燈實驗,那麼假如點燈函式為:
Isr_timer_led(){}
那麼則只需要在led init的時候進行呼叫register_timer(“led”, Isr_timer_led), 那麼當時間到後觸發定時器中斷,便會執行timer_irq.進入Isr_timer_led。
2.初始化定時器
五. irq之定時器中斷的PWM定時器有詳細介紹。這裡只貼出code部分:
void timer_init(void) { /* 設定TIMER0的時鐘 */ /* Timer clk = PCLK / {prescaler value+1} / {divider value} = 50000000/(49+1)/16 = 62500 */ TCFG0 = 49; /* Prescaler 0 = 49, 用於timer0,1 */ TCFG1 &= ~0xf; TCFG1 |= 3; /* MUX0 : 1/16 */ /* 設定TIMER0的初值 */ TCNTB0 = 625; /* 10Ms中斷一次 */ /* 載入初值, 啟動timer0 */ TCON |= (1<<1); /* Update from TCNTB0 & TCMPB0 */ /* 設定為自動載入並啟動 */ TCON &= ~(1<<1); TCON |= (1<<0) | (1<<3); /* bit0: start, bit3: auto reload */ /* 設定中斷 */ register_irq(10, timer_irq); }
3.支援長按和滑動
我們之前是2s timer觸發一次中斷,那如果是要支援觸控式螢幕,我們必須讓定時器10ms就觸發一次中斷。因此需要修改timer_init中的暫存器引數。
按下觸控式螢幕會產生TSC中斷,然後啟動ADC進而產生adc中斷的時候,在Isr_Adc函式中進行定時器的設定,檢測長按和滑動操作。
3.1定義touchscreen_timer_irq
static volatile int g_ts_timer_enable = 0; static void ts_timer_enable(void) { g_ts_timer_enable = 1; } static void ts_timer_disable(void) { g_ts_timer_enable = 0; } static int get_status_of_ts_timer(void) { return g_ts_timer_enable; } /* 每10ms該函式被呼叫一次 */ void touchscreen_timer_irq(void) { if (get_status_of_ts_timer() == 0) return; if (ADCDAT0 & (1<<15)) /* 如果鬆開 */ { ts_timer_disable(); enter_wait_pen_down_mode(); return; } /* 如果觸控式螢幕仍被按下, 進入"自動測量模式", 啟動ADC */ else /* 按下狀態 */ { /* 進入"自動測量"模式 */ enter_auto_measure_mode(); /* 啟動ADC */ ADCCON |= (1<<0); } }
3.2 register_timer("tsc_timer_irq", touchscreen_timer_irq )
void touchscreen_init(void) { /* 設定觸控式螢幕介面:暫存器 */ adc_ts_reg_init(); /* 設定中斷 */ adc_ts_int_init(); /* 註冊定時器處理函式 */ register_timer("touchscreen", touchscreen_timer_irq); /* 讓觸控式螢幕控制器進入"等待中斷模式" */ enter_wait_pen_down_mode(); } void Isr_Adc(void) { int x = ADCDAT0; int y = ADCDAT1; if (!(x & (1<<15))) /* 如果仍然按下才列印 */ { x &= 0x3ff; y &= 0x3ff; printf("x = %08d, y = %08d\n\r", x, y); /* 啟動定時器以再次讀取資料 */ ts_timer_enable(); } else { ts_timer_disable(); enter_wait_pen_down_mode(); } enter_wait_pen_up_mode(); }
我們來分析一下這個程式的過程:
①在touchscreen_init的時候我們先註冊了一個timer,然後修改了定時器的產生中斷的時間間隔為10ms中斷一次,所以touchscreen_timer_irq會每間隔10ms呼叫一次。沒有按下,則touchscreen_timer_irq雖然也有走,但是就直接return.
②然後如果按下觸控式螢幕,產生tsc中斷,啟動adc,產生adc中斷。
如果產生了adc中斷,但是讀取狀態發現已經鬆開了,則進入”等待按下狀態“,並且讓touchscreen_timer_irq失效。那麼要是狀態是被按下,則開啟ts_timer_enable。
③當使能touchscreen_timer_irq這個定時器中斷服務程式後,並且10ms到了touchscreen_timer_irq函式執行生效。
如果鬆開了,則進入”等待按下狀態“,並且讓touchscreen_timer_irq失效,表示沒有長按或者滑動。
如果任然按下,輸出長按或者滑動後的座標結果。