现在的位置: 首页 > 综合 > 正文

s3c2440 LCD及触摸屏的学习笔记(2)

2017年08月25日 ⁄ 综合 ⁄ 共 12123字 ⁄ 字号 评论关闭

触摸屏是通过中断来实现的。我的程序是在sdram中运行的,要想正确的实现中断跳转,就要使MMU工作,实现物理地址与虚拟地址的映射,把虚拟地址0x00000000映射到物理地址0x30000000(sdram的首地址)。MMU相应的函数在2440slib.s中。

 触摸屏可分为矢量压力传感式、电阻式、电容式、红外式和表面声波式等,我用的是最普遍的-四线电阻式。

 

s3c2440集成了4线制电阻式的触摸屏接口,触点坐标的检测是通过A/D转换来实现的。s3c2440提供8路A/D模拟输入,其中有4路是与触摸屏复用的,s3c2440比s3c2410改进的地方是片内部加入了开关用的MOS管,在设计电路时,直接将4路触摸屏引出外加一路基准电压(3.3v)就可以了。
  s3c2440一共有4种触摸屏接口模式,其中,自动(连续)XY坐标转换模式和等待中断模式应用地比较常见。在此,为实现触摸屏的功能,先是设置为等待中断模式,在产生中断后,再设置为自动(连续)XY坐标转换模式,依次读取触点的坐标值。

  还有就是触摸屏的校准, 校准就是实现触摸屏上的x、y坐标和LCD的像素坐标对应起来。比较常见的校正方法是三点校正法(网上找的),即 
LCD
上每个点PD的坐标为[XD,YD],触摸屏上每个点PT的坐标为[XT,YT]。要实现触摸屏上的坐标转换为LCD上的坐标,需要下列公式进行转换:

 

 简单的程序实现:

代码

#include "def.h"
#include 
"option.h"
#include 
"2440addr.h"     
#include 
"2440lib.h"
#include 
"2440slib.h"   
#include 
"mmu.h"
//================================

extern char __ENTRY[];
//void MMU_SetMTT(int vaddrStart,int vaddrEnd,int paddrStart,int attr);
//void MMU_Init(void);

//LCD*****************************************************
#define M5D(n)  ((n) & 0x1fffff)     //用于设置显示缓存区时,取低21位地址

#define LCD_WIDTH   240              //屏幕的宽
#define LCD_HEIGHT  320              //屏幕的高
 
//垂直同步信号的脉宽、后肩和前肩-----这些值是根据TopPoly-TD035STED4.pdf文件中的13页的表
#define VSPW      1 //(3-1)
#define VBPD      1 //(15-1)
#define VFPD      1 //(12-1)

//水平同步信号的脉宽、后肩和前肩-----这些值是根据TopPoly-TD035STED4.pdf文件中的13页的表
#define HSPW       (10-1)
#define HBPD       (20-1)
#define HFPD        (10-1)

//显示尺寸
#define LINEVAL  (LCD_HEIGHT-1)
#define HOZVAL   (LCD_WIDTH-1)

//for LCDCON1
#define CLKVAL_TFT          4            //设置时钟信号
#define MVAL_USED          0            //
#define PNRMODE_TFT      3            //TFT型LCD
#define BPPMODE_TFT      13           //24位TFT型LCD

//for LCDCON5 
#define BPP24BL        0       //32位数据表示24位颜色值时,低位数据有效,高8位无效
#define INVVCLK        0       //像素值在VCLK下降沿有效
#define INVVLINE       1       //翻转HSYNC信号
#define INVVFRAME      1       //翻转VSYNC信号
#define INVVD          0       //正常VD信号极性
#define INVVDEN        0       //正常VDEN信号极性
#define PWREN          1       //使能PWREN信号
#define BSWP           0       //颜色数据字节不交换
#define HWSWP          0       //颜色数据半字不交换

//定义显示缓存区
volatile unsigned int LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];

int A,B,C,D,E,F,K;
volatile int xdata, ydata;
int flagIIC;            //IIC标志
int flagTS;             //触摸屏标志
//lCD******************************************************
//LCD显示函数//////////////////////////////////////////////////
//延时程序
void delay(int a)
{
       
int k;
       
for(k=0;k<a;k++)              ;
}
   
//绘制屏幕背景颜色,颜色为c
void Brush_Background( unsigned int c)
{
   
int x,y ;
    
for( y = 0 ; y < LCD_HEIGHT ; y++ )
    {
        
for( x = 0 ; x < LCD_WIDTH ; x++ )
        {
            LCD_BUFFER[y][x] 
= c ;
        }
    }
}

//绘制“十”字型
void drawCross(unsigned int x,unsigned int y,unsigned int color)
{
       
int i;
       
for(i=x-10;i<x+11;i++)
            LCD_BUFFER[y][i]
=color;
       
for(i=y-10;i<y+11;i++)
               LCD_BUFFER[i][x]
=color;
}

//绘制正方形
void drawsquare(unsigned int x,unsigned int y,unsigned int color)
{
    
int i,j;
    
int x1=x-2;
    
int y1=y-2;
    
for(i=y1;i<y+2;i++)
    {
        
for(j=x1;j<x+2;j++)
            LCD_BUFFER[i][j] 
= color ;
    }
}

//绘制大小为8×16的ASCII码
void Draw_ASCII(unsigned int x,unsigned int y,unsigned int 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)
             {
                 LCD_BUFFER[y
+i][x+j]=color;
             }
             mask
=mask>>1;                  
        }
    }
}

 void init_port_lcd()//初始化
 {
    rGPCCON 
= 0xaaaaaaaa;       
    rGPCUP  
= 0xffff;     // The pull up function is disabled GPC[15:0] 

    //*** PORT D GROUP
    
//Ports  : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0
    
//Signal : VD23  VD22  VD21  VD20  VD19  VD18  VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9  VD8
    
//Binary : 10    10  , 10    10  , 10    10  , 10   10 , 10   10 , 10   10 , 10   10 ,10   10
    rGPDCON = 0xaaaaaaaa;       
    rGPDUP  
= 0xffff

    rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;
    rLCDCON2
=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
    rLCDCON3
=(HBPD<<19)|(HOZVAL<<8)|(HFPD);
    rLCDCON4
=(HSPW);//
    
//rLCDCON4 =  (5<< 0);
    rLCDCON5 = (BPP24BL<<12| (INVVCLK<<10| (INVVLINE<<9| (INVVFRAME<<8| (0<<7| (INVVDEN<<6| (PWREN<<3)  |(BSWP<<1| (HWSWP);

    rLCDSADDR1=(((unsigned int)LCD_BUFFER>>22)<<21)|M5D((unsigned int)LCD_BUFFER>>1);
    rLCDSADDR2
=M5D( (M5D((unsigned int)LCD_BUFFER>>1)+((LCD_WIDTH*32/16+0)*320))  );//LCD_WIDTH*LCD_HEIGHT*4
    rLCDSADDR3=(LCD_WIDTH*32/16)&0x7ff;//参考s3c2440的手册
    rLCDINTMSK|=(3);      // 屏蔽LCD中断
    
//rTCONSEL = 0;            //无效LPC3480
 rTCONSEL   &= (~7);
 

    rTPAL     = 0x0;
rTCONSEL 
&= ~((1<<4| 1);

    rGPGUP=rGPGUP&(~(1<<4))|(1<<4);      //GPG4上拉电阻无效
    rGPGCON=rGPGCON&(~(3<<8))|(3<<8); //设置GPG4为LCD_PWREN
    rGPGDAT = rGPGDAT | (1<<4);               //GPG4置1

    rLCDCON5
=rLCDCON5&(~(1<<3))|(1<<3);   //有效PWREN信号
    rLCDCON5=rLCDCON5&(~(1<<5))|(0<<5);   //PWREN信号极性不翻转

    rLCDCON1
|=1;                   //LCD开启
 }
//LCD显示函数//////////////////////////////////////////////////

void __irq ADCTs(void)
{
    rADCTSC 
= (1<<3)|(1<<2);         //上拉电阻无效,自动连续XY坐标转换模式开启
    rADCDLY = 40000;                    //延时

    rADCCON
|=0x1;                 //开始A/D转换

    
while(rADCCON & 0x1);         //检查A/D转换是否开始

    
while(!(rADCCON & 0x8000));   //等待A/D转换的结束

    
while(!(rSRCPND & ((unsigned int)0x1<<31)));   //判断A/D中断的悬挂位

    xdata
=(rADCDAT0&0x3ff);                //读取X轴坐标
    ydata=(rADCDAT1&0x3ff);                //读取Y轴坐标

    flagTS 
= 1;            //置标志

    rSUBSRCPND
|=0x1<<9;
    rSRCPND 
= 0x1<<31;
    rINTPND 
= 0x1<<31;         
    rINTSUBMSK
=~(0x1<<9);
    rINTMSK
=~(0x1<<31);                            //清A/D中断,开启A/D中断屏蔽
             
    rADCTSC 
=0xd3;                //再次设置等待中断模式,这一次是判断触笔的抬起

    rADCTSC
=rADCTSC|(1<<8);             //设置触笔抬起中断

    
while(1)         //等待触笔的抬起
    {
      
if(rSUBSRCPND & (0x1<<9))     //检查A/D触摸屏中断悬挂
      {
         
break;                   //如果触笔抬起,则跳出该循环
      }
    }    

    rADCDLY=50000;
    rSUBSRCPND
|=0x1<<9;        //写1清除标志
    rINTSUBMSK=~(0x1<<9);    //清0中断使能,ADC的子中断
    rSRCPND = 0x1<<31;        //写1清除标志
    rINTPND = 0x1<<31;      //再次清A/D中断,开启A/D中断屏蔽
    rADCTSC =0xd3;          //设置等待光标按下中断模式,为下一次触笔的落下做准备
                            
//01101 0011--// XP_PU, XP_Dis, XM_Dis, YP_Dis, YM_En.
}   

const unsigned char one[]={0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00};
const unsigned char two[]={0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00};
const unsigned char three[]=
{
0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00};
//用PCtoLCD2002字符生成软件

//触摸屏校正
void TSCal(void)
{
       
int i=0;
       
int xt[3],yt[3];
       Brush_Background(
0xFFFFFF);
       drawCross(
24,32,0xFF0000);        
       Draw_ASCII(
28,36,0xFF0000,one);        //----
       drawCross(216,160,0xFF0000);
       Draw_ASCII(
220,164,0xFF0000,two);    //----
       drawCross(120,288,0xFF0000);
       Draw_ASCII(
124,292,0xFF0000,three);  //----
 
       
//依次读取三个采样点的坐标值
       for(i=0;i<3;i++)
       {    
          
while(flagTS==0)
             delay(
500);
          xt[i]
=xdata;
          yt[i]
=ydata;
          flagTS
=0;             
       }
 
//计算参数
       K=(xt[0]-xt[2])*(yt[1]-yt[2])-(xt[1]-xt[2])*(yt[0]-yt[2]);
       D
=(32-288)*(yt[1]-yt[2])-(160-288)*(yt[0]-yt[2]);
       E
=(xt[0]-xt[2])*(160-288)-(32-288)*(xt[1]-xt[2]);
       F
=yt[0]*(xt[2]*160-xt[1]*288)+yt[1]*(xt[0]*288-xt[2]*32)+yt[2]*(xt[1]*32-xt[0]*160);
       A
=(24-120)*(yt[1]-yt[2])-(216-120)*(yt[0]-yt[2]);
       B
=(xt[0]-xt[2])*(216-120)-(24-120)*(xt[1]-xt[2]);
       C
=yt[0]*(xt[2]*216-xt[1]*120)+yt[1]*(xt[0]*120-xt[2]*24)+yt[2]*(xt[1]*24-xt[0]*216);
}

int Main(int argc, char **argv)
{
    
int i;
    unsigned 
char key;
    unsigned 
int mpll_val=0;
    
int data;
      
      
int xLcd,yLcd;
      
    mpll_val 
= (92<<12)|(1<<4)|(1);
    
    
//init FCLK=400M, so change MPLL first
    ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
    ChangeClockDivider(key, 
12);    

    rINTMOD=0x0;            // All=IRQ mode
    rINTMSK=BIT_ALLMSK;      // All interrupt is masked.

    MMU_Init();
    
    init_port_lcd();

    //*********************
    rADCDLY=50000;               //设置延时
    rADCCON=(1<<14)+(9<<6);      //设置A/D预分频
    rADCTSC=0xd3;                //设置cm屏为等待中断模式。
    pISR_ADC = (int)ADCTs;
    rINTMSK
=~(0x1<<31);         //开启中断
    rINTSUBMSK=~(BIT_SUB_TC);
    
    flagTS 
= 0;
       
//*********************
       
   TSCal();
//校正
   delay(200000);

    Brush_Background(0xFFFFFF);
    
    
while(1)
    {
       
if(flagTS)
       {
            flagTS
=0;
            xLcd 
= (A*xdata+B*ydata+C)/K;                //计算Y轴坐标
            yLcd = (D*xdata+E*ydata+F)/K;                //计算X轴坐标
            drawsquare(xLcd,yLcd,0xFF0000);        //绘制正方形
       }
       delay(
1000000);
    }
   
return 0;
}

//-------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------
void MMU_Init(void)//配置MMU
{
    
int i,j;
    MMU_DisableDCache();
    MMU_DisableICache();
    
    
for(i=0;i<64;i++)
        
for(j=0;j<8;j++)
            MMU_CleanInvalidateDCacheIndex((i
<<26)|(j<<5));
    
    
    MMU_InvalidateICache();
    MMU_DisableMMU();
    MMU_InvalidateTLB();
    
        MMU_SetMTT(
0x00000000,0x03f00000,0x30000000,RW_CB);  //bank0   __ENTRY的地址就是0x30000000
    MMU_SetMTT(0x04000000,0x07f00000,0,RW_NCNB);              //bank0
    MMU_SetMTT(0x08000000,0x0ff00000,0x08000000,RW_CNB);  //bank1
    MMU_SetMTT(0x10000000,0x17f00000,0x10000000,RW_NCNB); //bank2
    MMU_SetMTT(0x18000000,0x1ff00000,0x18000000,RW_NCNB); //bank3
    
//MMU_SetMTT(0x20000000,0x27f00000,0x20000000,RW_CB); //bank4
    MMU_SetMTT(0x20000000,0x27f00000,0x20000000,RW_CNB); //bank4 for STRATA Flash
    MMU_SetMTT(0x28000000,0x2ff00000,0x28000000,RW_NCNB); //bank5
    
//30f00000->30100000, 31000000->30200000
    MMU_SetMTT(0x30000000,0x30100000,0x30000000,RW_CB);      //bank6-1
    MMU_SetMTT(0x30200000,0x33e00000,0x30200000,RW_NCNB); //bank6-2
    
//
    MMU_SetMTT(0x33f00000,0x33f00000,0x33f00000,RW_CB);   //bank6-3
    MMU_SetMTT(0x38000000,0x3ff00000,0x38000000,RW_NCNB); //bank7
    
    MMU_SetMTT(
0x40000000,0x47f00000,0x40000000,RW_NCNB); //SFR
    MMU_SetMTT(0x48000000,0x5af00000,0x48000000,RW_NCNB); //SFR
    MMU_SetMTT(0x5b000000,0x5b000000,0x5b000000,RW_NCNB); //SFR
    MMU_SetMTT(0x5b100000,0xfff00000,0x5b100000,RW_FAULT);//not used

    
    MMU_SetTTBase(_MMUTT_STARTADDRESS);
//写转换表基地址到C2
    MMU_SetDomain(0x55555550|DOMAIN1_ATTR|DOMAIN0_ATTR);  //写域访问控制位到C3
        
//DOMAIN1: no_access, DOMAIN0,2~15=client(AP is checked)
    MMU_SetProcessId(0x0);
    MMU_EnableAlignFault();
        
    MMU_EnableMMU();     
//使能MMU
    MMU_EnableICache();  //使能ICache
    MMU_EnableDCache(); //DCache 必须要打开,当MMU打开时.  DCache should be turned on after MMU is turned on.

}

//vaddrStart:虚拟起始地址
//vaddrEnd:  虚拟结束地址
//paddrStart:物理起始地址
//attr:访问属性
void MMU_SetMTT(int vaddrStart,int vaddrEnd,int paddrStart,int attr)
{
    
volatile unsigned int *pTT;//定义了页表的指针
    volatile int i,nSec;
    pTT
=(unsigned int *)_MMUTT_STARTADDRESS+(vaddrStart>>20);//由于内存块是1M的,写页表的基地址
    nSec=(vaddrEnd>>20)-(vaddrStart>>20);//计数有多少个段(每个段为1M)
    for(i=0;i<=nSec;i++)
        
*pTT++=attr |(((paddrStart>>20)+i)<<20);
//页表存储访问信息和存储块的基地址
//(((paddrStart>>20)+i)<<20) :对应的物理内存页的地址
// attr:访问权限和缓冲属性
}

XDA×XTB×YTC

YDD×XTE×YTF

其中有ABCDEF六个参数, 分别解ABC和DEF,需要3组数据,那就需要采集3个校准点:
     XD0A×XT0B×YT0+C           
Y
D0D×XT0E×YT0F
  

          XD1A×XT1B×YT1+C
          YD1D×XT1E×YT1F  

         XD2A×XT2B×YT2+C          
YD2D×XT2E×YT2F
可以用矩阵方面的知识解这三元一次函数得:
D0=(XT0XT2)×(YT1YT2)(XT1XT2)×(YT0YT2);
D1=(XD0XD2)×(YT1YT2)(XD1XD2)×(YT0YT2);
D2=(XT0XT2)×(XD1XD2)(XD0XD2)×(XT1XT2);
D3=YT0×(XT2×XD1XT1×XD2)YT1×(XT0×XD2XT2×XD0)YT2×(XT1×XD0XT0×XD1);
D4=(YD0XD2)×(YT1YT2)(YD1XD2)×(YT0YT2);
D5=(XT0XT2)×(YD1YD2)(YD0YD2)×(XT1XT2);
D6=YT0×(XT2×YD1XT1×YD2)YT1×(XT0×YD2XT2×YD0)YT2×(XT1×YD0XT0×YD1);

A=D1/D0
B=D2/D0;
C=D3/D0;   
D=D4/D0;
F=D5/D0;
A=D6/D0;

程序要实现的功能是:程序一开始,界面上会出现3个十字的取样点,分别标有1、2、3,然后用触笔依次的点击,完成后,会进入第二个界面,用触笔随机的点击屏幕,会以触点绘制出边长为4的小正方形。

抱歉!评论已关闭.