1. 程式人生 > 其它 >s3c2440裸機-電阻觸控式螢幕程式設計(4.isr設計_4.2支援長按和滑動)

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失效,表示沒有長按或者滑動。

如果任然按下,輸出長按或者滑動後的座標結果。