S3C2440之触摸屏(一)

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

关于校准的问题下一章再讲。

你可能感兴趣的:(ARM,ARM)