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

触摸屏是通过中断来实现的。我的程序是在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            YD0D×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/D0B=D2/D0; C=D3/D0;    D=D4/D0; F=D5/D0; A=D6/D0;

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值