最近几天研究了下触摸屏,发现也并不像感觉中的那么神秘。

本人用的触摸屏方案是 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种状态

这样用定时器解决了一个消抖和滑动坐标检测的问题,我选择定时器。

无图无真相,无码无真相:下面是真相

(原文件名: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

{

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

{

for(j=0; 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

{

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

{

for(j=0; 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]

{

TouchXMin = (tempx[0]+tempx[1])/2;

}

if( (tempy[0]>tempy[1]-20) && ((tempy[0]

{

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;

}

}

}

wince7 屏幕控制_触摸屏控制方法,个人总结(欢迎拍砖,但不要打脸)相关推荐

  1. wince7 屏幕控制_技术干货:WinCE 7.0下的触摸屏驱动

    在嵌入式系统中较为常用的是四线电阻式触摸屏,通过检测x轴和y轴的电压,来确定触点的位置.一般触摸屏系统结构为:触摸屏->触摸屏控制器->处理器. wince7下触摸屏的驱动分为PDD层(位 ...

  2. wince7 屏幕控制_WinCE中触摸屏驱动开发详解

    本文向您介绍WinCE中采用分层驱动程序结构实现的触摸屏驱动,包括对触摸屏驱动模型的讲解.触摸屏驱动程序的实现及接口实现等知识. 1.触摸屏驱动程序的模型 1.1分层触摸屏驱动程序结构 本触摸屏驱动采 ...

  3. wince7 屏幕控制_WinCE下如何调用触摸屏校准程序

    wince的cordll提供了屏幕校准的函数,使用方法与我的上一篇文章中说的钩子函数类似,强制加载dll,获取地址,然后用函数指针调用.这里飞狐给出源代码. 首先在头文件里加入函数指针定义:typed ...

  4. python手机屏幕控制_用Python控制墨水屏

    按照基础教程墨水屏用了起来,但是,教程是用C写的,以后是想用python做开发的,这之间可咋切换? 万能的github上已经有人这么做了 https://github.com/GregDMeyer/I ...

  5. 开发板——屏幕控制(LCD和触摸屏)

    屏幕控制(LCD和触摸屏) LCD显示 显示bmp格式图片 显示jpeg格式图片 触摸屏的使用 LCD显示 打开LCD屏幕 open需要包含的头文件 #include <sys/types.h& ...

  6. 伺服扭矩模式怎么控制_气液增压缸是怎么增压的?气液增压缸好用吗?气液增压缸的原理及其伺服控制...

    气液增压缸是怎么增压的?气液增压缸好用吗?气液增压缸的原理及其伺服控制 https://www.zhihu.com/video/1175508481024602112 气液增压缸控制的 5 种方法玖容 ...

  7. UnityStandardAsset工程、源码分析_4_赛车游戏[玩家控制]_摄像机控制

    上一章地址:UnityStandardAsset工程.源码分析_3_赛车游戏[玩家控制]_特效.声效 经过前几章的分析,我们已经大致地了解了车辆控制相关的脚本.现在还有最后一个与玩家体验息息相关的部分 ...

  8. vb.net程序可以在触摸屏上运行么_触摸屏amp;触控一体机常见故障解决方法

    ■一体机电脑触摸屏使用时间一长,容易出现这样或那样的故障,以下触摸屏一体机常见故障及解决方法,供参考. 01 触摸屏不准 一台五线电阻触摸屏,用手指触摸显示器屏幕的部位不能正常地完成对应的操作. 故障 ...

  9. 中达优控触摸屏编程视频教程_触摸屏组态编程软件|中达优控触摸屏编程软件(YKBuilder)1.0 官方版_ - 极光下载站...

    YKBuilder是一个中达优控触摸屏编程软件!触摸屏组态编程软件在电脑的开始菜单,打开运行对话框,输入"dcslic"->确定启动"Licenses 管理工具. ...

最新文章

  1. 【SICP练习】66 练习2.37
  2. Boost:在向量中打印值
  3. 【离散数学中的数据结构与算法】七 排列与组合三
  4. 14.5.5.1 An InnoDB Deadlock Example 一个InnoDB 死锁实例
  5. Sentinel热点Key降级下_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0043
  6. nginx多入口配置隐藏.php,Nginx配置tp5支持pathinfo以及隐藏入口文件
  7. [Web Chart系列之五] 5. 实战draw2d之figure tooltip 实现
  8. ✨Synchronized底层实现---偏向锁
  9. 程序员面试金典——17.6最小调整有序
  10. 怎样开图纸便宜_一步一步教你如何看懂工程图纸,值得收藏!
  11. 解决办法:undefined reference to symbol '_ZTVN10__cxxabiv117__class_type_infoE@@CXXABI_1.3
  12. idea注册账号_【Meta分析】Meta分析该不该注册?如何注册?什么时候注册?
  13. GEOS库一些自己的见解和注意点
  14. 配置ntpd提供网络授时服务
  15. vb标准(一):用户界面的设计
  16. 百度地图(HTML5新特性)-全面详解(学习总结---从入门到深化)
  17. 计算机批量制作邀请函步骤,如何利用Word批量制作邀请函
  18. [Pyecharts]数据可视化 大屏展示
  19. 【threeJS】纹理贴图
  20. opencv 单个圆形孔和针检测

热门文章

  1. jinjia2模板,循环中的全局变量使用,避坑
  2. 基于c#开发海康工业相机
  3. springboot +thymeleaf 实现本地图片显示,和数据库查询显示
  4. 图片转excel表格方法介绍,办工常备工具
  5. 解决google地图无法使用网络定位的问题
  6. ros常遇到的Couldn‘t find executable named ---错误
  7. 平面设计中创意版式的几个设计技巧
  8. Linux系统的安装与卸载
  9. Fuzz工具使用详解
  10. Java 并发编程之任务取消(五)