触摸屏驱动程序设计
触摸屏工作原理:
四线电阻屏结构上如图,是在玻璃或丙稀酸基板上覆盖两层均匀导电的ITO层,分别作为x电极和y电极,他们之间由均匀排列的透明格点分来绝缘。X电极和y电极的正负端由导电线(黑色粗体线)从两端引出,引出x-,x+,y-,y+.
当接触触摸屏表面并施加压力时,上层的ITO导电层和下层的ITO导电层发生接触,形成上面右图的等效电路。
1.y坐标计算:
在y+加驱动电压V-drive,y-接地。X+作为引出端测量接触点的电压,由于ITO层均匀导电,触电电压与V-drive电压之比等于Y坐标与屏高度之比。
2.x坐标计算:
在x+加驱动电压V-drive电压,x-接地。Y+作为引出端测量接触点的电压,由于ITO层均匀导电,触点电压与V-drive电压比等于x坐标与屏宽度之比。
y=Vx/V-driv *heightx=Vy/ V-driv * width
触摸屏工作流程(理解好这几步流程,代码至少能看懂30%)
1.设置触摸屏接口为等待中断模式,等待触摸屏被按下。
2.如果中断(INT_TC)发生,选择X,Y坐标转换模式(x/y坐标分别转换模式,x/y坐标自动转换),启动AD转换。
3.当AD转换完后,通过中断(INT_ADC),获取x/y坐标,
ADCDAT0 bit[9:0]-x坐标;
ADCDAT1 bit[9:0]-y坐标;
4.设置触摸屏接口为等待中断模式,等待触摸笔离开触摸屏。
5.返回步骤1,等待下次触摸笔被按下。
#define GLOBAL_CLK 1 #include <stdlib.h> #include <string.h> #include "def.h" #include "option.h" #include "2440addr.h" #include "2440lib.h" #include "2440slib.h" #include "mmu.h" #include "profile.h" #include "memtest.h" #define ADC_FREQ 2500000 //#define ADC_FREQ 1250000 int count = 0; volatile U32 preScaler; int xdata,ydata; void Test_Touchpanel(void); static void __irq AdcTsAuto(void); static void cal_cpu_bus_clk(void); void Set_Clk(void); /************************************************* Function name: delay Parameter : times Description : 延时函数 Return : void Argument : void Autor & date : Daniel **************************************************/ void delay(int times) { int i,j; for(i=0;i<times;i++) for(j=0;j<400;j++); } /************************************************* Function name: Main Parameter : void Description : 主功能函数 Return : void Argument : void Autor & date : Daniel **************************************************/ int Main(void) { int Scom=0; MMU_Init(); Set_Clk(); Uart_Init(0,115200); Uart_Select(Scom); // Uart_Printf("\nHello World!\n"); Test_Touchpanel(); while(1); return 0; } /************************************************* Function name: Test_Touchpanel Parameter : void Description : 触摸屏初始化 Return : void Argument : void Autor & date : Daniel **************************************************/ void Test_Touchpanel(void) { rADCDLY=50000; //Normal conversion mode delay about (1/3.6864M)*50000=13.56ms /*设置AD转频率*/ preScaler = ADC_FREQ; Uart_Printf("ADC conv,freq. = %dHz\n",preScaler); preScaler = 50000000/ADC_FREQ - 1; //PCLK=50M rADCCON = (1<<14)|(preScaler<<6); //ADCPRS En,PRSCVL // rADCCON=(1<<14)+(preScaler<<6); //ADCPRS En, ADCPRS Value Uart_Printf("ADC touch screen test\n"); /*设置触摸屏为等待中断模式,等待触摸笔被按下*/ rADCTSC=0xd3; //Wfait,XP_PU,XP_Dis,XM_Dis,YP_Dis,YM_En /*clear irq*/ //ClearPending(BIT_ADC); rSRCPND = 0x80000000; rINTPND = 0x80000000; ClearSubPending(BIT_SUB_TC); pISR_ADC = (U32)AdcTsAuto; /*enable INT_TC irq*/ //EnableIrq(BIT_ADC); rINTMSK = 0x7fffffff;//允许中断 EnableSubIrq(BIT_SUB_TC); } /************************************************* Function name: AdcTsAuto Parameter : void Description : 中断服务程序 Return : void Argument : void Autor & date : Daniel **************************************************/ static void __irq AdcTsAuto(void) { U32 saveAdcdly; /****************stylus down************************/ /*检测子中断源,判断是否是INT_TC中断,且触摸笔按下*/ if(rSUBSRCPND & (BIT_SUB_TC))//产生中断 { if( !(rADCDAT0&0x8000))//按下产生的中断 Uart_Printf("\nStylus down\n"); else //抬起产生的中断 Uart_Printf("\nStylus up\n"); } /*pull-up disable,自动连续X,Y坐标转换*/ rADCTSC = (1<<3)|(1<<2); saveAdcdly=rADCDLY; rADCDLY=40000; //延时 //Normal conversion mode delay about (1/50M)*40000=0.8ms /*开始AD转换*/ rADCCON|=0x1; //start ADC while(rADCCON & 0x1); //check if Enable_start is low while(!(rADCCON & 0x8000));//转换是否结束 //check if EC(End of Conversion) flag is high, This line is necessary~!! while(!(rSRCPND & 0x80000000)); //check if ADC is finished with interrupt bit /*获取X,Y坐标*/ xdata=(rADCDAT0&0x3ff); ydata=(rADCDAT1&0x3ff); ClearSubPending(BIT_SUB_TC); //ClearPending(BIT_ADC); rSRCPND = 0x80000000; rINTPND = 0x80000000; EnableSubIrq(BIT_SUB_TC); //EnableIrq(BIT_ADC); rINTMSK = 0x7fffffff; /****************stylus down************************/ /****************stylus up**************************/ /*设置触摸屏为等待中断模式,等待触摸笔抬起*/ rADCTSC =0xd3; //Waiting for interrupt rADCTSC=rADCTSC|(1<<8); // Detect stylus up interrupt signal. while(1) //to check Pen-up state { if(rSUBSRCPND & (BIT_SUB_TC)) //check if ADC is finished with interrupt bit { Uart_Printf("Stylus Up Interrupt~!\n"); break; //if Stylus is up(1) state } } /****************stylus up**************************/ Uart_Printf("count=%03d XP=%04d, YP=%04d\n", count++, xdata, ydata); rADCDLY=saveAdcdly; /*设置触摸屏为等待中断模式,等待下次触摸笔按下*/ rADCTSC =0xd3; //Waiting for interrupt ClearSubPending(BIT_SUB_TC); //ClearPending(BIT_ADC); rSRCPND = 0x80000000; rINTPND = 0x80000000; EnableSubIrq(BIT_SUB_TC); //EnableIrq(BIT_ADC); rINTMSK = 0x7fffffff; } /************************************************* Function name: Set_Clk() Parameter : void Description : 设置CPU的时钟频率 Return : void Argument : void Autor & date : Daniel **************************************************/ void Set_Clk(void) { int i; U8 key; U32 mpll_val = 0 ; i = 2 ; //don't use 100M! //boot_params.cpu_clk.val = 3; switch ( i ) { case 0: //200 key = 12; mpll_val = (92<<12)|(4<<4)|(1); break; case 1: //300 key = 13; mpll_val = (67<<12)|(1<<4)|(1); break; case 2: //400 key = 14; mpll_val = (92<<12)|(1<<4)|(1); break; case 3: //440!!! key = 14; mpll_val = (102<<12)|(1<<4)|(1); break; default: key = 14; mpll_val = (92<<12)|(1<<4)|(1); break; } //init FCLK=400M, so change MPLL first ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); //set the register--rMPLLCON ChangeClockDivider(key, 12); //the result of rCLKDIVN [0:1:0:1] 3-0 bit cal_cpu_bus_clk(); //HCLK=100M PCLK=50M } /************************************************* Function name: cal_cpu_bus_clk Parameter : void Description : 设置PCLK\HCLK\FCLK的频率 Return : void Argument : void Autor & date : Daniel **************************************************/ static void cal_cpu_bus_clk(void) { static U32 cpu_freq; static U32 UPLL; U32 val; U8 m, p, s; val = rMPLLCON; m = (val>>12)&0xff; p = (val>>4)&0x3f; s = val&3; //(m+8)*FIN*2 不要超出32位数! FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100; //FCLK=400M FIN=12000000 val = rCLKDIVN; m = (val>>1)&3; p = val&1; val = rCAMDIVN; s = val>>8; switch (m) { case 0: HCLK = FCLK; break; case 1: HCLK = FCLK>>1; break; case 2: if(s&2) HCLK = FCLK>>3; else HCLK = FCLK>>2; break; case 3: if(s&1) HCLK = FCLK/6; else HCLK = FCLK/3; break; } if(p) PCLK = HCLK>>1; else PCLK = HCLK; if(s&0x10) cpu_freq = HCLK; else cpu_freq = FCLK; val = rUPLLCON; m = (val>>12)&0xff; p = (val>>4)&0x3f; s = val&3; UPLL = ((m+8)*FIN)/((p+2)*(1<<s)); UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL; }