觸摸屏歸納為輸入子系統

發(fā)布時(shí)間:2016-4-5 17:37    發(fā)布者:信盈達電子

觸摸屏歸納為輸入子系統,這里主要是針對電阻屏,其使用過(guò)程如下
當用觸摸筆按下時(shí),產(chǎn)生中斷。
在中斷處理函數處理函數中啟動(dòng)ADC轉換x,y坐標。
ADC結束,產(chǎn)生ADC中斷
在A(yíng)DC中斷處理函數里上報(input_event)啟動(dòng)定時(shí)器
再次啟動(dòng)定時(shí)器(可以處理滑動(dòng)、長(cháng)按)
松開(kāi)按鍵

其驅動(dòng)程序的寫(xiě)法和之前寫(xiě)輸入子系統的寫(xiě)法基本上一致。
寫(xiě)出入口函數,出口函數并加以修飾,加入相關(guān)頭文件,然后開(kāi)始完善各函數,在入口函數中分配input_dev結構體,設置(能產(chǎn)生哪類(lèi)事件,能產(chǎn)生這類(lèi)事件中的哪些事件),注冊設備,硬件相關(guān)的操作等。出口函數中主要對之前注冊、分配的一些資源進(jìn)行釋放。
還應根據2440數據手冊ADC轉換和觸摸屏那一章,對相關(guān)寄存器根據實(shí)際需要進(jìn)行設置。

點(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手冊P442 */
}
void enter_wait_pen_up_mode(void)       /* 進(jìn)入等待觸摸筆松開(kāi)模式 */
{
    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);       /* 啟動(dòng)ADC */
}
static int s3c_filter_ts(int x[, int y[)      /* 軟件過(guò)濾 */
{
#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)松開(kāi) */
        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坐標 */
        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完成時(shí),發(fā)現觸摸筆已松開(kāi),則丟棄此次結果
     */
    adcdat0 = s3c_ts_regs->adcdat0;
    adcdat1 = s3c_ts_regs->adcdat1;
    if (s3c_ts->adcdat0 & (1<<15))     /* bit[15判斷是否松開(kāi) */
    {
        /* 如果已經(jīng)松開(kāi)則丟棄結果 */
        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
    {
        /* 如果還是按下,則打印結果并進(jìn)入等待松開(kāi)模式 */
        //printk("adc_irq cnt = %d,x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);
        /* 優(yōu)化措施3:
         * 多次測量取平均值
         */
        x[cnt = adcdat0 & 0x3ff;    /* 將測量結果存入靜態(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計數清0 */
            enter_wait_pen_up_mode();       /* 測量完后要進(jìn)入等待松開(kāi)模式,這樣才能連續操作 */
            /* 啟動(dòng)定時(shí)器處理長(cháng)按/滑動(dòng)的情況 */
            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.分配一個(gè)input_dev結構體 */
    s3c_ts_dev = input_allocate_device();
    /* 2.設置 */
    /* 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)生絕對位移事件 */
    /* 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是因為觸摸屏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 使能時(shí)鐘CLKCON[15 (總開(kāi)關(guān),一般對不用的設備,時(shí)鐘一般是關(guān)閉的) */
    clk = clk_get(NULL, "adc");
    clk_enable(clk);
    /* 4.2 設置S3c2440的ADC/TS寄存器 */
    s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
    /* ADCCON
     * bit[14   : 1 預分頻使能
     * bit[13:6 :   預分頻系數
     *               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轉換,啟動(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
     * 設置ADCDLY為最大值,使得電壓穩定后再發(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");




測試方法主要是檢測上報事件是否正常,要想更好的測試,需要移植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可根據實(shí)際情況來(lái)定


使用:

先安裝s3c_ts.ko, lcd.ko     // lcd.ko是之前編譯好的LCD驅動(dòng),如果后面編譯s3c_ts時(shí)改過(guò)配置,直接裝載之前編譯好的lcd.ko可能會(huì )出現段錯誤,重新編譯一下lcd驅動(dòng)就可以了。

1.
修改 /etc/ts.conf第1行(去掉#號和第一個(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、數電模電、51單片機、PIC stm32 ARM Linux驅動(dòng) 嵌入式、安卓系統 FPGA、DSP Cortex-M3學(xué)習

請咨詢(xún)  朱工,騰訊QQ3208919269  中國移動(dòng)15088133726  深圳南山、民治、龍崗、西鄉、長(cháng)沙、鄭州、南寧同步學(xué)習中! 

理論與實(shí)踐相結合 一線(xiàn)工程師項目經(jīng)理教學(xué) 結合真實(shí)的產(chǎn)品案列 讓你感受前所未有的電子產(chǎn)品的開(kāi)發(fā)流程

2015給自己一個(gè)決心,只為自己!高薪就業(yè)不是夢(mèng),有想法你就來(lái) IT達人等著(zhù)你。!


本文地址:http://selenalain.com/thread-162607-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页