基于mini2440触摸屏版电子相册(裸机代码)

来源:互联网 发布:南风知我意妈妈网 编辑:程序博客网 时间:2024/05/29 18:39

主函数:

#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;elsegoto 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_PWRENrLCDCON5=(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=0extern 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);//全屏显示黑色//位置1Draw_X(160,40,WHITE);YdataClear;XdataClear;while(1){Touch_GetAdXY(&x0,&y0);//读取坐标位置if((252<y0)&&(y0<256))//按键按下{Draw_X(160,40,BLACK);break;}}//位置2Draw_X(40,180,WHITE);YdataClear;XdataClear;while(1){Touch_GetAdXY(&x1,&y1);//读取坐标位置if((702<y1)&&(y1<706))//按键按下{Draw_X(40,180,BLACK);break;}}//位置3Draw_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);#endifTouch_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 9volatile 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分频时钟有效,其值为9rADCTSC=0xd3;  //光标按下中断信号,YM有效,YP无效,XM有效,XP无效,XP上拉电阻,普通ADC转换,等待中断模式rADCDLY=50000; //正常转换模式转换延时大约为(1/3.6864M)*50000=13.56msrINTSUBMSK &=~(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]自动清0while(!(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文件.