1. 触摸屏简单的讲,其实就是在LCD屏上加了一层触摸膜,如果是电阻屏,
感知的是电压的不同,如果是电容屏,感知的是电流的不同。
2. 然后通过一个AD转换芯片通知ARM芯片,LCD有分辨率,以320X240的分辨率和电阻屏为例,
对应这么多个点,触摸到哪个点,返回的电压也是不同的,但是由于接触的物体一般接触点较大,
3. 触摸屏使用的时候一般都是做个框,在框内的坐标所有点都认为触发的是同一个功能。
触摸屏一般是用中断,注意按下和抬起分别会进入一次中断,也就是按下一次进入两次中断,
下面看程序。
/******************************
*文件名:touch.c *
*功能: 主显示界面 *
*创建者: 潘星宇 *
*最后修改:2013.03.21 *
*备注: *
* *
*******************************/
#include "touch.h"
volatile int xdata, ydata; //转换前的X,Y坐标值
int xLcd,yLcd; //转换后的X,Y坐标值
int TSOK; //校正完成
int aba[7];
/**************************************************************************
***** 函数名:check_touch
***** 功 能:判断触摸坐标
***** 参 数:无
***** 返回值:无
***** 创建者: 潘星宇
***** 创建时间:2013-03-10
***** 最后更新:2013-03-10
****************************************************************************/
void check_touch(void)
{
if (function_flag == 1) //如果是在主显示界面
{
if ((xLcd>=COLLATE_SQURE_START_X)&&(xLcd<=COLLATE_SQURE_START_X+60)&&(yLcd>=COLLATE_SQURE_START_Y)&&(yLcd<=COLLATE_SQURE_START_Y+60)) //如果触摸的是校准
{
function_flag = 20; //改变状态准备进入校准
}
// else if ((xLcd>=MODULE_START_X)&&(xLcd<=MODULE_START_X+16*6)&&(yLcd>=MODULE_START_Y+32)&&(yLcd<=MODULE_START_Y+32+16)) //如果触摸的是样例2
// {
// function_flag = 2; //改变状态准备进入电子钟样例
// }
else if ((xLcd>=CIRCLE_SQURE_START_X)&&(xLcd<=CIRCLE_SQURE_START_X+60)&&(yLcd>=CIRCLE_SQURE_START_Y)&&(yLcd<=CIRCLE_SQURE_START_Y+60)) //如果触摸的是样例3
{
function_flag = 3; //改变状态准备进入气泡样例
}
else if ((xLcd>=SNAKE_SQURE_START_X)&&(xLcd<=SNAKE_SQURE_START_X+60)&&(yLcd>=SNAKE_SQURE_START_Y)&&(yLcd<=SNAKE_SQURE_START_Y+60)) //如果触摸的是样例4
{
function_flag = 4; //改变状态准备进入贪吃蛇样例
}
else if ((xLcd>=DOOR_SQURE_START_X)&&(xLcd<=DOOR_SQURE_START_X+60)&&(yLcd>=DOOR_SQURE_START_Y)&&(yLcd<=DOOR_SQURE_START_Y+60)) //如果触摸的是样例5
{
function_flag = 5; //改变状态准备进入门禁样例
}
// else if ((xLcd>=200)&&(xLcd<=216)&&(yLcd>=150)&&(yLcd<=166))//如果触摸的是校准
// {
// function_flag = 20; //改变状态准备校准
// }
}
// else if (function_flag == 1) //如果是在跑马灯显示界面
// {
// if ((xLcd>=296)&&(xLcd<=328)&&(yLcd>=100)&&(yLcd<=116)) //如果触摸的是返回
// {
// draw_return(200+16*6, 100, COLOR_BLACK, COLOR_DARK_GREEN); //背景变为深绿色
// delay(16000000);
// function_flag = 0; //退出本样例
// }
// }
// else if (function_flag == 2) //如果是在电子钟显示界面
// {
// if ((xLcd>=400)&&(xLcd<=432)&&(yLcd>=130)&&(yLcd<=146)) //如果触摸的是返回
// {
// draw_return(400, 130, COLOR_BLACK, COLOR_DARK_GREEN); //背景变为深绿色
// delay(16000000);
// function_flag = 0; //退出本样例
// }
// }
else if (function_flag == 3) //如果是在气泡显示界面
{
if ((xLcd>=298)&&(xLcd<=298+50)&&(yLcd>=225)&&(yLcd<=225+30)) //如果触摸的是返回
{
draw_rectangle(298,225,50,30,COLOR_ON);
draw_return(308, 230, COLOR_BLACK, COLOR_ON);
delay(16000000);
function_flag = 1; //退出本样例
}
else if((xLcd>=150)&&(xLcd<=150+50)&&(yLcd>=225)&&(yLcd<=225+30)) //如果触摸的是加速
{
draw_rectangle(150,225,50,30,COLOR_ON);
draw_increase_speed(160, 230, COLOR_BLACK, COLOR_ON);
delay(16000000);
draw_rectangle(150,225,50,30,COLOR_OFF);
draw_increase_speed(160, 230, COLOR_BLACK, COLOR_OFF);
if (circle_time>100000)
{
circle_time -= 200000;
}
}
else if((xLcd>=220)&&(xLcd<=220+50)&&(yLcd>=225)&&(yLcd<=225+30)) //如果触摸的是减速
{
draw_rectangle(220,225,50,30,COLOR_ON);
draw_decrease_speed(230, 230, COLOR_BLACK, COLOR_ON);
delay(16000000);
draw_rectangle(220,225,50,30,COLOR_OFF);
draw_decrease_speed(230, 230, COLOR_BLACK, COLOR_OFF);
if (circle_time<2000000)
{
circle_time += 200000;
}
}
}
else if (function_flag == 4) //如果是在贪吃蛇显示界面
{
if ((xLcd>=298)&&(xLcd<=298+50)&&(yLcd>=225)&&(yLcd<=225+30)) //如果触摸的是返回
{
draw_rectangle(298,225,50,30,COLOR_ON);
draw_return(308, 230, COLOR_BLACK, COLOR_ON);
delay(16000000);
function_flag = 1; //退出本样例
}
else if((xLcd>=150)&&(xLcd<=150+50)&&(yLcd>=225)&&(yLcd<=225+30)) //如果触摸的是加号
{
draw_rectangle(150,225,50,30,COLOR_ON);
draw_increase_speed(160, 230, COLOR_BLACK, COLOR_ON);
delay(16000000);
draw_rectangle(150,225,50,30,COLOR_OFF);
draw_increase_speed(160, 230, COLOR_BLACK, COLOR_OFF);
if (snake_delay_time>1000000)
{
snake_delay_time -= 4000000;
}
}
else if((xLcd>=220)&&(xLcd<=220+50)&&(yLcd>=225)&&(yLcd<=225+30)) //如果触摸的是减号
{
draw_rectangle(220,225,50,30,COLOR_ON);
draw_decrease_speed(230, 230, COLOR_BLACK, COLOR_ON);
delay(16000000);
draw_rectangle(220,225,50,30,COLOR_OFF);
draw_decrease_speed(230, 230, COLOR_BLACK, COLOR_OFF);
if (snake_delay_time<200000000)
{
snake_delay_time += 4000000;
}
}
else
{
snake_ch = 1; //贪吃蛇有按键发生
snake_xLcd = xLcd; //返回贪吃蛇时的坐标,用于改变蛇的运动方向
snake_yLcd = yLcd;
}
}
else if ((function_flag == 5)&(door_error ==0)) //如果是在门禁界面
{
if ((xLcd>=320)&&(xLcd<=320+60)&&(yLcd>=210)&&(yLcd<=210+30)) //如果触摸的是返回
{
draw_rectangle(320,210,60,30,COLOR_ON);
draw_return(330, 218, COLOR_BLACK, COLOR_ON);
delay(16000000);
creat_flag = 0;
function_flag = 1; //退出本样例
}
else if(door_flag == 0)
{
door_key_value = check_door_key(xLcd,yLcd); //读取按键值
door_flag = 1; //清空标志位
}
}
}
/**************************************************************************
***** 函数名:AdcTsAuto()
***** 功 能:触摸屏中断服务程序
***** 参 数:无
***** 返回值:无
***** 创建者:
***** 创建时间:2011-03-30
***** 最后更新:2011-03-30
****************************************************************************/
void __irq AdcTsAuto(void)
{
volatile int nXMin = 1024; //10位AD最大1023 最小0 赋值刚好比范围多了1
volatile int nXMax = -1; //赋值与名字相反是为了后面的算法
volatile int nYMin = 1024;
volatile int nYMax = -1;
volatile int nX = 0; //8次采样临时用的X,Y坐标寄存器
volatile int nY = 0;
U8 nIndex=0;
volatile int nXCount = 0;
volatile int nYCount = 0;
if (rADCDAT0&0x8000)
{
rADCDAT0 &= ~0x8000;
/*配置为检测笔触按下中断信号*/
rADCTSC = rADCTSC & (~(1<<8));
/*清ADC,TC中断标志*/
rSUBSRCPND |= BIT_SUB_TC;
ClearPending(BIT_ADC);
/*再次配置为等待中断模式,为下次按下笔触作准备*/
rADCTSC = 0xd3; //等待再次笔尖落下产生中断
}
else //如果笔尖为落下态产生的中断
{
for (nIndex = 0; nIndex < 8; nIndex++)
{
/*配置为禁止上拉,自动转换XY坐标模式*/
rADCTSC=(1<<3)|(1<<2);
/*设置采样间隔*/
rADCDLY=40000; //Normal conversion mode delay about (1/50M)*40000=0.8ms
/*启动ADC*/
rADCCON|=0x1;
/*等待ADC启动起来*/
while (rADCCON & 0x1);
/*这一步是必须的,等待ADC转换结束*/
while (!(rADCCON & 0x8000));
/*检测ADC中断源标志是否置位*/
while (!(rSRCPND & (BIT_ADC)));
nX = (rADCDAT0&0x3ff); //取低十位AD转换值
nY = (rADCDAT1&0x3ff);
if (nX < nXMin) nXMin = nX; //记录下X,Y每次采样的最大和最小值
if (nX > nXMax) nXMax = nX;
if (nY < nYMin) nYMin = nY;
if (nY > nYMax) nYMax = nY;
nXCount += nX; //和累加
nYCount += nY;
}
xdata = (nXCount - nXMin - nXMax) / 6; //一共取样8次,减去最大值和最小值后,取平均
ydata = (nYCount - nYMin - nYMax) / 6;
/*清除ADC,TC中断标志位*/
rSUBSRCPND|=BIT_SUB_TC;
ClearPending(BIT_ADC);
if(!TSOK) //如果没有校验完成
{
/*等待中断模式*/
rADCTSC =0xd3;
/*配置为检测松开状态中断信号*/
rADCTSC=rADCTSC|(1<<8); // Detect stylus up interrupt signal.
while(1)
{
if (rADCUPDN&(1<<1))
{
rADCUPDN = 0;
break;
}
}
tsflag = 1;
ts.ts_x = xdata;
ts.ts_y = ydata;
}
else
{
xLcd = ( calibration_number[2] +calibration_number[0]*xdata + calibration_number[1]*ydata ) / calibration_number[6];
yLcd = ( calibration_number[5] +calibration_number[3]*xdata +calibration_number[4]*ydata ) / calibration_number[6];
rINTSUBMSK =rINTSUBMSK&(~BIT_SUB_TC); //打开触摸屏子屏蔽
check_touch(); //判断触摸坐标
/*等待中断模式*/
rADCTSC =0xd3;
/*配置为检测松开状态中断信号*/
rADCTSC=rADCTSC|(1<<8); // Detect stylus up interrupt signal.
}
}
}
/**************************************************************************
***** 函数名:TouchpanelInit()
***** 功 能:触摸屏初始化
***** 参 数:无
***** 返回值:无
***** 创建者:
***** 创建时间:2011-03-30
***** 最后更新:2011-03-30
****************************************************************************/
void TouchpanelInit(void)
{
rADCUPDN = 0; //无抬起落下
rADCDLY=50000; //延迟去抖动,延迟时钟为X-tal(3.68M)(1/3.6864M)*50000=13.56ms
rADCCON=(1<<14)+(9<<6); //使能预分频,预分频值为9
rADCTSC=0xd3; // 0 1 1 0 1 0 0 11
//检测笔尖落下 YMEN YPDIS XMDIS XPDIS XP-UPEN ADC_NORMAL 等待中断(笔尖落下产生中断)
pISR_ADC = (int)AdcTsAuto; //配置触摸屏中断服务函数
rINTMSK = rINTMSK&(~(BIT_ADC)); //打开触摸屏的总屏蔽(ADC中断使能)
rINTSUBMSK =rINTSUBMSK&(~(BIT_SUB_TC)); //打开触摸屏的子屏蔽
}
/**************************************************************************
***** 函数名:touchpanelRevise()
***** 功 能:触摸屏校正程序
***** 参 数:TS_again: 1 从新校正
0 判断EEPROM对应的地址选择是否需要校正
***** 返回值:无
***** 创建者:
***** 创建时间:2011-03-30
***** 最后更新:2011-03-30
****************************************************************************/
void touchpanelRevise(U8 TS_again)
{
char h_8 = 0; //参数最高8位
U8 mh_8 = 0; //参数次高8位
U8 ml_8 = 0; //参数次低8位
U8 l_8 = 0; //参数最低8位
U16 address = 0;
U8 i;
U8 IIC_data; //判断是否已经校准过的数据
int k;
for (k=0; k<7; k++)
{
aba[k]= calibration_number[k];
// if(aba[k]==0);
}
if (TS_again == 1) //表示用户主动申请校准,不进行IIC判断直接校准,并保持校准结果
{
TSOK = 0;
ts_main();
for (i=0; i<7; i++)
{
switch(i)
{
case 0:
{
address = 0x00;
break;
}
case 1:
{
address = 0x10;
break;
}
case 2:
{
address = 0x20;
break;
}
case 3:
{
address = 0x30;
break;
}
case 4:
{
address = 0x40;
break;
}
case 5:
{
address = 0x50;
break;
}
case 6:
{
address = 0x60;
break;
}
default:
{
break;
}
}
h_8 = ((calibration_number[i]&0xff000000)>>24);
mh_8 = ((calibration_number[i]&0x00ff0000)>>16);
ml_8 = ((calibration_number[i]&0x0000ff00)>>8);
l_8 = (calibration_number[i]&0x000000ff);
Wr24C080(EEPROM_ADDRESS,address,h_8); //保存校验参数0~6 最高8位
delay(16000000);
Wr24C080(EEPROM_ADDRESS,address+1,mh_8); //保存校验参数0~6 次高8位
delay(16000000);
Wr24C080(EEPROM_ADDRESS,address+2,ml_8); //保存校验参数0~6 次低8位
delay(16000000);
Wr24C080(EEPROM_ADDRESS,address+3,l_8); //保存校验参数0~6 最低8位
delay(16000000);
}
}
else
{
IIC_data = Rd24C080(EEPROM_ADDRESS,IIC_DATA_ADDRESS);
delay(16000000);
if (IIC_data != IIC_DATA) //如果没有进行过校准
{
ts_main();
for (i=0; i<7; i++)
{
switch(i)
{
case 0:
{
address = 0x00;
break;
}
case 1:
{
address = 0x10;
break;
}
case 2:
{
address = 0x20;
break;
}
case 3:
{
address = 0x30;
break;
}
case 4:
{
address = 0x40;
break;
}
case 5:
{
address = 0x50;
break;
}
case 6:
{
address = 0x60;
break;
}
default:
{
break;
}
}
h_8 = ((calibration_number[i]&0xff000000)>>24);
mh_8 = ((calibration_number[i]&0x00ff0000)>>16);
ml_8 = ((calibration_number[i]&0x0000ff00)>>8);
l_8 = (calibration_number[i]&0x000000ff);
Wr24C080(EEPROM_ADDRESS,address,h_8); //保存校验参数0~6 最高8位
delay(16000000);
Wr24C080(EEPROM_ADDRESS,address+1,mh_8); //保存校验参数0~6 次高8位
delay(16000000);
Wr24C080(EEPROM_ADDRESS,address+2,ml_8); //保存校验参数0~6 次低8位
delay(16000000);
Wr24C080(EEPROM_ADDRESS,address+3,l_8); //保存校验参数0~6 最低8位
delay(16000000);
}
}
else //已经校准过
{
for(i=0; i<7; i++)
{
switch(i)
{
case 0:
{
address = 0x00;
break;
}
case 1:
{
address = 0x10;
break;
}
case 2:
{
address = 0x20;
break;
}
case 3:
{
address = 0x30;
break;
}
case 4:
{
address = 0x40;
break;
}
case 5:
{
address = 0x50;
break;
}
case 6:
{
address = 0x60;
break;
}
default:
{
break;
}
}
h_8 = Rd24C080(EEPROM_ADDRESS,address); //读取校验参数0~6 最高8位
delay(4000);
mh_8 = Rd24C080(EEPROM_ADDRESS,address+1); //读取校验参数0~6 次高8位
delay(4000);
ml_8 = Rd24C080(EEPROM_ADDRESS,address+2); //读取校验参数0~6 次低8位
delay(4000);
l_8 = Rd24C080(EEPROM_ADDRESS,address+3); //读取校验参数0~6 最低8位
delay(4000);
calibration_number[i] = ((h_8<<24)|(mh_8<<16)|(ml_8<<8)|(l_8));
}
TSOK = 1; //触摸屏已校正
}
}
}
头文件如下:
#ifndef TOUCH_H
#define TOUCH_H
#include "2440addr.h"
#include "def.h"
#include "fbutils.h"
#include "tslib.h"
#include "global_value.h"
#include "LCD.h"
#include "snake.h"
#include "common_functions.h"
#include "random_circle.h"
#include "snake.h"
#include "IIC.h"
#include "door.h"
/**************************************************************************
***** 函数名:TouchpanelInit()
***** 功 能:触摸屏初始化
***** 参 数:无
***** 返回值:无
***** 创建者:
***** 创建时间:2011-03-30
***** 最后更新:2011-03-30
****************************************************************************/
extern void TouchpanelInit(void);
/**************************************************************************
***** 函数名:touchpanelRevise()
***** 功 能:触摸屏校正程序
***** 参 数:TS_again: 1 从新校正
0 判断EEPROM对应的地址选择是否需要校正
***** 返回值:无
***** 创建者:
***** 创建时间:2011-03-30
***** 最后更新:2011-03-30
****************************************************************************/
extern int ts_main(void);
extern void touchpanelRevise(U8 TS_again);
extern int TSOK; //校正完成
#endif
关于校准的问题下一章再讲。