觸摸屏歸納為輸入子系統(tǒng),這里主要是針對電阻屏,其使用過程如下 當(dāng)用觸摸筆按下時,產(chǎn)生中斷。 在中斷處理函數(shù)處理函數(shù)中啟動ADC轉(zhuǎn)換x,y坐標(biāo)。 ADC結(jié)束,產(chǎn)生ADC中斷 在ADC中斷處理函數(shù)里上報(input_event)啟動定時器 再次啟動定時器(可以處理滑動、長按) 松開按鍵 其驅(qū)動程序的寫法和之前寫輸入子系統(tǒng)的寫法基本上一致。 寫出入口函數(shù),出口函數(shù)并加以修飾,加入相關(guān)頭文件,然后開始完善各函數(shù),在入口函數(shù)中分配input_dev結(jié)構(gòu)體,設(shè)置(能產(chǎn)生哪類事件,能產(chǎn)生這類事件中的哪些事件),注冊設(shè)備,硬件相關(guān)的操作等。出口函數(shù)中主要對之前注冊、分配的一些資源進(jìn)行釋放。 還應(yīng)根據(jù)2440數(shù)據(jù)手冊ADC轉(zhuǎn)換和觸摸屏那一章,對相關(guān)寄存器根據(jù)實際需要進(jìn)行設(shè)置。 點擊(此處)折疊或打開 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct s3c_ts_regs { /* 相關(guān)的寄存器 */ unsigned long adccon; unsigned long adctsc; unsigned long adcdly; unsigned long adcdat0; unsigned long adcdat1; unsigned long adcupdn; }; static struct input_dev *s3c_ts_dev; static volatile struct s3c_ts_regs *s3c_ts_regs; static struct timer_list ts_timer; void enter_wait_pen_down_mode(void) /* 進(jìn)入等待觸摸筆按下模式 */ { s3c_ts_regs->adctsc = 0xd3; /* 進(jìn)入等待中斷模式 bit[8]為0 2440手冊P442 */ } void enter_wait_pen_up_mode(void) /* 進(jìn)入等待觸摸筆松開模式 */ { s3c_ts_regs->adctsc = 0x1d3; /* 進(jìn)入等待中斷模式 bit[8]為1 2440手冊P442 */ } static void enter_measure_xy_mode(void) /* 進(jìn)入xy測量模式 */ { s3c_ts_regs->adctsc = (1<<3) | (1<<2); } static void start_adc(void) { s3c_ts_regs->adccon |= (1<<0); /* 啟動ADC */ } static int s3c_filter_ts(int x[, int y[) /* 軟件過濾 */ { #define ERR_LIMIT 10 /* 經(jīng)驗值,容差值 */ int avr_x, avr_y; int det_x, det_y; avr_x = (x[0 + x[1)/2; avr_y = (y[0 + y[1)/2; det_x = (x[2 > avr_x) ? (x[2 - avr_x) : (avr_x - x[2); det_y = (y[2 > avr_y) ? (y[2 - avr_y) : (avr_y - y[2); if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT)) return 0; avr_x = (x[1 + x[2)/2; avr_y = (y[1 + y[2)/2; det_x = (x[3 > avr_x) ? (x[3 - avr_x) : (avr_x - x[3); det_y = (y[3 > avr_y) ? (y[3 - avr_y) : (avr_y - y[3); if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT)) return 1; } static void s3c_ts_timer_functions(unsigned long data) { if (s3c_ts->adcdat0 & (1<<15)) /* 假設(shè)時間到 */ { /* 如果觸摸已經(jīng)松開 */ input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上報事件,壓力值為0 */ input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(s3c_ts_dev); /* 上報完后要同步 */ enter_wait_pen_down_mode(); /* 進(jìn)入觸摸等待模式 */ } else { /* 否則測量x,y坐標(biāo) */ enter_measure_xy_mode(); start_adc(); } } static irqreturn_t pen_down_up_irq(int irq, void *dev id) { if (s3c_ts->adcdat0 & (1<<15)) /* 2440手冊P447 ADCDAT0寄存器 */ { printk("pen up\n"); enter_wait_pen_down_mode(); } else { //printk("pen down\n"); //enter_wait_pen_up_mode(); enter_measure_xy_mode(); start_adc(); } return IRQ_HANDLED; } static irqreturn_t adc_irq(int irq, void *dev id) { static int cnt = 0; static int x[4, y[4; int adcdat0, adcdat1; /* 優(yōu)化措施2 * 如果ACD完成時,發(fā)現(xiàn)觸摸筆已松開,則丟棄此次結(jié)果 */ adcdat0 = s3c_ts_regs->adcdat0; adcdat1 = s3c_ts_regs->adcdat1; if (s3c_ts->adcdat0 & (1<<15)) /* bit[15判斷是否松開 */ { /* 如果已經(jīng)松開則丟棄結(jié)果 */ cnt = 0; input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上報事件,壓力值為0 */ input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(s3c_ts_dev); enter_wait_pen_up_mode(); } else { /* 如果還是按下,則打印結(jié)果并進(jìn)入等待松開模式 */ //printk("adc_irq cnt = %d,x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff); /* 優(yōu)化措施3: * 多次測量取平均值 */ x[cnt = adcdat0 & 0x3ff; /* 將測量結(jié)果存入靜態(tài)變量中 */ y[cnt = adcdat1 & 0x3ff; ++cnt; if (cnt == 4) { /* 優(yōu)化措施4 * 軟件過濾 */ if (s3c_filter_ts(x, y)) { //printk("x = %d, y = %d\n", (x[0+x[1+x[2+x[3)/4, (y[0+y[1+y[2+y[3)/4); input_report_abs(s3c_ts_dev, ABS_X, (x[0+x[1+x[2+x[3)/4); input_report_abs(s3c_ts_dev, ABS_Y, (y[0+y[1+y[2+y[3)/4); input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1); input_report_key(s3c_ts_dev, BTN_TOUCH, 1); input_sync(s3c_ts_dev); } cnt = 0; /* cnt計數(shù)清0 */ enter_wait_pen_up_mode(); /* 測量完后要進(jìn)入等待松開模式,這樣才能連續(xù)操作 */ /* 啟動定時器處理長按/滑動的情況 */ mod_timer(&ts_timer, jiffies + HZ/100); /* 1HZ/100 = 10ms */ } else /* 否則再測量一次 */ { enter_measure_xy_mode(); start_adc(); } } return IRQ_HANDLED; } static int s3c_ts_init(void) { struct clk* clk; /* 1.分配一個input_dev結(jié)構(gòu)體 */ s3c_ts_dev = input_allocate_device(); /* 2.設(shè)置 */ /* 2.1 能產(chǎn)生哪類事件 */ set_bit(EV_KEY, s3c_ts_dev->evbit); /* 能夠產(chǎn)生按鍵事件 */ set_bit(EV_ABS, s3c_ts_dev->evbit); /* 能夠產(chǎn)生絕對位移事件 */ /* 2.2 能產(chǎn)生這類事件里的哪些事件 */ set_bit(BTN_TOUCH, s3c_ts_dev->evbit); /* 能夠產(chǎn)生按鍵類里面的觸摸屏事件 */ input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); /* X方向 0xFF是因為觸摸屏ADC是10位 */ input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); /* Y方向 */ input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);/* 壓力方向 */ /* 3.注冊 */ input_register_device(s3c_ts_dev); /* 4.硬件相關(guān)的操作 */ /* 4.1 使能時鐘CLKCON[15 (總開關(guān),一般對不用的設(shè)備,時鐘一般是關(guān)閉的) */ clk = clk_get(NULL, "adc"); clk_enable(clk); /* 4.2 設(shè)置S3c2440的ADC/TS寄存器 */ s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs)); /* ADCCON * bit[14 : 1 預(yù)分頻使能 * bit[13:6 : 預(yù)分頻系數(shù) * 49 ,ADCCLK = PCLK/(49+1) = 50MHz/(49+1)=1MHz * bit[5:3 : 多路選擇 * bit[2 : 省電模式選擇 * bit[1 : AD啟動方式,通過讀來啟動 * bit[0 : 啟動AD轉(zhuǎn)換,啟動后會自動清零 */ s3c_ts_regs->adccon = (1<<14) | (49<<6); request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL); request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL); /* 優(yōu)化措施1 * 設(shè)置ADCDLY為最大值,使得電壓穩(wěn)定后再發(fā)出中斷IRQ_TC */ s3c_ts_regs->adcdly = 0xffff; /* 優(yōu)化措施5 * 使用定時器,用來解決連按或滑動 */ init_timer(&ts_timer); ts_timer.function = s3c_ts_timer_function; add_timer(&ts_timer); enter_wait_pen_down_mode(); return 0; } static void s3c_ts_exit(void) { free_irq(IRQ_TC, NULL); free_irq(IRQ_ADC, NULL); iounmap(s3c_ts_regs); input_unregister_device(s3c_ts_dev); input_free_device(s3c_ts_dev); del_timer(&ts_timer); } module_init(s3c_ts_init); module_exit(s3c_ts_exit); MODULE_DESCRIPTION("s3c_ts driver for the s3c2440"); MODULE_LICENSE("GPL"); 測試方法主要是檢測上報事件是否正常,要想更好的測試,需要移植ts_lib這方面的資料網(wǎng)上都可以找到。 以tslib-1.4.tar.gz為例 sudo apt-get install autoconf sudo apt-get install automake sudo apt-get install libtool 編譯: tar xzf tslib-1.4.tar.gz cd tslib ./autogen.sh mkdir tmp // 安裝目錄 echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache ./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp make make install 安裝: cd tmp cp * -rf /nfsroot // /nfsroot可根據(jù)實際情況來定 使用: 先安裝s3c_ts.ko, lcd.ko // lcd.ko是之前編譯好的LCD驅(qū)動,如果后面編譯s3c_ts時改過配置,直接裝載之前編譯好的lcd.ko可能會出現(xiàn)段錯誤,重新編譯一下lcd驅(qū)動就可以了。 1. 修改 /etc/ts.conf第1行(去掉#號和第一個空格): # module_raw input 改為: module_raw input 2. export TSLIB_TSDEVICE=/dev/event0 export TSLIB_CALIBFILE=/etc/pointercal export TSLIB_CONFFILE=/etc/ts.conf export TSLIB_PLUGINDIR=/lib/ts export TSLIB_CONSOLEDEVICE=none export TSLIB_FBDEVICE=/dev/fb0 ts_calibrate ts_test 更多C語言 C++、JAVA、數(shù)電模電、51單片機(jī)、PIC stm32 ARM Linux驅(qū)動 嵌入式、安卓系統(tǒng) FPGA、DSP Cortex-M3學(xué)習(xí) 請咨詢 朱工,騰訊QQ3208919269 中國移動15088133726 深圳南山、民治、龍崗、西鄉(xiāng)、長沙、鄭州、南寧同步學(xué)習(xí)中! 理論與實踐相結(jié)合 一線工程師項目經(jīng)理教學(xué) 結(jié)合真實的產(chǎn)品案列 讓你感受前所未有的電子產(chǎn)品的開發(fā)流程 2015給自己一個決心,只為自己!高薪就業(yè)不是夢,有想法你就來 IT達(dá)人等著你!!! |