触摸屏学习

目录

  • ADC触摸屏

    • 硬件原理
    • 等效电路
    • 测量逻辑
    • 程序设计(一)获得ADC
      • 寄存器初始化
      • 中断初始化
      • ADC模式(中断、测量)
      • 中断函数
    • 程序设计(二)获得坐标
      • 生产者与消费者
      • ADC获取
    • 程序优化
    • 个人修改意见
    • TODO


title: ADC触摸屏

tags: ARM

date: 2018-11-02 18:35:45

---

ADC触摸屏

硬件原理

s3c2440有8通道的ADC,一次同时只能查询一个通道。分为A0~A7。这里的P(positive)表示的是正的意思

ADC通道
A4 TSYM -Y
A5 TSYP +Y
A6 TSXM -X
A7 TSXP +X

触摸屏采样有3种方式:

  • 自动反转XY轴相关开关采样
  • 手动切换开关采样
  • 等待中断模式,这个是平时没按下的状态

电阻屏的触摸原理,其实就是在一个均匀的电阻上采样后得到电压,然后基于vcc算出相对偏移.假设电阻总长为L,采样电压为V1,那么长度偏移则是V/DVDD*L.

基于此在X方向和Y方向均有均匀电阻.所以触摸屏实际是两片透明且均匀的电阻,不按下的时候中间并不导通.转换选择导通X方向与Y方向依次测的X坐标与Y坐标.也就是先连接Xm--Xp,侧的Yp的采样,就能获得X的偏移.

板载电路

这里X轴和Y轴接反了,尅使用Tslib库旋转倒置等

等效电路

关闭模式:断开上拉电阻与4线电路,防止漏电流

空闲等待中断:这个状态是平时没有按下触摸屏,等待按下触发一个按下的中断,当左右两边电阻触发的时候,导通了XPYMGND,这将使Y_ADC=0,--↓__产生一个下降沿等待中断模式设置值为 ADCTSC=0xd3; // XP_PU, XP_Dis, XM_Dis,YP_Dis,YM_En同样的,当按下后,还是同样的等效电路,当松开的时候,会有一个上升延中断.配置ADCTSCBIT8即可.

X轴采样:这里连通XP-XM,采样X_ADC

Y轴采样:这里连通YP-YM,采样Y_ADC

测量逻辑

触摸屏实际有两层,按下的时候,导通了上下两个平面,通过等效电路,可以看出通过切换开关,能够得到两种阻值。

  1. 按下触摸屏触发中断,打开ADC采样,等待ADC采样完成中断
  2. 松开触摸屏触发中断,退出流程
  3. ADC中断中获得XY的坐标,然后依然需要采样输出,这里可以采用打开定时器,定时采样
  4. 定时器中断到后,判断是否抬起,如果依然按下,触发ADC采样,这里关闭定时器自身的处理函数(关闭定时器中断).如果抬起,触摸屏转换到等待状态,关闭自身中断.
  5. 流程图在这里

程序设计(一)获得ADC

寄存器初始化

这里的DELAY 可以用作稳定ADC输出,也就是按下后多长时间开始采样

/*
1. 设置允许分配,分配系数为49+1,时钟为100M/50=2
2.  选择A0通道,因为后面选择自动转换,可以不考虑通道
*/
ADCCON = (1<<14) | (49<<6) | (0<<3);

/*  按下触摸屏, 延时一会再发出TC中断
 *  延时时间 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms
 */
ADCDLY = 60000;

中断初始化

//清除挂起标志
SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);
//取消次级屏蔽
INTSUBMSK &= ~((1<<ADC_INT_BIT) | (1<<TC_INT_BIT));
//注册中断函数,INTMSK &= ~(1<<irq); 取消源的mask
register_irq(31, AdcTsIntHandle);

void register_irq(int irq, irq_func fp)
{
    irq_array[irq] = fp;

    INTMSK &= ~(1<<irq);
}

ADC模式(中断、测量)

ADC在工作中存在3个模式的切换,空闲的时候进入等待按下中断的模式,然后进入自动测量的模式,在测量完成后需要进入等待松开的中断模式.此时可以设置定时器等待触发下一次的自动测量

// 空闲下等待触发落下中断
void enter_wait_pen_down_mode(void)
{
    ADCTSC = WAIT_PEN_DOWN | PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE |          XM_DISABLE | WAIT_INT_MODE;
}
//等待抬起的中断
void enter_wait_pen_up_mode(void)
{
    ADCTSC = WAIT_PEN_UP | PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE |            XM_DISABLE | WAIT_INT_MODE;
}
//自动测量模式
void enter_auto_measure_mode(void)
{
    ADCTSC = AUTO_PST | NO_OPR_MODE;
}

中断函数

  1. 定时器中断函数
  2. adc中断函数,包括adc采样完成中断和触摸屏触发中断

备注:可以发现,松开状态下进入中断,都进入空闲等待按下中断模式

触摸屏中断

if 松开中断
    关闭一切,进入等待按下模式
else 按下中断
    进入自动测量模式
    打开adc

定时器中断

if 松开
    关闭定时器
    进入等待按下模式
else 按下
    进入自动测量模式
    打开adc

ADC中断

if 松开
    关闭定时器
    进入等待按下模式
else 按下
    打印adc值
    *进入等待中断模式
    打开定时器

//这里可以优化做平均值
if 松开
    关闭定时器
    进入等待按下模式
    上报数据
else 按下
    if 测量计数到达16次
        返回平均值,开启定时器
    else
        直接进入自动测量模式
    

优化版本

进入adc中断
进入触摸屏中断
进入定时器中断后 都先关闭定时器

进入adc中断后
if按下
    满16次采样后打开定时器,进入等待松开中断
    未满16次继续打开adc采样
else 松开
    进入等待按下中断
    上报0

进入触摸屏中断
if 按下
    打开adc开始采样
else 松开
    进入等待按下中断
    上报0

进入定时器中断且当前定时器状态为open
if 按下
    打开adc采样
else 松开
    进入等待按下中断
    上报0

程序设计(二)获得坐标

同理,Y轴的坐标也按照相同的方式计算.程序设计中依次画出5个十字架,用户点击后计算K与b偏差

生产者与消费者

生产者:这里ADC完成测量后上报ADC采样,可以理解为生产者.在ADC采样完成16次并且依然按下的情况下上报实际adc,其他情况上报0.这里设置一个标志,只有等消费者取出数据之后,再上传数据.这里都是在中断中上报数据

void report_ts_xy(int x, int y, int pressure)
{
    //printf("x = %08d, y = %08d\n\r", x, y);

    if (g_ts_data_valid == 0)
    {
        g_ts_x = x;
        g_ts_y = y;
        g_ts_pressure = pressure;
        g_ts_data_valid = 1;
    }
}

消费者:中断中生产数据,循环中获取数据,取得数据后清除标志允许生产者上传数据.

void ts_read_raw(int *px, int *py, int *ppressure)
{
    while (g_ts_data_valid == 0);
    *px = g_ts_x;
    *py = g_ts_y;
    *ppressure = g_ts_pressure;
    g_ts_data_valid = 0;
}

状态标志: g_ts_data_valid是标志.0表示消费者已经取走数据,无新数据产生

ADC获取

  1. 等待点击,直到按键按下
  2. 按下后检测弹开,后上报数据坐标
/* 等待点击 */

do {
    ts_read_raw(&x, &y, &pressure);
} while (pressure == 0);

/* 等待弹开 */
do {
    *px = x;
    *py = y;
    ts_read_raw(&x, &y, &pressure);
    printf("get raw data: x = %08d, y = %08d\n\r", x, y);
} while (pressure);
  1. 判断XY是否颠倒.取X轴上的两个坐标A-----B,那么BX-AX应大于BY-AY,BY-AY约等于0
int is_ts_xy_swap(int a_ts_x, int a_ts_y, int b_ts_x, int b_ts_y)
{
    int dx = b_ts_x - a_ts_x;
    int dy = b_ts_y - a_ts_y;

    if (dx < 0)
        dx = 0 - dx;
    if (dy < 0)
        dy = 0 - dy;

    if(dx > dy)
        return 0; /* xy没有反转 */
    else
        return 1; /* xy反了 */
}
  1. 如果颠倒的话,需要将每个点的X与Y互换
if (g_ts_xy_swap)
{
    /* 对调所有点的XY坐标 */
    swap_xy(&a_ts_x, &a_ts_y);
    swap_xy(&b_ts_x, &b_ts_y);
    swap_xy(&c_ts_x, &c_ts_y);
    swap_xy(&d_ts_x, &d_ts_y);
    swap_xy(&e_ts_x, &e_ts_y);
}
  1. 坐标计算
/*
----------------------------
|                          |
|  +(A)              (B)+  |
|                          |
|                          |
|                          |
|            +(E)          |
|                          |
|                          |
|                          |
|  +(D)              (C)+  |
|                          |
----------------------------

*/

/* 确定公式的参数并保存 */
ts_s1 = b_ts_x - a_ts_x;
ts_s2 = c_ts_x - d_ts_x;
lcd_s = xres-50 - 50;

ts_d1 = d_ts_y - a_ts_y;
ts_d2 = c_ts_y - b_ts_y;
lcd_d = yres-50-50;

g_kx = ((double)(2*lcd_s)) / (ts_s1 + ts_s2);
g_ky = ((double)(2*lcd_d)) / (ts_d1 + ts_d2);

g_ts_xc = e_ts_x;
g_ts_yc = e_ts_y;

g_lcd_xc = xres/2;
g_lcd_yc = yres/2;

printf("A lcd_x = %08d, lcd_y = %08d\n\r", get_lcd_x_frm_ts_x(a_ts_x), get_lcd_y_frm_ts_y(a_ts_y));

int get_lcd_x_frm_ts_x(int ts_x)
{
    return g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
}

int get_lcd_y_frm_ts_y(int ts_y)
{
    return g_ky * (ts_y - g_ts_yc) + g_lcd_yc;
}

程序优化

视频教学修改要点

  1. 启动ADC时不应该进入等待中断模式,它会影响数据,视频教程中会有adc中断和定时器中断碰撞的问题,也就是adc采样未完成,可能先发生定时器中断的问题,然后定时器中断去触发等待中断的模式
  2. 只有在"等待中断模式"下才可以使用ADCDAT0‘BIT 15来判断触摸笔状态
  3. 校准非常重要,所以在程序种多次测量求平均值(不仅仅是在adc中断中求平均值)

寄存器ADCDAT0只有在等待中断的模式中才能用来判断是按下还是松开状态,所以定时器中断中不能用该寄存器.所以当定时器中断发生在ADC采样中的时候,不应该打断adc采样.韦东山的优化是先判断是否是自动采样模式,如果是在采样则退出.

void touchscreen_timer_irq(void)
{
    //定时器开关
    if (get_status_of_ts_timer() == 0)
        return;
/*------------------------------------------------------------
定时器开关只会被ADC采样16次完成后打开,其他状态下均会关闭定时器,
包括进入本函数这里的按下状态后进入自动测量模式
 ***************************************************************/
    if (is_in_auto_mode())
        return;

    /* 只有在"等待中断模式"下才可以使用ADCDAT0‘BIT 15来判断触摸笔状态 */

    if (ADCDAT0 & (1<<15)) /* 如果松开 */
    {
        printf("timer set pen down\n\r");
        ts_timer_disable();
        enter_wait_pen_down_mode();
        report_ts_xy(0, 0, 0);
        return;
    }
    else  /* 按下状态 */
    {
        /* 进入"自动测量"模式 */
        enter_auto_measure_mode();

        /* 启动ADC */
        ADCCON |= (1<<0);
    }
}

个人修改意见

我觉得更应该更改为如果开启了adc的采样,应该是去关闭定时器的标志.防止碰撞.定时器中断必须在采样16次完成之后才会发生.然后进入定时器中断处理的时候就能确保不会与adc中断冲突,也就是一定是在等待中断模式,上述的is_in_auto_mode也是可以去除的.

if (is_in_auto_mode())
    return;

所以我的优化方案是

进入adc中断
进入触摸屏中断
进入定时器中断后 都先关闭定时器

进入adc中断后
if按下
    满16次采样后打开定时器,进入等待松开中断
    未满16次继续打开adc采样
else 松开
    进入等待按下中断
    上报0

进入触摸屏中断
if 按下
    打开adc开始采样
else 松开
    进入等待按下中断
    上报0

进入定时器中断且当前定时器状态为open
if 按下
    打开adc采样
else 松开
    进入等待按下中断
    上报0
    

总结

  1. 处理好各种中断下的模式
  2. 判断断开还是按下应该是在等待中断模式下的
  3. 校准值应该求平均
  4. 采样画点值也该求平均

TODO

参考tslib 中更牛逼的矫正算法

原文地址:https://www.cnblogs.com/zongzi10010/p/9902571.html

时间: 2024-08-02 23:55:06

触摸屏学习的相关文章

基于STM32的触摸屏学习笔记

本文共有三个内容:一.电阻触摸屏的原理:二.XPT2046的控制字与数字接口:三.程序源码讲解(参考正点原子的代码) 一.电阻触摸屏的原理,上图: 图上的文字介绍了触摸的原理,下面给总结一下触摸的原理: 触摸屏工作主要是两个电阻屏(上下两层)在工作,如上图,当某一层电级加上电压时,会在该网络上形成电压梯度.如果有外力使得上下两层在某一点接触,则在未加电压的那一层可以测得接触点的电压,从而得出接触点的坐标(X或Y).举个例子:当我们在上层的电极间(Y+和Y-)加上电压,则会在上层形成电压梯度(这里

AM335x(TQ335x)学习笔记——触摸屏驱动编写

前面几篇文章已经通过配置DTS的方式完成了多个驱动的移植,接下来我们解决TQ335x的触摸驱动问题.由于种种原因,TQ335x的触摸屏驱动是以模块方式提供的,且Linux官方内核中也没有带该触摸屏的驱动源码,单纯的配置DTS是无法完成TQ335x的触摸驱动移植工作的,因此,本文参考内核中原有的pixcir_i2c_ts驱动编写TQ335x的触摸屏(TN92)驱动. 在之前移植TQ210时,我已经编写过TQ210的触摸屏驱动,我的TQ335x还是使用的TQ210的屏,因此,难度不是很大.这里需要说

msg2133触摸屏(TP源代码学习)

强调:下面的设备指触摸屏 ABS:绝对值 1.     input子系统简介 Linux输入设备总类繁杂,常见的包括有按键.键盘.触摸屏.鼠标.摇杆等等,他们本身就是字符设备,而linux内核将这些设备的共同性抽象出来,简化驱动开发建立了一个input子系统.子系统共分为三层,如图1所示. 图1 驱动层和硬件相关,直接捕捉和获取硬件设备的数据信息等(包括触摸屏被按下.按下位置.鼠标移动.键盘按下等等),然后将数据信息报告到核心层.核心层负责连接驱动层和事件处理层,设备驱动(device driv

Linux嵌入式驱动学习之路(十九)触摸屏驱动

触摸屏使用流程: 1. 按下产生中断. 2.在中断处理程序中启动AD转换XY坐标. 3.AD转换结束并产生AD中断. 4. 在AD的中断处理函数中上报信息,启动定时器. 5. 定时器时间到后进入中断,处理长按滑动.跳转到第二步 6. 松开. sd

I.MX6Q(TQIMX6Q/TQE9)学习笔记——新版BSP之触摸屏驱动移植

之所以说是驱动移植是因为之前已经在TQ210.AM335x两个平台上移植过了,因此,仅需要少量修改就可以将驱动移植到imx6q.下面开始触摸驱动移植. DTS编写 参考其它DTS的i2c设备写法,我们可以添加如下内容: &i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1_2>; status = "okay&q

cortex_m3_stm32嵌入式学习笔记(二十二):触摸屏实验(触摸屏驱动)

目前最常用的触摸屏有两种:电阻式触摸屏与电容式触摸屏. 电阻式触摸屏 在 Iphone 面世之前,几乎清一色的都是使用电阻式触摸屏, 电阻式触摸屏利用压力感应进行触点检测控制,需要直接应力接触, 通过检测电阻来定位触摸位置. 电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,这是一种多层的复合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电阻)导电层,上面再盖有一层外表面硬化处理.光滑防擦的塑料层.它的内表面也涂有一层涂层.在他们之间有许多细小的(小于 1

【Android开发学习笔记】【第十课】运动事件 之——触摸屏

概念 触摸屏 (TouchScreen) 和 滚动球(TrackBall)是Android 中除了键盘之外的主要输入设备. 而这两个事件都可以用运动事件(MotionEvent)用于接收他们的信息 直接看代码吧 package com.example.motion; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.MotionEvent; import a

【转】朱兆祺带你一步一步学习嵌入式(连载)

原文网址:http://bbs.elecfans.com/jishu_357014_2_1.html#comment_top  从最初涉及嵌入式Linux开始到现在,深深的知道嵌入式的每一步学习都是举步维艰.从去年11月份开始,我就着手整理各种学习资料,希望推动嵌入式学习的前进贡献自己微不足道的一份力量.从去年到现在,将C语言的学习经验整理成<攻破C语言笔试与机试陷阱及难点>(现在仍在更新),这份资料已经在电子发烧友论坛的单片机论坛连载(http://bbs.elecfans.com/jish

嵌入式技术学习路线

嵌入式技术是各种电子产品的核心技术,也是工业4.0.远程医疗.3D打印等新兴产业的核心技术,具有广阔的发展前景.很多计算机.电子信息类专业的学生都想把嵌入式开发作为自己的职业目标,但是因为嵌入式涉及的知识太多,太杂,太广,很多嵌入式初学者陷入嵌入式知识的海洋中,东学一点,西学一点,找不到学习的方向. 作为过来人,给大家谈谈正确的嵌入式学习路线,供各位嵌入式初学者参考,希望对大家有所帮助. 嵌入式工程师需要掌握的内容非常广泛,主要包括嵌入式软件.嵌入式硬件.以及相关行业.产品的专业知识.作为嵌入式