照着别人的程序,修来该去,搞了三天,终于ok啦。把main.c文件贴出来分享。该文件比较独立,只需再加入串口打印程序,就可以运行啦。这里用的320*240的lcd屏。
程序运行后会在屏幕上显示5个“+”,让你去一次点击用于标定触摸屏的坐标和lcd坐标的关系。标定成功后程序会清屏(青)。然后点击屏幕任意地方,该地方会显示一个20*20的蓝方块。点击左下角菜单,会再次清屏。
#include "2440addr.h"
#include "def.h"
#define _ISR_STARTADDRESS 0x33ffff00
#define adc_frequency 2000000
#define SCR_XSIZE (320)
#define SCR_YSIZE (240)
#define CLKVAL (5) //VCLK=HCLK÷[(CLKVAL+1)×2]
#define PNRMODE (3) //TFT LCD panel
#define BPPMODE (12) //16 bpp for TFT
#define ENVID (1) //输出和控制 有效
#define VBPD (3) //垂直同步信号后肩
#define LINEVAL (240-1) //垂直尺寸
#define VFPD (5) //垂直同步信号前肩
#define VSPW (15) //垂直同步信号脉宽
#define HBPD (58) //水平同步信号后肩
#define HOZVAL (320-1) //水平尺寸
#define HFPD (15) //水平同步信号前肩
#define HSPW (8) //水平同步信号脉宽
#define FRM565 (1) //565格式
#define PWREN (1) //GPG供电使能(用于掉电模式)
#define BSWP (1) //字节不交换:
//#define HWSWP (1) //半字交换 16位用不到
#define OFFSIZE (0) //若不用虚拟屏幕,则为0
#define PAGEWIDTH 320//虚拟屏幕的宽 单位半字 若不用虚拟屏幕,则和实际一致
U32 PCLK=50000000;
U16 x_tsc,y_tsc;
volatile U16 pixel[240][320];
volatile short demarcated=0;
float kx,bx,ky,by;
void tsc_int_init(void);
void TSC_ISR(void) __irq ;
void tsc_init(void);
void tsc_get(void);
void lcd_init(void);
void zhengfangxing(short x, short y,U32 color);
void Delay(unsigned int x);
void LcdClearScr(U16 c);
void menu(void);
int demarcate(void);
int main(void)
{
int i=0;
demarcated=0;
Delay(10);
Uart_Printf("\n触摸屏和LCD综合实验\n");
Delay(10);
Uart_Printf("\n标定后,触摸处将显一个方块\n");
tsc_int_init(); //触摸屏中断初始化
tsc_init(); //触摸屏初始化
lcd_init(); //LCD初始化
LcdClearScr( 0x1f00);//清屏:绿
for(i=-8;i<9;i++) //设置标定屏幕的5个取样点;以“+”号在屏上显示出来;
{
pixel[10+i][10] = 0xffff;
pixel[230+i][10] = 0xffff;
pixel[230+i][310] = 0xffff;
pixel[10+i][310] = 0xffff;
pixel[120+i][160] = 0xffff;
}
for (i=-8;i<9;i++)
{
pixel[10][10+i] =0xffff;
pixel[230][10+i] =0xffff;
pixel[230][310+i]=0xffff;
pixel[10][310+i] =0xffff;
pixel[120][160+i]=0xffff;
}
while(demarcated==0);//主意 :demarcated若不定义成volatile型,demarcated变成1后此处也检测不出来。
//空循环直至标定成功;
LcdClearScr( 0x1f00 ) ; //清屏:绿
menu(); //左下角和右下角显示两个红方块做菜单。左下角表示清屏,右下角未使用。
//循环,若点击到“清屏”菜单,则清楚之前显示的蓝方块(有下面的if句完成);
while(1) // 若未点击到菜单,则在点击处显示一个蓝方块(在中断函数里完成);
if((kx*x_tsc+bx-10)<10&&(ky*y_tsc+by-230)<10&&(-10)<(kx*x_tsc+bx-10)&&-10<(ky*y_tsc+by-230))
{ x_tsc=320;//跳出if句。
LcdClearScr( 0x1f00 ) ; //清屏:绿
menu();
}
}
//显示两个方块做菜单用****************************************************
void menu(void)
{
zhengfangxing(10,230,0x8888);
zhengfangxing(310,230,0x8888);
}
//标定函数,用于程序刚开始建立触摸屏坐标与显示屏坐标之间的转换关系**********
int demarcate()
{
static float x[6],y[6];//(x0和y0未用) x1 x2 x3 x4 x5
static int j=1;
if(j<6) //此行可略去;
{ Uart_Printf("\n取样第%4d个点:x=%d,y=%d\n",j,x_tsc,y_tsc);
x[j]=x_tsc;
y[j]=y_tsc;
}
if(j++<5)return;
if((x[1]-x[4])==0|(y[1]-y[2])==0|(x[2]-x[3])==0|(y[4]-y[3])==0)
{
j=1;
Uart_Printf("\n除数为零!标定失败,请重新标定!\n");
return;
}
/*触摸屏坐标和显示屏坐标的成线性关系(y=kx+b);本实验所用的屏的
触摸屏的x方向和lcd屏的x方向在一个方向,触摸屏的y和lcd屏的y在一个
方向:前4个点用于标定k,b的值;第五个点用来检验标定误差,误差太大
会提示重新标定。所用的五个点一次为(320*240lcd坐标):(10,10)、
(10,230)、(310,230)、(310,10)(130,120)*/
kx=(10-310)/(x[1]-x[4]); //标定x方向的kx,bx
bx=10-(10-310)/(x[1]-x[4])*x[1];//bx=10-kx*x[1];
kx=( (10-310)/(x[2]-x[3])+kx )/2;//再次标定并取平均值
bx=(10-(10-310)/(x[2]-x[3])*x[2] +bx)/2;
ky=(10-230)/(y[1]-y[2]); //标定y方向的ky,by
by=10-(10-230)/(y[1]-y[2])*y[1];
ky=( (10-230)/(y[4]-y[3])+ky )/2;
by=( 10-(10-230)/(y[4]-y[3])*y[4] +by)/2;
//拿第五个点来检查标定后的误差是否在正负10个像素内;
if (-10<(kx*x[5]+bx-160) && (-10)<(kx*x[5]+bx-160)&&(-10)<(ky*y[5]+by-120) && (ky*y[5]+by-120)<10 )
{
Uart_Printf("\n标定成功\n");
demarcated=1;
return;
}
else
{
j=1;
Uart_Printf("\n标定失败,请重新标定!\n");
}
}
//**********************************************************************
void tsc_int_init(void) //触摸屏中断初始化
{
rSUBSRCPND |= 1<<9; //INT_TC清0
rSRCPND |= 1<<31; //INT_ADC清0
rINTPND |= 1<<31; //INT_ADC清0
pISR_ADC = (U32)TSC_ISR; //申请中断向量
rINTMSK = rINTMSK & ~(1<<31); //禁止ADC的屏蔽
rINTSUBMSK = rINTSUBMSK & ~(1<<9); //禁止TSC的屏蔽
rADCTSC = 0x0d3 ; //等待中断模式的特定设置
}
//*********************************************************************
void TSC_ISR(void) __irq //触摸屏中断例程
{
static int i=1;
rINTMSK |= 1<<31; //ADC中断的屏蔽
rINTSUBMSK |= 1<<9 | 1<<10; //TSC和ADC_S中断屏蔽
tsc_get(); //得到触点坐标
if(demarcated==1)
{
Uart_Printf("第%4d个点:x=%d,y=%d\n",i++,x_tsc,y_tsc);
zhengfangxing(kx*x_tsc+bx,ky*y_tsc+by,12345);
}
else
demarcate();
Delay(200); //防止起笔时抖动
rSUBSRCPND |= 1<<9; //INT_TC清0
rSRCPND |= 1<<31; //INT_ADC清0
rINTPND |= 1<<31; //INT_ADC清0
rINTMSK = rINTMSK & ~(1<<31); //禁止ADC的屏蔽
rINTSUBMSK = rINTSUBMSK & ~(1<<9); //禁止TSC的屏蔽
rINTSUBMSK = rINTSUBMSK & ~(1<<10); //禁止ADC_S的屏蔽
}
//******************************************************************
void tsc_init(void) //触摸屏初始化
{
rADCDLY= 0x9000;//必须要延时
rADCCON = (PCLK/adc_frequency - 1)<<6 | 1<<14;//设置ADC频率,预分频有效
}
//读取触摸屏坐标函数**************************************************
void tsc_get(void)
{
U16 i,temporary;
rADCCON = rADCCON & ~(7<<3) | 7<<3 ; //选择XP通道
rADCTSC = (0<<7)|(1<<6)|(1<<5)|(0<<4)|(1<<3)|(0<<2)|1 ; //X测量模式:YM=Z, YP=AIN[5] ,XM=GND, XP=V, PULL_UP=DISABLE, NORMAL, X-position (ENABLE=GND/V)
temporary=0;
for(i=0;i<10;i++)
{
rADCCON|=0x1; //启动ADC
while(rADCCON & 0x1); //等待启动
while(!(rADCCON & 0x8000)); //等待是否转换完毕
temporary += rADCDAT0&0x3FF ;
}
x_tsc=temporary/10; //读取十次,取平均值
rADCCON = rADCCON & ~(7<<3) | 5<<3 ; //选择YP通道
rADCTSC = (1<<7)|(0<<6)|(0<<5)|(1<<4)|(1<<3)|(0<<2)|2 ; //Y测量模式:YM=GND, YP=V ,XM=Z, XP=AIN[7], PULL_UP=DISENBLE, NORMAL, Y-position (DISABLE=AIN/Z)
temporary=0;
for(i=0;i<10;i++)
{
rADCCON|=0x1; //启动ADC
while(rADCCON & 0x1); //等待启动
while(!(rADCCON & 0x8000)); //等待是否转换完毕
temporary+=rADCDAT1&0X3FF;
}
y_tsc=temporary/10; //得到转换结果
tsc_int_init(); //触摸屏中断初始化
Delay(10);
while(!((rADCDAT0 & 0X8000) & (rADCDAT1 & 0X8000) ));//等待笔尖抬起
}
//*********************************************************************
void lcd_init(void)
{
rGPCUP=0XFFFFFFFF;
rGPDUP = 0xffffffff;
rGPCCON = 0xAAAAAAAA; //LCD功能
rGPDCON = 0xAAAAAAAA; //LCD功能
rGPGCON = rGPGCON & ~(3<<8) | 3<<8 ; //LCD电源功能
rLCDCON1 =0;
rLCDCON1 = rLCDCON1 & ~(0x3ff<<8) | CLKVAL<<8 ; //LCD频率
rLCDCON1 = rLCDCON1 & ~(0x3<<5) | PNRMODE<<5 ; //显示模式
rLCDCON1 = rLCDCON1 & ~(0xc<<1) | BPPMODE<<1 ; //BPP模式(每个像素用几位表示)
rLCDCON1 = rLCDCON1 & ~(1) | 0 ; //关闭输出
rLCDCON2 = rLCDCON2 & ~(0xff<<24) | VBPD<<24 ; //与LCD属性一致
rLCDCON2 = rLCDCON2 & ~(0x3ff<<14) | (LINEVAL)<<14 ; //垂直尺寸
rLCDCON2 = rLCDCON2 & ~(0xff<<6) | VFPD<<6 ; //与LCD属性一致
rLCDCON2 = rLCDCON2 & ~(0x3f) | VSPW ; //与LCD属性一致
rLCDCON3 = rLCDCON3 & ~(0x7f<<19) | HBPD<<19 ; //与LCD属性一致
rLCDCON3 = rLCDCON3 & ~(0x7ff<<8) | (HOZVAL)<<8 ; //水平尺寸
rLCDCON3 = rLCDCON3 & ~(0xff) | HFPD ; //与LCD属性一致
rLCDCON4 = rLCDCON4 & ~(0xff00) |(13<<8) ;
rLCDCON4 = rLCDCON4 & ~(0xff) | HSPW ; //与LCD属性一致
rLCDCON5 = rLCDCON5 & ~(1<<11) | FRM565<<11 ; //模式:565或5551
rLCDCON5 = rLCDCON5 |(1<<8) ;
rLCDCON5 = rLCDCON5 & ~(1<<3) | PWREN<<3 ; //供电引脚使能 ( GPG4 )
rLCDCON5 = rLCDCON5 & ~(1<<1) | BSWP ; //字节是否交换
rLCDSADDR1 = rLCDSADDR1 & ~(0x1ff<<21) | ( ( (U32)pixel>>22 )&0x1ff )<<21 ; //缓存区首地址高位[30:22]->rLCDSADDR1[29:21]
rLCDSADDR1 = rLCDSADDR1 & ~(0x1fffff) | ( (U32)pixel>>1 )&0x1fffff ; //缓存区首地址低位[21:1]->rLCDSADDR1[20:0]
rLCDSADDR2 = rLCDSADDR2 & ~(0x1fffff) | ( ((U32)pixel+(LINEVAL+1)*(HOZVAL+1)*2)>>1 )&0x1fffff ; //缓存区(尾地址+1)低位[21:1]->rLCDSADDR2[20:0]
rLCDSADDR3 = rLCDSADDR3 & ~(0x7ff<<11) |OFFSIZE<<11 ; //虚拟屏幕偏移长度
rLCDSADDR3 = rLCDSADDR3 & ~(0x7ff) | PAGEWIDTH ; //虚拟屏幕宽度
rLCDCON1 = rLCDCON1 & ~(1) | ENVID ; //开启输出,这个要最后做,不然有问题
}
void LcdClearScr(U16 c)//lcd 清屏函数
{
unsigned int x,y;
for (y=0;y<SCR_YSIZE;y++)
{
for(x=0;x<SCR_XSIZE;x++)
pixel[y][x]=c;
}
}
/*未用到************************************************************
U8 make_pixel(U16 x,U16 y,U32 color)
{
if(x<SCR_XSIZE && y<SCR_YSIZE)
{
pixel[y][x] = color;
return 1;
}
else return 0;
}
*/
//*矩形填充*********************************************************
void rectangle(U16 x1,U16 x2,U16 y1,U16 y2,U32 color)
{
U16 x;
for(;y1<=y2;y1++)
for(x=x1;x<=x2;x++)
if(x>=0&&x<SCR_XSIZE&&y1>=0&&y1<SCR_YSIZE)
pixel[y1][x] = color;
}
//此函数只是简单的调用了另一个函数,有存在的必要吗********************
void zhengfangxing(short x,short y,U32 color)
{
if(x<0|y<0)
{
Uart_Printf("\nx=%d;y=%d\n",x,y);
return;
}
rectangle(x-10,x+10,y-10,y+10,color);
}
//*******************************************************************
void Delay(unsigned int x)
{
unsigned int i,j,k;
for(i=0;i<=x;i++)
for(j=0;j<0xff;j++)
for(k=0;k<0xff;k++);
}