- 收藏
- 点赞
- 分享
- 举报
触摸屏控制方法,个人总结
看到一篇很不错的文章,特转来分享 原帖地址: 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;
}
}
}
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片![alt](url)
-
02019-12-26 18:22:10
-
02020-01-02 15:31:22
-
2009-03-17 08:47:02
-
122016-02-29 14:13:53
-
2020-04-10 21:57:49
-
2012-12-04 14:19:56
-
2019-10-18 15:11:26
-
2016-03-19 16:53:44
-
2009-03-13 08:31:13
-
2024-01-09 18:11:26
-
2016-03-25 02:21:12
-
2018-12-07 17:42:51
-
2021-05-26 18:24:17
-
2014-12-22 09:19:07
-
2023-11-13 14:46:33
-
2024-01-17 09:00:46
-
2012-12-24 14:17:53
-
2020-11-22 18:52:46
-
2020-10-01 16:31:00
-
5Hi3516CV610 如何使用SD卡升级固件
-
5cat /dev/logmpp 报错 <3>[ vi] [func]:vi_send_frame_node [line]:99 [info]:vi pic queue is full!
-
50如何获取vpss chn的图像修改后发送至vo
-
5FPGA通过Bt1120传YUV422数据过来,vi接收不到数据——3516dv500
-
50SS928 运行PQtools 拼接 推到设备里有一半画面会异常
-
53536AV100的sample_vdec输出到CVBS显示
-
10海思板子mpp怎么在vi阶段改变视频数据尺寸
-
10HI3559AV100 多摄像头同步模式
-
9海思ss928单路摄像头vio中加入opencv处理并显示
-
10EB-RV1126-BC-191板子运行自己编码的程序
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明