⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 touchpad.c

📁 msp430的触摸屏驱动
💻 C
字号:

/***************************************************************************************
****************************************************************************************
* FILE		: TouchPad.c
* Description	: 
*			  
* Copyright (c) 2003~2008 by 创易电子(Design Easy). All Rights Reserved.
* 
* History:
* Version		Name       		Date			Description
   1.0		Wang Shaowei	2008/12/17	Initial Version (For DesignEasy LCM MCU board)
   1.1		Liu Ying			2008/12/22	Comments
   1.2          zha sheng                       2009/1/12       For msp430
****************************************************************************************
****************************************************************************************/
#include "TouchPad.h"
#include "lcd.h"
/*
考虑到非校准情况下的触摸屏,通常都是写字、画画等连续的,
在我们的系统中,对于触摸功能是这样处理的:
首次触摸是由中断检测得到,之后响应中断进行处理;
处理完后开启一个5ms定时器,
定时器到时处理时主动读取触摸坐标,
     若是有效坐标则处理,处理完后同样开启一个5ms定时器
     若是无效坐标则表示没有触摸,此时再清除中断标记、
     重新打开中断响应,等待下一次触摸中断
注意不要太早打开中断,一则因为系统中断不宜太频繁,二者避免误触发

*/

typedef struct 
{
	U16 X;
	U16 Y;
}TP_POS;
/*记录在两次校准中得到的触摸坐标*/
TP_POS TPposA, TPposB;



typedef struct 
{
	U16 K;
	U16 A;
}TP_ARG;

/*坐标转化参数,从触摸获得的数值到LCD的坐标之间需要进行映射转换*/
TP_ARG TPargX, TPargY;


/*
校准说明: 
Xt = Kx * Xl + Ax
Yt = Ky * Yl + Ay

Xt: TP ADC 触摸获得的坐标
Kx: X arg
Xl: LCD pos lcd的坐标
Ax: X offset

Yt: TP ADC 触摸获得的坐标
Ky: Y arg
Yl: LCD pos lcd的坐标
Ay: Y offset

lcd和触摸屏的坐标之间的转换就是上面这两个公式,
用于校准,(从两组Xl Yl Xt Yt求出Kx Ky Ax Ay)
也用于转化得到lcd的坐标(从Xt Yt Kx Ky Ax Ay求出Xl Yl )
*/
/*==================================================================
* Function	: tp_pos_adjust
* Description	: 校准屏幕
* Input Para	: void               屏幕上的校准坐标由宏定义TP_ADJUEST_POS_X1,
                       TP_ADJUEST_POS_Y1,TP_ADJUEST_POS_X2,TP_ADJUEST_POS_Y2
                       步骤为:1,画第一个点推出。校准标记置1;
                               2,由中断调用触发第一个点,同时清除第一个点画第二个点。点数标记为1;
                               3,中断调用得第二个点坐标,同时清除第二个点的显示,复位标记
                                注意:  每次推出开中断。
* Output Para	: void
* Return Value  : unsigned char 是否错误 (获得TPargX, TPargY)
===================================================================*/
U8 tp_pos_adjust(void)
{
    if((!bTP_adjust)&&(!bTP_adjust_count))
    {    
         TP_INT_CLOSE;
         bTP_adjust = true;
         lcd_display_adjust(TP_ADJUEST_POS_X1,TP_ADJUEST_POS_Y1);//调用绘图函数,在屏幕上绘制校准用图形。
         TP_INT_OPEN;
         return 0;
    }
    else if(!bTP_adjust_count)
    {    
         TPposA.X = TP_X;
         TPposA.Y = TP_Y;
         lcd_display_rectangle_color(TP_ADJUEST_POS_X1-3, TP_ADJUEST_POS_Y1-3,TP_ADJUEST_POS_X1+3,TP_ADJUEST_POS_Y1+3,0xFFFF);
         delay_ms(50000);//使操作延时
         delay_ms(50000);
         delay_ms(50000);
         delay_ms(50000);
         delay_ms(50000);
         lcd_display_adjust(TP_ADJUEST_POS_X2,TP_ADJUEST_POS_Y2);
         delay_ms(50000);
         bTP_adjust_count = true;
         TP_INT_OPEN;
         return 0;
    }
    else 
    {
        TPposB.X = TP_X;
        TPposB.Y = TP_Y;    
         /*坐标转换函数*/
        TPargX.K = (TPposA.X - TPposB.X) / (TP_ADJUEST_POS_X2-TP_ADJUEST_POS_X1);
        TPargY.K = (TPposA.Y - TPposB.Y) / (TP_ADJUEST_POS_Y2-TP_ADJUEST_POS_Y1);
        TPargX.A = TPposB.X -(TPargX.K * ((TP_ADJUEST_POS_X2-TP_ADJUEST_POS_X1)/2)); 
        TPargY.A = TPposB.Y -(TPargY.K * ((TP_ADJUEST_POS_Y2-TP_ADJUEST_POS_Y1)/2));
        lcd_display_rectangle_color(TP_ADJUEST_POS_X2-3, TP_ADJUEST_POS_Y2-3,TP_ADJUEST_POS_X2+3,TP_ADJUEST_POS_Y2+3,0xFFFF);
        bTP_adjust_count = false;
        bTP_adjust = false;
        TP_INT_OPEN;
        return 0;
    }
  
}
/*==================================================================
* Function	: tp_pos_display
* Description	: 获得触摸轨迹,或其他图形
* Input Para	: void
* Output Para	: void
* Return Value: void
==================================================================*/
void tp_pos_display(void)
{
  //画点
  lcd_display_dot( TP_end_x,  TP_end_y);
  return;
}
/*==================================================================
* Function	: serial_write_bit_high
* Description	: 写bit1,TP_nCS 之前已经拉低
* Input Para	: void
* Output Para	: void
* Return Value: void
==================================================================*/
void serial_write_bit_high(void)
{

   	TP_DIN_set;//拉高
   
   	TP_DCLK_cle;  //模拟一个时钟脉冲,所存数据     
   	TP_DCLK_set;
   	TP_DCLK_cle;

	return;
}


/*==================================================================
* Function	: serial_write_bit_low
* Description	: 写bit0,TP_nCS 之前已经拉低
* Input Para	: void
* Output Para	: void
* Return Value: void
==================================================================*/
void serial_write_bit_low(void)
{
   	TP_DIN_cle;  
   
   	TP_DCLK_cle;          
   	TP_DCLK_set;
   	TP_DCLK_cle;   

	return;
}


/* 
关于TP_nCS何时置1何时置0的说明:
因为对触摸屏控制电路的控制,都是先写命令、然后读数据的,
所以下面的serial_write_data、serial_read_data总是成对出现,
我们总是在serial_write_data开始时将TP_nCS置0,
在serial_read_data结束时将TP_nCS置1,
这部分请看触摸控制电路芯片时序图
*/


/*==================================================================
* Function	: serial_write_bit_low
* Description	: 写8bit字节,开始将TP_nCS置0
* Input Para	: U8 SendData
* Output Para	: void
* Return Value: void
==================================================================*/
void serial_write_data(U8 SendData)
{
   	U8 i,c=0x80;
	
	TP_DCLK_cle;
	TP_nCS_cle;

	/*从bit7到bit0依次传送*/
	for (i=8; i>0; i--)
	{
		if (SendData & c)
		{
		   serial_write_bit_high();
		}
		else
		{
		   serial_write_bit_low();
		}
                c>>=1;
	}
	
   	TP_DIN_cle;

	return;
}



/*==================================================================
* Function	: serial_read_data
* Description	: 读12bit数据,TP_nCS 之前已经置零,结束时需将TP_nCS置1
* Input Para	: void
* Output Para	: void
* Return Value: U16 读到的数据,只有12bit有效
==================================================================*/
U16 serial_read_data(void)
{ 
	U8 i;
        U16 c=0x800;  
   	U16 RcvData=0; 
        unsigned long int retry=0;	
	
   	TP_DCLK_cle; 
   	TP_DCLK_set; 

	/*等待一段时间*/
	while(TP_nBUSY)
   	{

 	   	TP_DCLK_cle; 
   		TP_DCLK_set; 
   		retry++;
   		if(retry>100)
   		{
   			return 0;
   		}
   	};
	
   	for(i=12; i>0; i--)
   	{
      	      TP_DCLK_set;
		if(TP_DOUT)
		{
			RcvData |= c; 
		}
              c>>=1;
	      TP_DCLK_cle; 
   	}
	
	TP_nCS_set;
	
   	return(RcvData);
}



/*==================================================================
* Function	: tp_init
* Description	: 初始化tp
* Input Para	: void
* Output Para	: void
* Return Value: void
==================================================================*/
void tp_init(void)
{
	U8 cmd = 0;
        /*初始化常数值*/
        bTP_INT = false;
        bTP_adjust = false;
        bTP_adjust_count = false;
        bTP_touch= false;
	/*在校准之前也可以使用触摸屏,用这一组默认参数。
	校准之后用校准得到的参数*/
	TPargX.K = TOUCH_PANEL_ARG_X_K;
	TPargX.A = TOUCH_PANEL_ARG_X_A;	
	TPargY.K = TOUCH_PANEL_ARG_Y_K;
	TPargY.A = TOUCH_PANEL_ARG_Y_A;

	/*送初始化命令*/
   	cmd=TOUCH_PANEL_START_BIT|TOUCH_PANEL_Y_PLUS|TOUCH_PANEL_12BIT_SAMPLE| TOUCH_PANEL_DIFF_MODE;
   	serial_write_data(cmd);
	serial_read_data();

	return;
}



/*==================================================================
* Function	: tp_read_adc
* Description	: 得到触摸坐标
* Input Para	: U16 * X, U16 * Y,若全为0表示获得坐标不成功
* Output Para	: void
* Return Value: void
==================================================================*/
void tp_read_adc(U16 * X, U16 * Y)
{
	U8 cmd = 0;
	
   /*读取X 坐标X ADC*/
	cmd=TOUCH_PANEL_START_BIT|TOUCH_PANEL_Y_PLUS|TOUCH_PANEL_12BIT_SAMPLE| TOUCH_PANEL_DIFF_MODE;
   	serial_write_data(cmd);
	*X=serial_read_data();
        TP_to_LED_x=(*X - TPargX.A) / TPargX.K;
	
	cmd = 0;
   /*读取Y 坐标Y ADC*/
   	cmd=TOUCH_PANEL_START_BIT|TOUCH_PANEL_X_PLUS|TOUCH_PANEL_12BIT_SAMPLE| TOUCH_PANEL_DIFF_MODE ;
   	serial_write_data(cmd);
	*Y=serial_read_data();
        

	/*坐标转化*/
	/*触摸屏和LCD屏幕的原点不同,一个在左下,一个在左上,需要将Y坐标转化一下*/
	*Y = 4096 - *Y;
        TP_to_LED_y=(*Y - TPargY.A) / TPargY.K;
	/*触摸屏的范围大于LCD屏幕范围,判断是否超出了四周的边框*/
	/*if(*X < 0x0080 || *Y < 0x0080 || *X > 0xF80 || *Y > 0xF80)
	{
		*X = 0;
		*Y = 0;
     //           check_err();///////////////////////////////for test
	}
    //    lcd_display_full_screen_color(0xffff);
        U16 test1,test2;
        U8 temp,a,b,c,d;
        test1 = *X;test2 = *Y;
        temp = test1&0x00ff;;
        a=temp & 0x0f;
        if(a>=10)
          a=a+'A';
        else
          a=a+'0';
        b=temp>>4;
        if(b>=10)
          b=b+'A';
        else
          b=b+'0';
        temp=test1>>8;
        c=temp & 0x0f;
         if(c>=10)
          c=c+'A';
        else
          c=c+'0';
        d=temp>>4;
        if(d>=10)
          d=d+'A';
        else
          d=d+'0';
        lcd_show_text(50,50,&a,0xFFFF,0x0000);
        lcd_show_text(70,50,&b,0xFFFF,0x0000);
        lcd_show_text(90,50,&c,0xFFFF,0x0000);
        lcd_show_text(110,50,&d,0xFFFF,0x0000);
        temp = test2;
        a=temp & 0x0f;
        if(a>=10)
          a=a+'A';
        else
          a=a+'0';
        b=temp>>4;
        if(b>=10)
          b=b+'A';
        else
          b=b+'0';
        temp=test2>>8;
        c=temp & 0x0f;
         if(c>=10)
          c=c+'A';
        else
          c=c+'0';
        d=temp>>4;
        if(d>=10)
          d=d+'A';
        else
          d=d+'0';
        lcd_show_text(50,80,&a,0xFFFF,0x0000);
        lcd_show_text(70,80,&b,0xFFFF,0x0000);
        lcd_show_text(90,80,&c,0xFFFF,0x0000);
        lcd_show_text(110,80,&d,0xFFFF,0x0000);*/
	return;
}
/*==================================================================
* Function	: tp_pos_task
* Description	: 处理由中断出发的触摸屏操作,区别是校验还是触摸操作,
                  由触摸屏中断调用,调用前请关闭中断,调用后请开中断
* Input Para	: U16 * X, U16 * Y,若全为0表示获得坐标不成功
* Output Para	: void
* Return Value: void
==================================================================*/
void tp_pos_task(void)
{
    if(bTP_INT)//中断调用
    {
      /*一笔的起点,坐标从中断中获得*/
      bTP_INT = false; 
      bTP_touch = true;//触摸中
      TP_end_x=TP_start_x=TP_to_LED_x;
      TP_end_y=TP_start_y=TP_to_LED_y;//记录开始坐标,初始化结束坐标
  //    if(TP_drawenable_start_x<=TP_end_x||TP_drawenable_start_y<=TP_end_y||TP_drawenable_end_x>=TP_end_x||TP_drawenable_end_y>=TP_end_y)
  //       tp_pos_display();             
     // 调用timer 5ms;
      delay_ms(500);     
      tp_pos_task();      
      //TP_INT_OPEN;
      return;
    } 
    else
    {
      tp_read_adc(&TP_X, &TP_Y);
      if(TP_X > 0)
      {
        signed char temp1,temp2;      
        temp1 = TP_to_LED_x-TP_end_x;//相邻点坐标的绝对值
        temp2 = TP_to_LED_y-TP_end_y;
        if(temp1<0)
          temp1=-temp1;
        if(temp2<0)
          temp2=-temp2;
        if(temp1<3&&temp2<3)//消除噪点
        {
           
           if(TP_drawenable_start_x<=TP_end_x&&TP_drawenable_start_y<=TP_end_y&&TP_drawenable_end_x>=TP_end_x&&TP_drawenable_end_y>=TP_end_y)
              tp_pos_display();
           delay_ms(500);  
        }
         TP_end_x=TP_to_LED_x;//记录当前坐标为结束坐标 
         TP_end_y=TP_to_LED_y;
         //调用timer 5ms;
              
         tp_pos_task();
        return;
      }
      else
      {
        /*没有读到有效的坐标,一笔结束,重新打开中断*/
        bTP_touch = false;//触摸结束
        TP_INT_OPEN;
        return;
      }
      
    }
    
}
/*==================================================================
* Function	: xx
* Description	: MSp430中断函数,捕捉触摸屏操作。
* Input Para	: void
* Output Para	: void
* Return Value  : void
==================================================================*/
#pragma vector = PORT2_VECTOR
__interrupt void Port_2(void)
{  
  TP_INT_CLOSE;// 禁止中断   
//  P2IFG &= 0xFB;//清除中断标志寄存器
  tp_read_adc(&TP_X,&TP_Y);
  
  bTP_INT = true;
//  check_err();
  if(bTP_adjust)
     tp_pos_adjust();
  else
     tp_pos_task();
  P2IFG = 0x00;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -