觸摸屏歸納為輸入子系統(tǒng),這里主要是針對(duì)電阻屏,其使用過(guò)程如下 當(dāng)用觸摸筆按下時(shí),產(chǎn)生中斷。 在中斷處理函數(shù)處理函數(shù)中啟動(dòng)ADC轉(zhuǎn)換x,y坐標(biāo)。 ADC結(jié)束,產(chǎn)生ADC中斷 在ADC中斷處理函數(shù)里上報(bào)(input_event)啟動(dòng)定時(shí)器 再次啟動(dòng)定時(shí)器(可以處理滑動(dòng)、長(zhǎng)按) 松開(kāi)按鍵 其驅(qū)動(dòng)程序的寫(xiě)法和之前寫(xiě)輸入子系統(tǒng)的寫(xiě)法基本上一致。 寫(xiě)出入口函數(shù),出口函數(shù)并加以修飾,加入相關(guān)頭文件,然后開(kāi)始完善各函數(shù),在入口函數(shù)中分配input_dev結(jié)構(gòu)體,設(shè)置(能產(chǎn)生哪類(lèi)事件,能產(chǎn)生這類(lèi)事件中的哪些事件),注冊(cè)設(shè)備,硬件相關(guān)的操作等。出口函數(shù)中主要對(duì)之前注冊(cè)、分配的一些資源進(jìn)行釋放。 還應(yīng)根據(jù)2440數(shù)據(jù)手冊(cè)ADC轉(zhuǎn)換和觸摸屏那一章,對(duì)相關(guān)寄存器根據(jù)實(shí)際需要進(jìn)行設(shè)置。 點(diǎn)擊(此處)折疊或打開(kāi) #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手冊(cè)P442 */ } void enter_wait_pen_up_mode(void) /* 進(jìn)入等待觸摸筆松開(kāi)模式 */ { s3c_ts_regs->adctsc = 0x1d3; /* 進(jìn)入等待中斷模式 bit[8]為1 2440手冊(cè)P442 */ } static void enter_measure_xy_mode(void) /* 進(jìn)入xy測(cè)量模式 */ { s3c_ts_regs->adctsc = (1<<3) | (1<<2); } static void start_adc(void) { s3c_ts_regs->adccon |= (1<<0); /* 啟動(dòng)ADC */ } static int s3c_filter_ts(int x[, int y[) /* 軟件過(guò)濾 */ { #define ERR_LIMIT 10 /* 經(jīng)驗(yàn)值,容差值 */ 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è)時(shí)間到 */ { /* 如果觸摸已經(jīng)松開(kāi) */ input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上報(bào)事件,壓力值為0 */ input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(s3c_ts_dev); /* 上報(bào)完后要同步 */ enter_wait_pen_down_mode(); /* 進(jìn)入觸摸等待模式 */ } else { /* 否則測(cè)量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手冊(cè)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完成時(shí),發(fā)現(xiàn)觸摸筆已松開(kāi),則丟棄此次結(jié)果 */ adcdat0 = s3c_ts_regs->adcdat0; adcdat1 = s3c_ts_regs->adcdat1; if (s3c_ts->adcdat0 & (1<<15)) /* bit[15判斷是否松開(kāi) */ { /* 如果已經(jīng)松開(kāi)則丟棄結(jié)果 */ cnt = 0; input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上報(bào)事件,壓力值為0 */ input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(s3c_ts_dev); enter_wait_pen_up_mode(); } else { /* 如果還是按下,則打印結(jié)果并進(jìn)入等待松開(kāi)模式 */ //printk("adc_irq cnt = %d,x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff); /* 優(yōu)化措施3: * 多次測(cè)量取平均值 */ x[cnt = adcdat0 & 0x3ff; /* 將測(cè)量結(jié)果存入靜態(tài)變量中 */ y[cnt = adcdat1 & 0x3ff; ++cnt; if (cnt == 4) { /* 優(yōu)化措施4 * 軟件過(guò)濾 */ 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計(jì)數(shù)清0 */ enter_wait_pen_up_mode(); /* 測(cè)量完后要進(jìn)入等待松開(kāi)模式,這樣才能連續(xù)操作 */ /* 啟動(dòng)定時(shí)器處理長(zhǎng)按/滑動(dòng)的情況 */ mod_timer(&ts_timer, jiffies + HZ/100); /* 1HZ/100 = 10ms */ } else /* 否則再測(cè)量一次 */ { enter_measure_xy_mode(); start_adc(); } } return IRQ_HANDLED; } static int s3c_ts_init(void) { struct clk* clk; /* 1.分配一個(gè)input_dev結(jié)構(gòu)體 */ s3c_ts_dev = input_allocate_device(); /* 2.設(shè)置 */ /* 2.1 能產(chǎn)生哪類(lèi)事件 */ set_bit(EV_KEY, s3c_ts_dev->evbit); /* 能夠產(chǎn)生按鍵事件 */ set_bit(EV_ABS, s3c_ts_dev->evbit); /* 能夠產(chǎn)生絕對(duì)位移事件 */ /* 2.2 能產(chǎn)生這類(lèi)事件里的哪些事件 */ set_bit(BTN_TOUCH, s3c_ts_dev->evbit); /* 能夠產(chǎn)生按鍵類(lèi)里面的觸摸屏事件 */ input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); /* X方向 0xFF是因?yàn)橛|摸屏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.注冊(cè) */ input_register_device(s3c_ts_dev); /* 4.硬件相關(guān)的操作 */ /* 4.1 使能時(shí)鐘CLKCON[15 (總開(kāi)關(guān),一般對(duì)不用的設(shè)備,時(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啟動(dòng)方式,通過(guò)讀來(lái)啟動(dòng) * bit[0 : 啟動(dòng)AD轉(zhuǎn)換,啟動(dòng)后會(huì)自動(dòng)清零 */ 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 * 使用定時(shí)器,用來(lái)解決連按或滑動(dòng) */ 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"); 測(cè)試方法主要是檢測(cè)上報(bào)事件是否正常,要想更好的測(cè)試,需要移植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ù)實(shí)際情況來(lái)定 使用: 先安裝s3c_ts.ko, lcd.ko // lcd.ko是之前編譯好的LCD驅(qū)動(dòng),如果后面編譯s3c_ts時(shí)改過(guò)配置,直接裝載之前編譯好的lcd.ko可能會(huì)出現(xiàn)段錯(cuò)誤,重新編譯一下lcd驅(qū)動(dòng)就可以了。 1. 修改 /etc/ts.conf第1行(去掉#號(hào)和第一個(gè)空格): # 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語(yǔ)言 C++、JAVA、數(shù)電模電、51單片機(jī)、PIC stm32 ARM Linux驅(qū)動(dòng) 嵌入式、安卓系統(tǒng) FPGA、DSP Cortex-M3學(xué)習(xí) 請(qǐng)咨詢(xún) 朱工,騰訊QQ3208919269 中國(guó)移動(dòng)15088133726 深圳南山、民治、龍崗、西鄉(xiāng)、長(zhǎng)沙、鄭州、南寧同步學(xué)習(xí)中! 理論與實(shí)踐相結(jié)合 一線工程師項(xiàng)目經(jīng)理教學(xué) 結(jié)合真實(shí)的產(chǎn)品案列 讓你感受前所未有的電子產(chǎn)品的開(kāi)發(fā)流程 2015給自己一個(gè)決心,只為自己!高薪就業(yè)不是夢(mèng),有想法你就來(lái) IT達(dá)人等著你!!! |