vacumm

vacumm

0个粉丝

4

问答

0

专栏

2

资料

vacumm  发布于  2013-11-21 21:51:50
采纳率 0%
4个问答
3129

触摸屏控制方法,个人总结

 

看到一篇很不错的文章,特转来分享 原帖地址: http://www.amobbs.com/thread-5128122-1-1.html 最近几天研究了下触摸屏,发现也并不像感觉中的那么神秘。

本人用的触摸屏方案是 4线电阻屏+xpt2046(这个和ADS7843完全一样)。

控制过程主要分一下几步:

1,读数——这里读出来的是触摸屏控制芯片的AD值,是屏的物理坐标 2,滤波——触摸屏类似按键,按下和放开时会有抖动 3,转化——把屏的物理坐标转化成逻辑坐标,这里的逻辑坐标在LCD的范围内对应LCD的像素点坐标。 4,定位——触摸屏的定位,这个其实应该放到最开始。

读数:

这里按照控制芯片的时序使用管脚模拟SPI的方式读出来的,用过STM32的SPI,也可以,不过习惯模拟,不用那么复杂的配置了。 (程序见后面部分)

滤波:

这里使用了2种方式的滤波,一种是像按键一样,检测到控制芯片INT引脚变低之后,延时20ms,然后如果在检测还是为低,则是真正的按下。 第二种是软件滤波,程序读取了10次触摸屏的物理坐标,然后冒泡排序,最后去掉最前面的和最后面的,只保留中间3个,再对中间3个取平均。 (程序见后面部分)

转化:

这个很简单,在任何一个介绍触摸屏的文章估计都能见到。 xp——x的物理坐标 xl—— x的逻辑坐标 LCDXSIZE ——LCD的x方向做大值 xpmin —— 在LCD(0,0)坐标处的x的物理坐标 xpmax LCD最大处x物理坐标 yp——y的物理坐标 yl—— y的逻辑坐标 LCDYSIZE ——LCD的y方向最大值 ypmin —— 在LCD(0,0)坐标处的y的物理坐标 ypmax LCD最大处y物理坐标

xl = (xp-xpmin)LCDXSIZE/(xpmax-xpmin) yl = (yp-ypmin)LCDYSIZE/(ypmax-ypmin)

定位:

这里定位的作用是求处上面的xpmin,xpmax,ypmin和ypmax,方法就是在屏幕上知道2点,求这两点所在直线上的一点(而且知道要求点的某一个坐标) 在屏上分别画出4个点,其实3个点足以,但是一般都用4个点,取得这四个点的物理坐标。假设分别为: --x1,y1-------------------x2,y2----
   --x3,y3-------------------x4,y4----
      |                        |

对应的物理坐标为 cx1,cy1 cx2,cy2, cx3,cy3 cx4,cy4

利用比例关系 x1/(cx1-xpmin) = x2/(cx2-xpmin) —————————————— 这里x1和x2不相等 可以求出xpmin,同样用比例关系 x2/(cx2-xpmin) = LCDXSIZE/(xpmax-xpmin)———————————— 这里最好x2>x1,更准些 可以求出xpmax

然后用同样的方法求出ypmin和ypmax _____分割线__ ———————————————————————————————————————————————————————————————— 用中断读控制芯片的INT引脚还是用定时器读?

用中断比较节省资源,但是我在做一个画图板的时候,发现滑动坐标没办法求出来,于是就去想定时器读。 用定时器读有个好处:延时操作可以在定时器里设置一个标志字,然后如果有按下就置位这个标志,下次再去真正读取。 定时器里可以给触摸屏设置多种不同的状态,这里按照Windows的情况设置了down,move,up还有none4种状态 这样用定时器解决了一个消抖和滑动坐标检测的问题,我选择定时器。

无图无真相,无码无真相:下面是真相 [attach]1236[/attach]

(原文件名:touch.jpg)

头文件::

ifndef __TOUCH_H__

define __TOUCH_H__

include "stm32f10x_lib.h"

enum { TOUCH_NONE=0, // TOUCH_DOWN, TOUCH_MOVE, TOUCH_UP, };

define TOUCH_CLK_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_13)

define TOUCH_CLK_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_13)

define TOUCH_DOUT_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_15)

define TOUCH_DOUT_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_15)

define TOUCH_READ_DIN() GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14)

define TOUCH_CS_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_12)

define TOUCH_CS_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_12)

define TOUCH_READ_INT() GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_7)

define TOUCH_READ_BUSY() GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_8)

define TOUCH_CHX 0x90 //差分方式读取

define TOUCH_CHY 0xD0

define TOUCH_GETTIMES 10

extern vu16 TouchX, TouchY; extern vu8 TouchPress,TouchState; extern u8 TouchCalibrated;

void Touch_Init(void); u16 Touch_GetX(void); u16 Touch_GetY(void); void Touch_Calibrate(void); void Touch_GetState(void);

endif

C文件::

include "Touch.h"

include "systick.h"

include "Graphics.h"

vu16 TouchX, TouchY; vu8 TouchPress=0, TouchState=TOUCH_NONE; //state有4种状态,0无按键,1按下,2抬起,3move u8 TouchCalibrated = 0;

u16 TouchXMin, TouchXMax, TouchYMin, TouchYMax; /**** 初始化触摸屏需要的端口 芯片--TSC2046 ****/ void Touch_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; //EXTI_InitTypeDef EXTI_InitStructure; //NVIC_InitTypeDef NVIC_InitStructure; //SPI_InitTypeDef SPI_InitStructure;

/* Enable GPIOB, GPIOC and AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO, ENABLE);  //RCC_APB2Periph_AFIO
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

//SPI 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

//SPI_MISO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* CS pins configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/*INI Pin*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOG, &GPIO_InitStructure);

/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟空闲为低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //上升沿所存 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; SPI_Init(SPI2, &SPI_InitStructure); SPI_Cmd(SPI2,ENABLE);
/

if 0

EXTI_ClearITPendingBit(EXTI_Line7);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource7);  

/* Configure Button EXTI line */
EXTI_InitStructure.EXTI_Line = EXTI_Line7;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);

endif

}

/=====================================================================/ u16 Touch_AdjY(u16 adx) //240 { u16 sx=0; int r = adx - TouchYMin; r *= 240; sx=r / (TouchYMax - TouchYMin); if (sx>=240) return 0xFFFF; return sx; }

u16 Touch_AdjX(u16 ady) //320 { u16 sy=0; int r = ady - TouchXMin; r *= 320; sy=r/(TouchXMax - TouchXMin); if (sy>=320) return 0xFFFF; return sy; }

u16 Touch_Read(u8 cmd) { u8 i; u16 pos=0;

TOUCH_CLK_LOW();
TOUCH_CS_LOW();
for(i=0; i<8; i++)
{
    if(cmd&0x80) TOUCH_DOUT_HIGH();
    else TOUCH_DOUT_LOW();
    cmd <<= 1;
    TOUCH_CLK_HIGH();
    TOUCH_CLK_LOW();
}
Delay(50);
for(i=0; i<12 ;i++)
{
   pos <<= 1;
   TOUCH_CLK_HIGH();
   if(TOUCH_READ_DIN() == Bit_SET)
    pos |= 0x01;
   TOUCH_CLK_LOW(); 
}
TOUCH_CS_HIGH();

return pos;

}

u16 Touch_GetX(void) { u8 count=0, i,j; u16 pos[TOUCH_GETTIMES]={0}; u16 res=0xffff, temp;

while((count<TOUCH_GETTIMES)&&(TOUCH_READ_INT() == Bit_RESET)) 
{ 
    count++; 
    //TOUCH_CS_LOW();                                           //选中器件
    //SPI_I2S_SendData(SPI2,TOUCH_CHX);                           //
    //while(TOUCH_READ_BUSY() == Bit_SET);                      //等待busy信号 
    //pos[count] = (u8 )SPI_I2S_ReceiveData(SPI2); 
    //TOUCH_CS_HIGH(); 
    pos[count] = Touch_Read(TOUCH_CHX);
} 
if(count < TOUCH_GETTIMES)                                                  //干扰,丢弃
    return res;
for(i=0; i<TOUCH_GETTIMES-1; i++)
{
    for(j=0; j<TOUCH_GETTIMES-i-1; j++)  
    {
        if(pos[j]>pos[j+1])
        {
            temp = pos[j];
            pos[j] = pos[j+1];
            pos[j+1] = temp;
        }
    }
}

res = (pos[TOUCH_GETTIMES/2-1]+pos[TOUCH_GETTIMES/2]+pos[TOUCH_GETTIMES/2+1])/3;
if(TouchCalibrated==1) //已经校准过了,否则这里只输出物理值
    res = Touch_AdjX(res);

return res;    

}

u16 Touch_GetY(void) { u8 count=0, i,j; u16 pos[TOUCH_GETTIMES]={0}; u16 res = 0xffff, temp;

while((count<TOUCH_GETTIMES)&&(TOUCH_READ_INT() == Bit_RESET)) 
{ 
    count++; 
   // TOUCH_CS_LOW();                                           //选中器件
    //SPI_I2S_SendData(SPI2,TOUCH_CHY);                           //
    //while(TOUCH_READ_BUSY() == Bit_SET);                      //等待busy信号 
    //pos[count] = (u8 )SPI_I2S_ReceiveData(SPI2);  
    //TOUCH_CS_HIGH();  
    pos[count] = Touch_Read(TOUCH_CHY);
} 
if(count < TOUCH_GETTIMES)                                                  //干扰,丢弃
    return 0xffff;
for(i=0; i<TOUCH_GETTIMES-1; i++)
{
    for(j=0; j<TOUCH_GETTIMES-i-1; j++)  
    {
        if(pos[j]>pos[j+1])
        {
            temp = pos[j];
            pos[j] = pos[j+1];
            pos[j+1] = temp;
        }
    }
}

res = (pos[TOUCH_GETTIMES/2-1]+pos[TOUCH_GETTIMES/2]+pos[TOUCH_GETTIMES/2+1])/3;
if(TouchCalibrated==1) //已经校准过了,否则这里只输出物理值
    res = Touch_AdjY(res);

return res; 

}

void Touch_Calibrate(void) { u16 x[4] = {30, 290, 30, 290}; u16 y[4] = {20, 20, 220, 220}; u16 cx[4],cy[4], tempx[2], tempy[2]; u8 i; u16 color;

//画出需要的点,然后点击
TouchXMin = 0; TouchYMin = 0;

color = GetColor(); SetColor(BLUE); ClearDevice();

while(TRUE) { for(i=0; i<4; i++) //画出5个点,点击后记录标志值 { SetColor(RED); FillCircle(x,y,3); while((TouchPress==0)||(TouchState!=TOUCH_DOWN)); TouchPress = 0; cx= TouchX; cy= TouchY; SetColor(BLUE); ClearDevice(); }

tempx[0] = (290*cx[0]-30*cx[1])/260;
tempx[1] = (290*cx[2]-30*cx[3])/260;
tempy[0] = (220*cy[0]-20*cy[2])/200;
tempy[1] = (220*cy[1]-20*cy[3])/200;

if( (tempx[0]>tempx[1]-20) && ((tempx[0]<tempx[1]+20)))
{
    TouchXMin = (tempx[0]+tempx[1])/2;
}
if( (tempy[0]>tempy[1]-20) && ((tempy[0]<tempy[1]+20)))
{
    TouchYMin = (tempy[0]+tempy[1])/2;
}
if(TouchXMin != 0 && TouchYMin !=0)
{
    TouchXMax = (cx[1]-TouchXMin)*320/290 + TouchXMin;
    TouchYMax = (cy[2]-TouchYMin)*240/220 + TouchYMin;
    break;
}

} SetColor(color); TouchCalibrated = 1; }

void Touch_GetState(void) //定时器里调用 { u16 x, y; static BOOL islow = FALSE;

if(TOUCH_READ_INT() != Bit_RESET)          //没有按下的情况下,如果之前是按下的,则
{                                           //是抬起
    if((TouchState == TOUCH_DOWN)||(TouchState == TOUCH_MOVE))
    {
        TouchState = TOUCH_UP;
        TouchPress = 1;
    }
    else
        TouchState = TOUCH_NONE;
    return;
}
else
{
    if(islow == FALSE)
        islow = TRUE;
    else
    {
        x = Touch_GetX();         
        y = Touch_GetY();
        if((x != 0xffff) && (x != 0xffff))      //有真的按下
        {
          switch(TouchState)
          {
            case TOUCH_NONE:            //原来没有按下,现在一定是按下了
                TouchState = TOUCH_DOWN;
                break;
            case TOUCH_DOWN:            //原来按下了,现在一定是move了
                TouchState = TOUCH_MOVE;
                break;
            case TOUCH_MOVE:            //之前是move,现在还是move

                break;
            case TOUCH_UP:              //之前是up,这种情况应该不会出现
            default:
                TouchState = TOUCH_NONE;
                break;
          }
          TouchX = x;
          TouchY = y;
          TouchPress = 1;
        }
        islow = FALSE;
    }
}

}

我来回答
回答0个
时间排序
认可量排序
易百纳技术社区暂无数据
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
相关问答
无更多相似问答 去提问
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区