主函数:
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "profile.h"
#define LED1_on rGPBDAT = ((0xf<<5)^(1<<5)) //GPB5=0
#define LED4_on rGPBDAT = ((0xf<<5)^(1<<8)) //GPB8=0
#define LED_off rGPBDAT = (0xf<<5) //GPB5=1,GPB6=1,GPB7=1,GPB8=1
#define touch_1 (X>16&&X<64&&Y>208&&Y<224)
#define touch_2 (X>256&&X<304&&Y>208&&Y<224)
extern U32 X,Y;
extern void BMP_display(int x0,int y0,int x1,int y1,const U8 *bmp);
extern void word(int x,int y,int length,const unsigned char string[]);
extern void LCD_clear(U32 color);
extern void CLK_init(void);
extern void LCD_IO_init(void);
extern void LCD_POWER(void);
extern void LCD_init(void);
extern void LCD_on(void);
extern void LCD_off(void);
extern void Tc_calibrate(void);
extern unsigned char gImage_1[]; //extern声明引用外部数组
extern unsigned char gImage_2[];
extern unsigned char gImage_3[];
extern unsigned char gImage_4[];
extern unsigned char gImage_5[];
extern unsigned char gImage_6[];
extern unsigned char gImage_7[];
extern unsigned char gImage_8[];
void Main(void)
{
U16 n;
//保存各张图片的尺寸
U16 num[8][2]={320,240,320,240,320,240,320,240
,320,240,320,240,320,240,320,240};
U8 *photo[8]={
gImage_1,gImage_2,
gImage_3,gImage_4,
gImage_5,gImage_6,
gImage_7,gImage_8,
};
unsigned char String0[]="上一幅";
unsigned char String1[]="下一幅";
int length0=sizeof(String0);
int length1=sizeof(String1);
rGPBCON=(01<<00);//关闭蜂鸣器
rGPBDAT=0x00;
rGPGCON &=(~(1<<1)|~(1<<11)); //GPG0,GPG5为输入,即按键KEY1和KEY3输入
rGPBCON |=((1<<16)|(1<<14)|(1<<12)|(1<<10)); //GPB5~8设为输出
LED_off;
CLK_init();
LCD_POWER();
LCD_IO_init();
LCD_init();
LCD_on();
LCD_clear(0xffffff) ; //清屏显示白色
BMP_display(0, 0, num[0][0], num[0][1], photo[0]); //显示第一张图片
n=0;
while(1)
{
word(16,208,length0,String0);
word(256,208,length1,String1);
Tc_calibrate();
/*利用轮询对按键实行扫描,外加goto调转实现去抖,
可以利用中断对按键检测则去抖问题即可解决*/
m:
if((!(rGPGDAT&(1<<0)))||touch_1) //当KEY1按下
{
LED1_on;
n++;
BMP_display(0, 0, num[n][0], num[n][1], photo[n]);
if(n>7) n=0; //未超出数组范围n自加
if(!(rGPGDAT&(1<<0))) //若按键未放开则进入goto等待按键放开
{
loop1:
if(rGPGDAT&(1<<0)) goto m; //若按键放开再次进入
else //goto返回等待下一次按下
goto loop1;
}
}
else
k:
if((!(rGPGDAT&(1<<5)))||touch_2) //当KEY3按下
{
LED4_on;
if(n==0) n=7; //未超出数组范围n自减
n--;
BMP_display(0, 0, num[n][0], num[n][1], photo[n]);
if(!(rGPGDAT&(1<<5)))
{
loop2:
if(rGPGDAT&(1<<5)) goto k;
else
goto loop2;
}
}
}
}
LCD驱动函数部分:
#define GLOBAL_CLK 1
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "profile.h"
#define LCD_WIDTH 320 //屏幕宽度
#define LCD_HEIGHT 240 //屏幕高度
#define CLKVAL 4 //时钟信号
//垂直同步信号的脉宽、后肩和前肩
#define VSPW (2-1)
#define VBPD (11-1)
#define VFPD (5-1)
//水平同步信号的脉宽、后肩和前肩
#define HSPW (2-1)
#define HBPD (69-1)
#define HFPD (5-1)
//显示尺寸
#define HOZVAL (LCD_WIDTH-1)
#define LINEVAL (LCD_HEIGHT-1)
//定义显示缓存,volatile声明编译不对此进行优化,直接读取原始地址
volatile unsigned short LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
//声明为静态函数,仅在本文件可见,其他文件不能使用该函数
/**********************************
*时钟初始化
**********************************/
void CLK_init(void)
{
rMPLLCON &= ~0xFFFFF;
rMPLLCON |= (127<<12)|(2<<4)|1; //初始化FCLK为405M
rCLKDIVN = (2<<1)|1; //HCLK = FCLK/4 =100M,PCLK = HCLK/2 = 50M
}
/**********************************
*LCD端口初始化
**********************************/
void LCD_IO_init(void)
{
rGPCUP=0xff; //GPC口上拉电阻不可用
rGPCCON=0xaaaa02aa;//GPC8-15设置为VD, VM,VFRAME,VLINE,VCLK,LEND
rGPDUP=0xff; //GPD口上拉电阻不可用
rGPDCON=0xaaaaaaaa; //GPD0-15设置为VD
}
/**********************************
*LCD电源管理
**********************************/
void LCD_POWER(void)
{
rGPGUP=(1<<4);
rGPGCON=(3<<8); //GPG4设置为LCD_PWREN
rLCDCON5=(1<<3); //Enable PWREN signal
}
/**********************************
*LCD开启
**********************************/
void LCD_on(void)
{
rLCDCON1 |=1; //利用LCDCON1控制相关参数实现开启LCD
}
/**********************************
*LCD关闭
**********************************/
void LCD_off(void)
{
rLCDCON1 &=~1; //利用LCDCON1控制相关参数实现关闭LCD
}
/**********************************
*LCD初始化
**********************************/
void LCD_init(void)
{
CLK_init();
LCD_POWER();
LCD_IO_init();
LCD_on();
rLCDCON1=(CLKVAL<<8)|(3<<5)|(12<<1)|(0<<0); //VCLK=10M,TFT LCD,16bpp
rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
rLCDCON4=HSPW;
/*5:6:5Format,Enable PWREN signal,Swap Enable*/
rLCDCON5=(1<<11)|(1<<9)|(1<<8)|(1<<3)|1;
/*显存起始地址[30:22]保存到LCDSADDR1[29:21],显存始地址[21:1]位
保存到LCDSADDR1[20:0],显存结束地址[21:1]保存到LCDSADDR2[20:0]*/
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|(((U32)LCD_BUFFER&0x3fffff)>>1);
rLCDSADDR2=(((U32)LCD_BUFFER+LCD_WIDTH*LCD_HEIGHT*2)>>1)&0x1fffff;
rLCDSADDR3=LCD_WIDTH; //设置虚拟屏设置为屏幕宽度,没有可以不设置
rTPAL=0; //临时调色板不可用
rLCDINTMSK |=3; //屏蔽 LCD 中断
rTCONSEL &=~(0x17); //LCC3600,LPC3600不可用
}
GU函数I部分,用于显示文字的画图等:
#include "def.h"
#include "Font_libs.h"
#define LCD_WIDTH 320 //屏幕宽度
#define LCD_HEIGHT 240 //屏幕高度
//定义显示缓存,volatile声明编译不对此进行优化,直接读取原始地址
extern volatile unsigned short LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
/**********************************
*刷新背景颜色
**********************************/
void LCD_clear(U32 color)
{
U32 x,y;
for(y=0;y<LCD_HEIGHT;y++)
{
for(x=0;x<LCD_WIDTH;x++)
{
LCD_BUFFER[y][x]=color;
}
}
}
/**********************************
*BMP数组图片显示
**********************************/
void BMP_display(int x0,int y0,int x1,int y1,const U8 *bmp)
{
int x,y,p=0;
U32 data;
for(y=0;y<y1;y++)
{
for(x=0;x<x1;x++)
{
data=(bmp[p]<<8|bmp[p+1]);
if((x0+x)<LCD_WIDTH && (y0+y)<LCD_HEIGHT)
LCD_BUFFER[y0+y][x0+x]=data;
p=p+2;
}
}
}
/**********************************
*绘制像素点
**********************************/
void PutPixel(U32 x,U32 y,U32 c )
{
LCD_BUFFER[y][x]=c;
}
/**********************************
*绘制大小为16×16的中文字符
**********************************/
void Draw_Text16(U32 x,U32 y,U32 color,const unsigned char ch[])
{
unsigned short int i,j;
unsigned char mask,buffer;
for(i=0;i<16;i++)
{
mask=0x80; //掩码
buffer=ch[i*2]; //提取一行的第一个字节
for(j=0;j<8;j++)
{
if(buffer&mask)
{
PutPixel(x+j,y+i,color); //为笔画上色
}
mask=mask>>1;
}
mask=0x80; //掩码复位
buffer=ch[i*2+1]; //提取一行的第二个字节
for(j=0;j<8;j++)
{
if(buffer&mask)
{
PutPixel(x+j+8,y+i,color); //为笔画上色
}
mask=mask>>1;
}
}
}
/**********************************
*绘制大小为8×16的ASCII码
**********************************/
void Draw_ASCII(U32 x,U32 y,U32 color,const unsigned char ch[])
{
unsigned short int i,j;
unsigned char mask,buffer;
for(i=0;i<16;i++)
{
mask=0x80;
buffer=ch[i];
for(j=0;j<8;j++)
{
if(buffer&mask)
{
PutPixel(x+j,y+i,color);
}
mask=mask>>1;
}
}
}
/**********************************
*显示字符
**********************************/
void word(int x,int y,int length,const unsigned char string[])
{
int i,j=0;
unsigned char qh,wh;
const unsigned char *mould;
for(i=0;i<length-1;i++)
{
if(string[i]&0x80) //中文字符
{
qh=string[i]-0xa0; //区号
wh=string[i+1]-0xa0; //位号
mould=& __CHS[((qh-1)*94+wh-1)*32 ];
Draw_Text16(x+j,y,0x0f,mould);
j+=16;//每写完一个右移16个像素
i++;
}
else //ASCII码字符
{
mould=&__ASCII[string[i]*16];
Draw_ASCII(x+j,y,0x0f,mould);
j+=8;//每写完一个右移8个像素
}
}
}
/**********************************
*画直线
**********************************/
void Draw_Line(int x1,int y1,int x2,int y2,U32 color)
{
int dx,dy,e;
dx=x2-x1;
dy=y2-y1;
if(dx>=0)
{
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 1/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 2/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 8/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 7/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
else //dx<0
{
dx=-dx; //dx=abs(dx)
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 4/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 3/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 5/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
PutPixel(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 6/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
PutPixel(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
}
/**********************************
*画十字叉
**********************************/
void Draw_X(int x,int y,U32 color)
{
Draw_Line(x-20,y,x+20,y,color);
Draw_Line(x,y-20,x,y+20,color);
}
触摸屏矫正计算函数部分(基于三点矫正):
#include "def.h"
#include "2440addr.h"
#include "2440lib.h"
#define LCD_CALIBRATE 0 //1时打开触摸屏校验
#define BLACK (0x000000) //黑色
#define WHITE (0xffffff) //白色
#define YdataClear ydata=0
#define XdataClear xdata=0
extern volatile int xdata, ydata;
extern void LCD_clear(U32 n);
extern void Draw_X(int x,int y,U32 color);
extern void CLK_init(void);
extern void LCD_IO_init(void);
extern void LCD_POWER(void);
extern void LCD_init(void);
extern void LCD_on(void);
extern void LCD_off(void);
extern void Touch_Init(void);
U32 X,Y;
float x0,y0,x1,y1,x2,y2;
float xt,yt;
float A=-0.363030314,B=-0.00609157188,C=349.596954,D=-0.00253245141,E=0.312928855,F=-38.1721191,K=292207;
//读取TC坐标
void Touch_GetAdXY(float *x,float *y)
{
*x=xdata;
*y=ydata;
}
//矫正参数A,B,C,D,E,F,K的计算
void Calculate_P(float xt0,float yt0,float xt1,float yt1,float xt2,float yt2)
{
float xd0=160,yd0=40,xd1=40,yd1=180,xd2=260,yd2=200;
K=(xt0-xt2)*(yt1-yt2)-(xt1-xt2)*(yt0-yt2);
A=((xd0-xd2)*(yt1-yt2)-(xd1-xd2)*(yt0-yt2))/K;
B=((xt0-xt2)*(xd1-xd2)-(xd0-xd2)*(xt1-xt2))/K;
C=(yt0*(xt2*xd1-xt1*xd2)+yt1*(xt0*xd2-xt2*xd0)+yt2*(xt1*xd0-xt0*xd1))/K;
D=((yd0-yd2)*(yt1-yt2)-(yd1-yd2)*(yt0-yt2))/K;
E=((xt0-xt2)*(yd1-yd2)-(yd0-yd2)*(xt1-xt2))/K;
F=(yt0*(xt2*yd1-xt1*yd2)+yt1*(xt0*yd2-xt2*yd0)+yt2*(xt1*yd0-xt0*yd1))/K;
}
//数据的矫正
void Tc_Correct(float xt,float yt)
{
X=(U32)(A*xt+B*yt+C);
Y=(U32)(D*xt+E*yt+F);
}
//触摸屏矫正函数
void Tc_calibrate(void)
{
Touch_Init();
#if LCD_CALIBRATE==1
CLK_init();
LCD_POWER();
LCD_IO_init();
LCD_init();
LCD_on();
LCD_clear(BLACK);//全屏显示黑色
//位置1
Draw_X(160,40,WHITE);
YdataClear;
XdataClear;
while(1)
{
Touch_GetAdXY(&x0,&y0);//读取坐标位置
if((252<y0)&&(y0<256))//按键按下
{
Draw_X(160,40,BLACK);
break;
}
}
//位置2
Draw_X(40,180,WHITE);
YdataClear;
XdataClear;
while(1)
{
Touch_GetAdXY(&x1,&y1);//读取坐标位置
if((702<y1)&&(y1<706))//按键按下
{
Draw_X(40,180,BLACK);
break;
}
}
//位置3
Draw_X(260,200,WHITE);
YdataClear;
XdataClear;
while(1)
{
Touch_GetAdXY(&x2,&y2);//读取坐标位置
if((762<y2)&&(y2<764))//按键按下
{
Draw_X(260,200,BLACK);
break;
}
}
Calculate_P(x0,y0,x1,y1,x2,y2);
#endif
Touch_GetAdXY(&xt,&yt);//读取坐标位置
Tc_Correct(xt,yt);
Uart_Printf("X=%4d, Y=%4d\n",X,Y);
while(1)
{
if(rSUBSRCPND&(1<<9)) break;
//if(!(rGPGDAT&(1<<0))) break;
//if(!(rGPGDAT&(1<<5))) break;
}
}
触摸屏的ADC中断部分:
#include "def.h"
#include "mmu.h"
#include "2440addr.h"
#include "2440lib.h"
#define PRSCVL 9
volatile int xdata, ydata;
void __irq Adc_Tc_Handler(void);
extern U32 X,Y;
extern float xt,yt;
void Touch_Init(void)
{
MMU_Init(); //初始化MMU,解决中断向量表入口地址与内存地址之间不一致问题,进行地址的重映射
rADCCON=((1<<14)|(PRSCVL<<6)); //A/D分频时钟有效,其值为9
rADCTSC=0xd3; //光标按下中断信号,YM有效,YP无效,XM有效,XP无效,XP上拉电阻,普通ADC转换,等待中断模式
rADCDLY=50000; //正常转换模式转换延时大约为(1/3.6864M)*50000=13.56ms
rINTSUBMSK &=~(1<<9);//TC中断使能
rINTMSK &=~(1<<31);//ADC总中断使能
pISR_ADC=(int)Adc_Tc_Handler;//指向中断向量表
}
void __irq Adc_Tc_Handler(void)
{
rADCTSC|=(1<<3)|(1<<2); //XP上拉电阻无效, 自动连续测量X坐标和Y坐标.
rADCCON|=(1<<0);//ADC转换开始
while(rADCCON&(1<<0));//检测ADC转换是否开始且ADCCON[0]自动清0
while(!(rADCCON&(1<<15))); //检测ADCCON[15]是否为1,ADC转换是否结束,(必须)
while(!(rINTPND&(1<<31)));//检测ADC中断是否已请求
xdata=rADCDAT0&0x3ff;//读x坐标
ydata=rADCDAT1&0x3ff;//读y坐标
Uart_Printf("\nXdata=%04d, Ydata=%04d\n", xdata, ydata);
rSUBSRCPND|=(1<<9);
rSRCPND|=(1<<31);
rINTPND|=(1<<31);
rADCTSC =0xd3; //ADC等待中断模式
rADCTSC|=(1<<8); //ADCTSC[8]=1,设置抬起中断信号
while(1)
{
if(rSUBSRCPND&(1<<9))//检测触屏中断是否已请求
{
break; //跳出循环
}
}
rADCTSC &=~(1<<8);//ADCTSC[8]=0光标按下中断信号
rSUBSRCPND|=(1<<9);
rSRCPND|=(1<<31);
rINTPND|=(1<<31);
}
注:图片的取模在此忽略,读者自行取模,每个部分为独立的.c文件.