最近因为项目需要,需要在STM32平台上(裸机)驱动电容触摸屏,触摸屏控制IC为FT6206,触摸屏供应商只提供了Linux的驱动代码,看得一头雾水,只好自己写。

      网上搜索相关资料,好不容易才搜索到一份敦泰的调屏资料,上面写是0x70,抱着试一下的心态,试了一下,没想到还真的是这个地址,心中窃喜,接下来就简单,读坐标点数据就行了。但碰到一个问题是,资料上写着是支持手势的,但我怎么按屏幕,从手势寄存器中读出来的都是0x00,表示没有手势 ,但坐标点数据读出来都是正确的,心中那个郁闷啊,不过我的项目用不上手势,就不管它了,如果有人知道是为什么,还请多多指点。

    还有一个地方需要注意的,就是上电后需要给芯片一个唤醒信号,该信号主机可以通过触摸屏的INT或者RST引脚提供。

    好了,直接上代码:

这个是.h文件

#ifndef __TOUCH_H
#define __TOUCH_H

#ifdef   MY_TOUCH_GLOBALS
#define  MY_TOUCH_EXT
#else
#define  MY_TOUCH_EXT  extern
#endif

/**************************引脚配置********************************/
#define CT_SDA_PIN              GPIO_Pin_15
#define CT_SCL_PIN              GPIO_Pin_14
#define CT_RST_PIN              GPIO_Pin_13
#define CT_INT_PIN              GPIO_Pin_12

#define RCC_CT_I2C_PORT            RCC_APB2Periph_GPIOF
#define RCC_CT_CONTROL_PORT        RCC_APB2Periph_GPIOF
#define CT_CONTROL_PORT            GPIOF
#define CT_I2C_PORT                GPIOF

#define TOUCH_GPIO_PortSource   GPIO_PortSourceGPIOF
#define TOUCH_GPIO_PinSource    GPIO_PinSource12
#define TOUCH_EXTI_Line         EXTI_Line12
#define TOUCH_EXTI_IRQn         EXTI15_10_IRQn
/***************************相关宏定义********************************/
#define TOUCH_NO_POINT          (~0)

/************************错误代码*****************************/
#define CT_COM_OK               (0)
#define CT_ACK_FAIL             (1)

#define FT6X06_ID               (0x6206)
#define CT_IC                   (FT6X06_ID)              //使用的控制IC
#define CT_ADDR                 (0x70)                  //器件地址
#define CT_WRITE_MASK           (0x00)
#define CT_READ_MASK            (0x01)

#define CT_CACK_TIMEOUT         (3000)                  //等待ACK超时时间
//reg map
#define DEVICE_MODE             (0x00)                  //This register is the device mode register, configure it to determine the current mode of the chip
#define GEST_ID                 (0x01)                  //This register describes the gesture of a valid touch
#define TD_STATUS               (0x02)                  //How many points detected
#define P1_XH                   (0x03)                  //This register describes MSB of the X coordinate of the nth touch point and the corresponding event flag
#define P1_XL                   (0x04)                  //This register describes LSB of the X coordinate of the nth touch point
#define P1_YH                   (0x05)                  //This register describes MSB of the Y coordinate of the nth touch point and corresponding touch ID
#define P1_YL                   (0x06)                  //This register describes LSB of the Y coordinate of the nth touch point
#define P2_XH                   (0x09)                  
#define P2_XL                   (0x0A)                  
#define P2_YH                   (0x0B)                  
#define P2_YL                   (0x0C) 
#define ID_G_THGROUP            (0x80)                  //灵敏度
#define ID_G_PERIODACTIVE       (0x88)                  //扫描频率,This register describes the period of active status, it should not less than 12,最大14      
#define ID_G_AUTO_CLB_MODE      (0xA0)                  //This register describes auto calibration mode
#define G_MODE                  (0xA4)
#define ID_G_STATE              (0xA7)                  //This register is used to configure the run mode of TPM.
#define ID_G_FTID               (0xA8)                  //芯片ID
#define ID_G_ERR                (0xA9)                  //This register describes the error code when the TPM is running      

/*********************相关结构体*************************/
#if (CT_IC == FT6X06_ID)
    #define MAX_TOUCH_POINT     (2)                     //最大触摸点个数
#endif
#ifndef MAX_TOUCH_POINT
    #define MAX_TOUCH_POINT     (2)
#endif

//触摸点事件
#define EVENT_PRESS_DOWN        (0) 
#define EVENT_LIFT_UP           (1)
#define EVENT_CONTACT           (2)
#define EVENT_NONE              (3)
//手势
#define GUSTURE_MOVE_UP         (0x10)
#define GUSTURE_MOVE_RIGHT      (0x14)
#define GUSTURE_MOVE_DOWN       (0x18)
#define GUSTURE_MOVE_LEFT       (0x1C)
#define GUSTURE_MOVE_ZOOM_IN    (0x48)
#define GUSTURE_MOVE_ZOOM_OUT   (0x49)
#define GUSTURE_NONE            (0x00)

#define CT_READ_START           (GEST_ID)               //每次检测到触摸屏中断信号时从哪个寄存器开始读取数据
#define CT_READ_LENGTH          (12)                    //每次检测到触摸屏中断信号时读取多少个数据
#define CT_READ_NO_GEST         (0)                     //手势在读出数据的位置
#define CT_READ_NO_TD_STATUS    (CT_READ_NO_GEST+1)     //有效点数
#define CT_READ_NO_P1           (CT_READ_NO_TD_STATUS+1)
#define CT_READ_NO_P2           (CT_READ_NO_P1+6)

#define CT_DEF_VALID_POINT_ERROR (10)

typedef struct
{   
    uint8_t M_EventFlag;        //触摸点事件
    uint16_t M_Xpos;
    uint16_t M_Ypos;
    uint16_t M_PreXpos;         //上一次的点位置
    uint16_t M_PreYpos;
}ST_CTPoint;

typedef struct
{
    uint8_t M_nPoint;           //当前有效,触摸点个数,对于FT6X06最多两个
    uint8_t M_Gesture;          //手势             
    ST_CTPoint * M_pStCTPoint[MAX_TOUCH_POINT]; 
}ST_CTTouchStatus;

typedef struct
{
    uint16_t M_ValidStartXpos;      //X有效起始位置
    uint16_t M_ValidEndXpos;        //X有效结束位置
    uint16_t M_ValidStartYpos;      //Y有效起始位置
    uint16_t M_ValidEndYpos;        //Y有效结束位置
    uint8_t M_ValidErrRange;        //容许偏差
}ST_ValidPoint;

MY_TOUCH_EXT ST_CTPoint StCTPoint1;
MY_TOUCH_EXT ST_CTPoint StCTPoint2;
MY_TOUCH_EXT ST_CTTouchStatus StCTTouchStatus;
MY_TOUCH_EXT uint8_t FlagCTINT;                 //触摸中断标志
MY_TOUCH_EXT uint8_t FlagPointToDeal;           //是否有点有效标志

/* 
**函数名:CTI2C_GPIO_Config
**传入参数:无
**返回值:无
**功能:初始化CTI2C引脚
*/  
void CTI2C_GPIO_Config(void);

uint8_t CT_Write_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,const uint8_t *s);
uint8_t CT_Read_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,uint8_t *s);
void CT_Reset(void);
void CT_Init_Val(void);
uint8_t CT_GetTouch_Status(uint8_t *RetPointToDealFlag);

#endif
#ifndef __TOUCH_H
#define __TOUCH_H

#ifdef   MY_TOUCH_GLOBALS
#define  MY_TOUCH_EXT
#else
#define  MY_TOUCH_EXT  extern
#endif

/**************************引脚配置********************************/
#define CT_SDA_PIN              GPIO_Pin_15
#define CT_SCL_PIN              GPIO_Pin_14
#define CT_RST_PIN              GPIO_Pin_13
#define CT_INT_PIN              GPIO_Pin_12

#define RCC_CT_I2C_PORT            RCC_APB2Periph_GPIOF
#define RCC_CT_CONTROL_PORT        RCC_APB2Periph_GPIOF
#define CT_CONTROL_PORT            GPIOF
#define CT_I2C_PORT                GPIOF

#define TOUCH_GPIO_PortSource   GPIO_PortSourceGPIOF
#define TOUCH_GPIO_PinSource    GPIO_PinSource12
#define TOUCH_EXTI_Line         EXTI_Line12
#define TOUCH_EXTI_IRQn         EXTI15_10_IRQn
/***************************相关宏定义********************************/
#define TOUCH_NO_POINT          (~0)

/************************错误代码*****************************/
#define CT_COM_OK               (0)
#define CT_ACK_FAIL             (1)

#define FT6X06_ID               (0x6206)
#define CT_IC                   (FT6X06_ID)              //使用的控制IC
#define CT_ADDR                 (0x70)                  //器件地址
#define CT_WRITE_MASK           (0x00)
#define CT_READ_MASK            (0x01)

#define CT_CACK_TIMEOUT         (3000)                  //等待ACK超时时间
//reg map
#define DEVICE_MODE             (0x00)                  //This register is the device mode register, configure it to determine the current mode of the chip
#define GEST_ID                 (0x01)                  //This register describes the gesture of a valid touch
#define TD_STATUS               (0x02)                  //How many points detected
#define P1_XH                   (0x03)                  //This register describes MSB of the X coordinate of the nth touch point and the corresponding event flag
#define P1_XL                   (0x04)                  //This register describes LSB of the X coordinate of the nth touch point
#define P1_YH                   (0x05)                  //This register describes MSB of the Y coordinate of the nth touch point and corresponding touch ID
#define P1_YL                   (0x06)                  //This register describes LSB of the Y coordinate of the nth touch point
#define P2_XH                   (0x09)                  
#define P2_XL                   (0x0A)                  
#define P2_YH                   (0x0B)                  
#define P2_YL                   (0x0C) 
#define ID_G_THGROUP            (0x80)                  //灵敏度
#define ID_G_PERIODACTIVE       (0x88)                  //扫描频率,This register describes the period of active status, it should not less than 12,最大14      
#define ID_G_AUTO_CLB_MODE      (0xA0)                  //This register describes auto calibration mode
#define G_MODE                  (0xA4)
#define ID_G_STATE              (0xA7)                  //This register is used to configure the run mode of TPM.
#define ID_G_FTID               (0xA8)                  //芯片ID
#define ID_G_ERR                (0xA9)                  //This register describes the error code when the TPM is running      

/*********************相关结构体*************************/
#if (CT_IC == FT6X06_ID)
    #define MAX_TOUCH_POINT     (2)                     //最大触摸点个数
#endif
#ifndef MAX_TOUCH_POINT
    #define MAX_TOUCH_POINT     (2)
#endif

//触摸点事件
#define EVENT_PRESS_DOWN        (0) 
#define EVENT_LIFT_UP           (1)
#define EVENT_CONTACT           (2)
#define EVENT_NONE              (3)
//手势
#define GUSTURE_MOVE_UP         (0x10)
#define GUSTURE_MOVE_RIGHT      (0x14)
#define GUSTURE_MOVE_DOWN       (0x18)
#define GUSTURE_MOVE_LEFT       (0x1C)
#define GUSTURE_MOVE_ZOOM_IN    (0x48)
#define GUSTURE_MOVE_ZOOM_OUT   (0x49)
#define GUSTURE_NONE            (0x00)

#define CT_READ_START           (GEST_ID)               //每次检测到触摸屏中断信号时从哪个寄存器开始读取数据
#define CT_READ_LENGTH          (12)                    //每次检测到触摸屏中断信号时读取多少个数据
#define CT_READ_NO_GEST         (0)                     //手势在读出数据的位置
#define CT_READ_NO_TD_STATUS    (CT_READ_NO_GEST+1)     //有效点数
#define CT_READ_NO_P1           (CT_READ_NO_TD_STATUS+1)
#define CT_READ_NO_P2           (CT_READ_NO_P1+6)

#define CT_DEF_VALID_POINT_ERROR (10)

typedef struct
{   
    uint8_t M_EventFlag;        //触摸点事件
    uint16_t M_Xpos;
    uint16_t M_Ypos;
    uint16_t M_PreXpos;         //上一次的点位置
    uint16_t M_PreYpos;
}ST_CTPoint;

typedef struct
{
    uint8_t M_nPoint;           //当前有效,触摸点个数,对于FT6X06最多两个
    uint8_t M_Gesture;          //手势             
    ST_CTPoint * M_pStCTPoint[MAX_TOUCH_POINT]; 
}ST_CTTouchStatus;

typedef struct
{
    uint16_t M_ValidStartXpos;      //X有效起始位置
    uint16_t M_ValidEndXpos;        //X有效结束位置
    uint16_t M_ValidStartYpos;      //Y有效起始位置
    uint16_t M_ValidEndYpos;        //Y有效结束位置
    uint8_t M_ValidErrRange;        //容许偏差
}ST_ValidPoint;

MY_TOUCH_EXT ST_CTPoint StCTPoint1;
MY_TOUCH_EXT ST_CTPoint StCTPoint2;
MY_TOUCH_EXT ST_CTTouchStatus StCTTouchStatus;
MY_TOUCH_EXT uint8_t FlagCTINT;                 //触摸中断标志
MY_TOUCH_EXT uint8_t FlagPointToDeal;           //是否有点有效标志

/* 
**函数名:CTI2C_GPIO_Config
**传入参数:无
**返回值:无
**功能:初始化CTI2C引脚
*/  
void CTI2C_GPIO_Config(void);

uint8_t CT_Write_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,const uint8_t *s);
uint8_t CT_Read_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,uint8_t *s);
void CT_Reset(void);
void CT_Init_Val(void);
uint8_t CT_GetTouch_Status(uint8_t *RetPointToDealFlag);

#endif


这个是.c文件

#define   MY_TOUCH_GLOBALS

#include ".././includes.h"

#define        SDA_High                    GPIO_WriteBit(CT_I2C_PORT,CT_SDA_PIN,Bit_SET)
#define        SDA_Low                          GPIO_WriteBit(CT_I2C_PORT,CT_SDA_PIN,Bit_RESET)
#define     SDA_INPUT                   {CT_I2C_PORT->CRH&=0X0FFFFFFF;CT_I2C_PORT->CRH|= 8ul<<28;}//第15脚,(15-8)*4 = 28
#define     SDA_OUTPUT                  {CT_I2C_PORT->CRH&=0X0FFFFFFF;CT_I2C_PORT->CRH|= 3ul<<28;}//第15脚,(15-8)*4 = 28
#define        SCL_High                    GPIO_WriteBit(CT_I2C_PORT,CT_SCL_PIN,Bit_SET)
#define        SCL_Low                          GPIO_WriteBit(CT_I2C_PORT,CT_SCL_PIN,Bit_RESET)
#define        GetSDABit                    GPIO_ReadInputDataBit(CT_I2C_PORT,CT_SDA_PIN)

#define     CT_DELAY_US(val)            Delay_us(val)
/* 
**函数名:CTI2C_GPIO_Config
**传入参数:无
**返回值:无
**功能:初始化CTI2C引脚
*/  
void CTI2C_GPIO_Config(void)
{
    /*定义一个GPIO_InitTypeDef类型的结构体*/   
    GPIO_InitTypeDef GPIO_InitStructure; 
    EXTI_InitTypeDef    EXTI_InitStructure; 
    
    /*开启GPIO的外设时钟*/   
    RCC_APB2PeriphClockCmd(RCC_CT_I2C_PORT | RCC_CT_CONTROL_PORT, ENABLE); 
          
    /*选择要控制的引脚*/                                                                  
    GPIO_InitStructure.GPIO_Pin = CT_SDA_PIN | CT_SCL_PIN;        
    /*设置引脚模式为通用推挽输出*/   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            
    /*设置引脚速率为10MHz */       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_I2C_PORT,&GPIO_InitStructure); 

    /*选择要控制的引脚*/                                                                  
    GPIO_InitStructure.GPIO_Pin = CT_RST_PIN;        
    /*设置引脚模式为通用推挽输出*/   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            
    /*设置引脚速率为10MHz */       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_CONTROL_PORT,&GPIO_InitStructure); 
    
    /*选择要控制的引脚*/                                                                  
    GPIO_InitStructure.GPIO_Pin = CT_INT_PIN;        
    /*设置引脚模式为通用推挽输出*/   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;            
    /*设置引脚速率为10MHz */       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_CONTROL_PORT,&GPIO_InitStructure); 

    /*********************初始化外部中断**********************/    
    /*开启引脚复用AFIO的外设时钟,因为用到了AFIO外部中断配置寄存器*/   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE); 
    /* Selects as EXTI Line */ 
    GPIO_EXTILineConfig(TOUCH_GPIO_PortSource, TOUCH_GPIO_PinSource);
    /*选择外部中断线*/ 
    EXTI_InitStructure.EXTI_Line = TOUCH_EXTI_Line; 
    /*设置EXTI线路为中断请求*/
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /*下降沿触发*/        
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    /*使能选中线路*/        
    EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
    /*外部中断初始化*/
    EXTI_Init(&EXTI_InitStructure);
/******************************************************/
}
/**************************/
static void CTI2C_start(void)//CTI2C启动函数
{
    SDA_OUTPUT;
    SCL_High;
    SDA_High;
     CT_DELAY_US(300);
    SDA_Low;
    CT_DELAY_US(300);
    SCL_Low;
}

/**************************/
static void CTI2C_stop(void)// CTI2C停止函数
{
    SDA_OUTPUT;
    SDA_Low;
    SCL_High;
    CT_DELAY_US(300);
    SDA_High;
    CT_DELAY_US(300);
    SDA_Low;
    SCL_Low;
}

/**************************/
static void CTI2C_write_byte(const uint8_t s)//CTI2C写1byte函数,S为需要写的内容
{
      uint8_t temps;
      uint8_t dat,i;
      temps=s;
      dat=0x80;
      SDA_OUTPUT;
      for(i=0;i<8;i++)
      {
        if(dat&temps)//对应位为一就发一 
         {
             SDA_High;
            CT_DELAY_US(100);//延时一下,保证数据建立时间大于50ns
            //SCL的频率,高速为400KHz,标准为100KHz
            SCL_High;
            CT_DELAY_US(300);
            SCL_Low;
            CT_DELAY_US(300);
         }
         else
         {
             SDA_Low;
            CT_DELAY_US(100);//延时一下,保证数据建立时间大于50ns
            SCL_High;
            CT_DELAY_US(300);
            SCL_Low;
            CT_DELAY_US(300);
         }
         dat=dat>>1;//注意Keil中将有符号数的右移操作作算术右移处理,我需要的是逻辑右移,因此dat要先定义为无符号数,否则会出错
      }
    SDA_High;//主控制器写完后要预先释放对SDA总线的控制
    CT_DELAY_US(100);//留一点时间接收应答信号
}

/**************************/
static void CTI2C_read_byte(uint8_t *s)//CTI2C读1byte函数,数据放在形参中,成功返回1,失败返回0
{
     uint8_t temps=0,i;
     uint8_t text=0x80;
     uint8_t sdain;
     SDA_INPUT;
     SDA_High;//设SDA为输入方式
     for(i=0;i<8;i++)
     {
          SCL_High;//使SDA上的数据有效
         CT_DELAY_US(100);//延时一下,保证SDA已经稳定
         sdain = GetSDABit;//取得SDA上的数据
         if(1==sdain)
         {
             temps |=(text>>i);//先接收高位
         }
         SCL_Low;//读完后允许SDA上的数据刷新,并延时一下让被读器件有时间更新要输出的数据
         CT_DELAY_US(300);
     }
     *s=temps;
     CT_DELAY_US(300);//留一点时间发送应答信号
}
/**************************/
static uint8_t CTI2C_check_ack(void)//CTI2C应答位检查函数,正常应答返回0,否则返回1
{
    uint8_t sdain;
    SDA_INPUT;
    SDA_High;//置SDA为输入
    SCL_High;//使SDA上的数据有效
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    sdain = GetSDABit;//取得SDA上的数据
    SCL_Low;
    if(1==sdain)
        return 1;
    else
        return 0;    
}

/**************************/
static void CTI2C_send_ack(void)//CTI2C发送应答信号函数
{
    SDA_OUTPUT;
    SDA_Low;
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    SCL_High;
    CT_DELAY_US(300);
    SCL_Low;
    SDA_High;

}
/**************************/
static void CTI2C_send_nack(void)//CTI2C发送非应答信号函数
{
    SDA_OUTPUT;
    SDA_High;
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    SCL_High;
    CT_DELAY_US(300);
    SCL_Low;
    SDA_Low;
}
/**************************/

/******************************************************************************
 * FUNCTION: CT_Write_Nbyte ( )
 * DESCRIPTION: 写触摸屏寄存器
 *    Input the description of function: 
 * Input Parameters: 器件地址,待写寄存器地址,待写数据数量,存储待写入数据的地址
 * Output Parameters: 无
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Write_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,const uint8_t *s)//CTI2C写nbyte函数,写数据由形参数组传入,成功返回1,失败返回0
{
    uint8_t temps,ack=1;
    uint16_t tempn;
    uint16_t cack_time=0;
    CTI2C_start();//启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_WRITE_MASK);//发送寻址字节
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    CTI2C_write_byte(add);//发送要写入的起始地址
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    for(tempn=0;tempn<n;tempn++)
    {
        ack=1;//应答位
        cack_time=0;
        temps=*(s+tempn);
        while(ack)
        {
            CTI2C_write_byte(temps);
            ack=CTI2C_check_ack();//检查应答信号,非应答则重发该字节
            cack_time++;
            if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
                   return CT_ACK_FAIL;
        }
    }
    CTI2C_stop();// CTI2C停止
    return CT_COM_OK;
}

/******************************************************************************
 * FUNCTION: CT_Read_Nbyte ( )
 * DESCRIPTION: 从触摸屏中读出数据
 *    Input the description of function: 
 * Input Parameters: 器件地址,待读寄存器地址,待读数据数量,存储待读出数据的地址
 * Output Parameters: 读取的数据
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Read_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,uint8_t *s)//CTI2C读nbyte函数,所读数据放在形参数组中(由程序员设置合适的数组大小),成功返回1,失败返回0
{
    uint8_t temps;
    uint16_t tempn;
    uint16_t cack_time=0;
    CTI2C_start();//启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_WRITE_MASK);//发送寻址字节,伪写
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    CTI2C_write_byte(add);//发送要读入的起始地址
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    CTI2C_start();//再次启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_READ_MASK);//再次发送寻址字节,读
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    for(tempn=0;tempn<n;tempn++)
    {
        CTI2C_read_byte(&temps);
        *(s+tempn)=temps;
        if(tempn+1<n)//如果已经读完所有数据了,就不要发应答信号,直接发非应答位和停止位
            CTI2C_send_ack();//CTI2C发送应答信号.准备下一字节的接收
    }
    CTI2C_send_nack();//接收完毕,发送非应答位和停止位
    CTI2C_stop();
    return CT_COM_OK;
}


//复位触摸芯片
void CT_Reset(void)
{
    //The reset signal from host to CTPM, active low, and the low pulse width should be more than or equal to 1ms
    GPIO_SetBits(CT_CONTROL_PORT,CT_RST_PIN);
    Delay_ms(1);
    GPIO_ResetBits(CT_CONTROL_PORT,CT_RST_PIN);
    Delay_ms(5);
    GPIO_SetBits(CT_CONTROL_PORT,CT_RST_PIN);
    Delay_ms(1);
}

/******************************************************************************
 * FUNCTION: CT_Init_Val ( )
 * DESCRIPTION: 初始化触摸芯片相关变量
 *    Input the description of function: 
 * Input Parameters: 
 * Output Parameters: 
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
void CT_Init_Val(void)
{
    FlagCTINT = RESET;
    FlagPointToDeal = RESET;
    
    StCTPoint1.M_EventFlag = EVENT_NONE;
    StCTPoint2.M_EventFlag = EVENT_NONE;

    StCTTouchStatus.M_Gesture = GUSTURE_NONE;
    StCTTouchStatus.M_nPoint = 0;
    StCTTouchStatus.M_pStCTPoint[0] = &StCTPoint1;
    StCTTouchStatus.M_pStCTPoint[1] = &StCTPoint2;
}


/******************************************************************************
 * FUNCTION: CT_GetTouch_Status ( )
 * DESCRIPTION: 获取当前触摸状态,保存在ST_CTTouchStatus中
 *    Input the description of function: 
 * Input Parameters: 
 * Output Parameters: 是否有需要处理的触摸状态
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_GetTouch_Status(uint8_t *RetPointToDealFlag)
{
    uint8_t StrTempData[CT_READ_LENGTH],Error = ERROR_OK;
    uint16_t Temp;

    Error = CT_Read_Nbyte(CT_ADDR,CT_READ_START,CT_READ_LENGTH,StrTempData);

    if(Error == CT_COM_OK)
    {
        Error = ERROR_OK;
        
        StCTTouchStatus.M_Gesture = StrTempData[CT_READ_NO_GEST];       //手势
        StCTTouchStatus.M_nPoint = StrTempData[CT_READ_NO_TD_STATUS];   //有多少个点有效

        if(StCTTouchStatus.M_nPoint > 0 && StCTTouchStatus.M_nPoint <= MAX_TOUCH_POINT)
        {
            *RetPointToDealFlag = SET;
            //Event Flag
            StCTTouchStatus.M_pStCTPoint[0]->M_EventFlag = StrTempData[CT_READ_NO_P1]>>6;
            StCTTouchStatus.M_pStCTPoint[1]->M_EventFlag = StrTempData[CT_READ_NO_P1]>>6;
            //X1 Position
            Temp = StrTempData[CT_READ_NO_P1]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P1+1];
            StCTTouchStatus.M_pStCTPoint[0]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[0]->M_Xpos;
            StCTTouchStatus.M_pStCTPoint[0]->M_Xpos = Temp; 
            //Y1 Position
            Temp = StrTempData[CT_READ_NO_P1+2]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P1+3];
            StCTTouchStatus.M_pStCTPoint[0]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[0]->M_Ypos;
            StCTTouchStatus.M_pStCTPoint[0]->M_Ypos = Temp;
            //X2 Position
            Temp = StrTempData[CT_READ_NO_P2]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P2+1];
            StCTTouchStatus.M_pStCTPoint[1]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[1]->M_Xpos;
            StCTTouchStatus.M_pStCTPoint[1]->M_Xpos = Temp; 
            //Y2 Position
            Temp = StrTempData[CT_READ_NO_P2+2]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P2+3];
            StCTTouchStatus.M_pStCTPoint[1]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[1]->M_Ypos;
            StCTTouchStatus.M_pStCTPoint[1]->M_Ypos = Temp;            
        }
        //没有按键按下
        else
        {
//            StCTTouchStatus.M_pStCTPoint[0]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[0]->M_Xpos;
//            StCTTouchStatus.M_pStCTPoint[0]->M_Xpos = TOUCH_NO_POINT; 
//            StCTTouchStatus.M_pStCTPoint[0]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[0]->M_Ypos;
//            StCTTouchStatus.M_pStCTPoint[0]->M_Ypos = TOUCH_NO_POINT;

//            StCTTouchStatus.M_pStCTPoint[1]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[1]->M_Xpos;
//            StCTTouchStatus.M_pStCTPoint[1]->M_Xpos = TOUCH_NO_POINT; 
//            StCTTouchStatus.M_pStCTPoint[1]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[1]->M_Ypos;
//            StCTTouchStatus.M_pStCTPoint[1]->M_Ypos = TOUCH_NO_POINT;
            Error = ERROR_UNKNOW;
        }
    }
    
    return Error;
}


/******************************************************************************
 * FUNCTION: CT_Check_Point_Valid ( )
 * DESCRIPTION: 检测当前触摸区域是否有效
 *    Input the description of function: 
 * Input Parameters: 待对比当前有效触摸区域
 * Output Parameters: 
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Check_Point_Valid(ST_ValidPoint *pStValidPoint)
{
    uint8_t Stauts = ERROR_TOUCH_POINT_INVALID,n;
    uint16_t ValidStart, ValidEnd; 
    
    for(n = 0; n < StCTTouchStatus.M_nPoint; n++)
    {
        //检测X,Y坐标是否都在有效区域内
        if(pStValidPoint->M_ValidStartXpos > pStValidPoint->M_ValidErrRange)
        {
            ValidStart = pStValidPoint->M_ValidStartXpos - pStValidPoint->M_ValidErrRange;
        }
        else
        {
            ValidStart = pStValidPoint->M_ValidStartXpos;
        }
        ValidEnd = pStValidPoint->M_ValidEndXpos + pStValidPoint->M_ValidErrRange;
        
        if((StCTTouchStatus.M_pStCTPoint[n]->M_Xpos >= ValidStart) && (StCTTouchStatus.M_pStCTPoint[n]->M_Xpos <= ValidEnd))
        {
            if(pStValidPoint->M_ValidStartYpos > pStValidPoint->M_ValidErrRange)
            {
                ValidStart = pStValidPoint->M_ValidStartYpos - pStValidPoint->M_ValidErrRange;
            }
            else
            {
                ValidStart = pStValidPoint->M_ValidStartYpos;
            }
            ValidEnd = pStValidPoint->M_ValidEndYpos + pStValidPoint->M_ValidErrRange;

            if((StCTTouchStatus.M_pStCTPoint[n]->M_Ypos >= ValidStart) && (StCTTouchStatus.M_pStCTPoint[n]->M_Ypos <= ValidEnd))
            {
                Stauts = ERROR_TOUCH_POINT_VALID;
            }
        }
    }

    return Stauts;
}

void EXTI15_10_IRQHandler(void)
{
    FlagCTINT = SET;
    
    /* 清楚中断标志位*/
    EXTI_ClearITPendingBit(TOUCH_EXTI_Line);
}
#define   MY_TOUCH_GLOBALS

#include ".././includes.h"

#define        SDA_High                    GPIO_WriteBit(CT_I2C_PORT,CT_SDA_PIN,Bit_SET)
#define        SDA_Low                          GPIO_WriteBit(CT_I2C_PORT,CT_SDA_PIN,Bit_RESET)
#define     SDA_INPUT                   {CT_I2C_PORT->CRH&=0X0FFFFFFF;CT_I2C_PORT->CRH|= 8ul<<28;}//第15脚,(15-8)*4 = 28
#define     SDA_OUTPUT                  {CT_I2C_PORT->CRH&=0X0FFFFFFF;CT_I2C_PORT->CRH|= 3ul<<28;}//第15脚,(15-8)*4 = 28
#define        SCL_High                    GPIO_WriteBit(CT_I2C_PORT,CT_SCL_PIN,Bit_SET)
#define        SCL_Low                          GPIO_WriteBit(CT_I2C_PORT,CT_SCL_PIN,Bit_RESET)
#define        GetSDABit                    GPIO_ReadInputDataBit(CT_I2C_PORT,CT_SDA_PIN)

#define     CT_DELAY_US(val)            Delay_us(val)
/* 
**函数名:CTI2C_GPIO_Config
**传入参数:无
**返回值:无
**功能:初始化CTI2C引脚
*/  
void CTI2C_GPIO_Config(void)
{
    /*定义一个GPIO_InitTypeDef类型的结构体*/   
    GPIO_InitTypeDef GPIO_InitStructure; 
    EXTI_InitTypeDef    EXTI_InitStructure; 
    
    /*开启GPIO的外设时钟*/   
    RCC_APB2PeriphClockCmd(RCC_CT_I2C_PORT | RCC_CT_CONTROL_PORT, ENABLE); 
          
    /*选择要控制的引脚*/                                                                  
    GPIO_InitStructure.GPIO_Pin = CT_SDA_PIN | CT_SCL_PIN;        
    /*设置引脚模式为通用推挽输出*/   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            
    /*设置引脚速率为10MHz */       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_I2C_PORT,&GPIO_InitStructure); 

    /*选择要控制的引脚*/                                                                  
    GPIO_InitStructure.GPIO_Pin = CT_RST_PIN;        
    /*设置引脚模式为通用推挽输出*/   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            
    /*设置引脚速率为10MHz */       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_CONTROL_PORT,&GPIO_InitStructure); 
    
    /*选择要控制的引脚*/                                                                  
    GPIO_InitStructure.GPIO_Pin = CT_INT_PIN;        
    /*设置引脚模式为通用推挽输出*/   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;            
    /*设置引脚速率为10MHz */       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_CONTROL_PORT,&GPIO_InitStructure); 

    /*********************初始化外部中断**********************/    
    /*开启引脚复用AFIO的外设时钟,因为用到了AFIO外部中断配置寄存器*/   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE); 
    /* Selects as EXTI Line */ 
    GPIO_EXTILineConfig(TOUCH_GPIO_PortSource, TOUCH_GPIO_PinSource);
    /*选择外部中断线*/ 
    EXTI_InitStructure.EXTI_Line = TOUCH_EXTI_Line; 
    /*设置EXTI线路为中断请求*/
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /*下降沿触发*/        
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    /*使能选中线路*/        
    EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
    /*外部中断初始化*/
    EXTI_Init(&EXTI_InitStructure);
/******************************************************/
}
/**************************/
static void CTI2C_start(void)//CTI2C启动函数
{
    SDA_OUTPUT;
    SCL_High;
    SDA_High;
     CT_DELAY_US(300);
    SDA_Low;
    CT_DELAY_US(300);
    SCL_Low;
}

/**************************/
static void CTI2C_stop(void)// CTI2C停止函数
{
    SDA_OUTPUT;
    SDA_Low;
    SCL_High;
    CT_DELAY_US(300);
    SDA_High;
    CT_DELAY_US(300);
    SDA_Low;
    SCL_Low;
}

/**************************/
static void CTI2C_write_byte(const uint8_t s)//CTI2C写1byte函数,S为需要写的内容
{
      uint8_t temps;
      uint8_t dat,i;
      temps=s;
      dat=0x80;
      SDA_OUTPUT;
      for(i=0;i<8;i++)
      {
        if(dat&temps)//对应位为一就发一 
         {
             SDA_High;
            CT_DELAY_US(100);//延时一下,保证数据建立时间大于50ns
            //SCL的频率,高速为400KHz,标准为100KHz
            SCL_High;
            CT_DELAY_US(300);
            SCL_Low;
            CT_DELAY_US(300);
         }
         else
         {
             SDA_Low;
            CT_DELAY_US(100);//延时一下,保证数据建立时间大于50ns
            SCL_High;
            CT_DELAY_US(300);
            SCL_Low;
            CT_DELAY_US(300);
         }
         dat=dat>>1;//注意Keil中将有符号数的右移操作作算术右移处理,我需要的是逻辑右移,因此dat要先定义为无符号数,否则会出错
      }
    SDA_High;//主控制器写完后要预先释放对SDA总线的控制
    CT_DELAY_US(100);//留一点时间接收应答信号
}

/**************************/
static void CTI2C_read_byte(uint8_t *s)//CTI2C读1byte函数,数据放在形参中,成功返回1,失败返回0
{
     uint8_t temps=0,i;
     uint8_t text=0x80;
     uint8_t sdain;
     SDA_INPUT;
     SDA_High;//设SDA为输入方式
     for(i=0;i<8;i++)
     {
          SCL_High;//使SDA上的数据有效
         CT_DELAY_US(100);//延时一下,保证SDA已经稳定
         sdain = GetSDABit;//取得SDA上的数据
         if(1==sdain)
         {
             temps |=(text>>i);//先接收高位
         }
         SCL_Low;//读完后允许SDA上的数据刷新,并延时一下让被读器件有时间更新要输出的数据
         CT_DELAY_US(300);
     }
     *s=temps;
     CT_DELAY_US(300);//留一点时间发送应答信号
}
/**************************/
static uint8_t CTI2C_check_ack(void)//CTI2C应答位检查函数,正常应答返回0,否则返回1
{
    uint8_t sdain;
    SDA_INPUT;
    SDA_High;//置SDA为输入
    SCL_High;//使SDA上的数据有效
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    sdain = GetSDABit;//取得SDA上的数据
    SCL_Low;
    if(1==sdain)
        return 1;
    else
        return 0;    
}

/**************************/
static void CTI2C_send_ack(void)//CTI2C发送应答信号函数
{
    SDA_OUTPUT;
    SDA_Low;
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    SCL_High;
    CT_DELAY_US(300);
    SCL_Low;
    SDA_High;

}
/**************************/
static void CTI2C_send_nack(void)//CTI2C发送非应答信号函数
{
    SDA_OUTPUT;
    SDA_High;
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    SCL_High;
    CT_DELAY_US(300);
    SCL_Low;
    SDA_Low;
}
/**************************/

/******************************************************************************
 * FUNCTION: CT_Write_Nbyte ( )
 * DESCRIPTION: 写触摸屏寄存器
 *    Input the description of function: 
 * Input Parameters: 器件地址,待写寄存器地址,待写数据数量,存储待写入数据的地址
 * Output Parameters: 无
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Write_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,const uint8_t *s)//CTI2C写nbyte函数,写数据由形参数组传入,成功返回1,失败返回0
{
    uint8_t temps,ack=1;
    uint16_t tempn;
    uint16_t cack_time=0;
    CTI2C_start();//启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_WRITE_MASK);//发送寻址字节
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    CTI2C_write_byte(add);//发送要写入的起始地址
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    for(tempn=0;tempn<n;tempn++)
    {
        ack=1;//应答位
        cack_time=0;
        temps=*(s+tempn);
        while(ack)
        {
            CTI2C_write_byte(temps);
            ack=CTI2C_check_ack();//检查应答信号,非应答则重发该字节
            cack_time++;
            if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
                   return CT_ACK_FAIL;
        }
    }
    CTI2C_stop();// CTI2C停止
    return CT_COM_OK;
}

/******************************************************************************
 * FUNCTION: CT_Read_Nbyte ( )
 * DESCRIPTION: 从触摸屏中读出数据
 *    Input the description of function: 
 * Input Parameters: 器件地址,待读寄存器地址,待读数据数量,存储待读出数据的地址
 * Output Parameters: 读取的数据
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Read_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,uint8_t *s)//CTI2C读nbyte函数,所读数据放在形参数组中(由程序员设置合适的数组大小),成功返回1,失败返回0
{
    uint8_t temps;
    uint16_t tempn;
    uint16_t cack_time=0;
    CTI2C_start();//启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_WRITE_MASK);//发送寻址字节,伪写
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    CTI2C_write_byte(add);//发送要读入的起始地址
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    CTI2C_start();//再次启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_READ_MASK);//再次发送寻址字节,读
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
           return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());

    for(tempn=0;tempn<n;tempn++)
    {
        CTI2C_read_byte(&temps);
        *(s+tempn)=temps;
        if(tempn+1<n)//如果已经读完所有数据了,就不要发应答信号,直接发非应答位和停止位
            CTI2C_send_ack();//CTI2C发送应答信号.准备下一字节的接收
    }
    CTI2C_send_nack();//接收完毕,发送非应答位和停止位
    CTI2C_stop();
    return CT_COM_OK;
}


//复位触摸芯片
void CT_Reset(void)
{
    //The reset signal from host to CTPM, active low, and the low pulse width should be more than or equal to 1ms
    GPIO_SetBits(CT_CONTROL_PORT,CT_RST_PIN);
    Delay_ms(1);
    GPIO_ResetBits(CT_CONTROL_PORT,CT_RST_PIN);
    Delay_ms(5);
    GPIO_SetBits(CT_CONTROL_PORT,CT_RST_PIN);
    Delay_ms(1);
}

/******************************************************************************
 * FUNCTION: CT_Init_Val ( )
 * DESCRIPTION: 初始化触摸芯片相关变量
 *    Input the description of function: 
 * Input Parameters: 
 * Output Parameters: 
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
void CT_Init_Val(void)
{
    FlagCTINT = RESET;
    FlagPointToDeal = RESET;
    
    StCTPoint1.M_EventFlag = EVENT_NONE;
    StCTPoint2.M_EventFlag = EVENT_NONE;

    StCTTouchStatus.M_Gesture = GUSTURE_NONE;
    StCTTouchStatus.M_nPoint = 0;
    StCTTouchStatus.M_pStCTPoint[0] = &StCTPoint1;
    StCTTouchStatus.M_pStCTPoint[1] = &StCTPoint2;
}


/******************************************************************************
 * FUNCTION: CT_GetTouch_Status ( )
 * DESCRIPTION: 获取当前触摸状态,保存在ST_CTTouchStatus中
 *    Input the description of function: 
 * Input Parameters: 
 * Output Parameters: 是否有需要处理的触摸状态
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_GetTouch_Status(uint8_t *RetPointToDealFlag)
{
    uint8_t StrTempData[CT_READ_LENGTH],Error = ERROR_OK;
    uint16_t Temp;

    Error = CT_Read_Nbyte(CT_ADDR,CT_READ_START,CT_READ_LENGTH,StrTempData);

    if(Error == CT_COM_OK)
    {
        Error = ERROR_OK;
        
        StCTTouchStatus.M_Gesture = StrTempData[CT_READ_NO_GEST];       //手势
        StCTTouchStatus.M_nPoint = StrTempData[CT_READ_NO_TD_STATUS];   //有多少个点有效

        if(StCTTouchStatus.M_nPoint > 0 && StCTTouchStatus.M_nPoint <= MAX_TOUCH_POINT)
        {
            *RetPointToDealFlag = SET;
            //Event Flag
            StCTTouchStatus.M_pStCTPoint[0]->M_EventFlag = StrTempData[CT_READ_NO_P1]>>6;
            StCTTouchStatus.M_pStCTPoint[1]->M_EventFlag = StrTempData[CT_READ_NO_P1]>>6;
            //X1 Position
            Temp = StrTempData[CT_READ_NO_P1]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P1+1];
            StCTTouchStatus.M_pStCTPoint[0]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[0]->M_Xpos;
            StCTTouchStatus.M_pStCTPoint[0]->M_Xpos = Temp; 
            //Y1 Position
            Temp = StrTempData[CT_READ_NO_P1+2]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P1+3];
            StCTTouchStatus.M_pStCTPoint[0]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[0]->M_Ypos;
            StCTTouchStatus.M_pStCTPoint[0]->M_Ypos = Temp;
            //X2 Position
            Temp = StrTempData[CT_READ_NO_P2]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P2+1];
            StCTTouchStatus.M_pStCTPoint[1]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[1]->M_Xpos;
            StCTTouchStatus.M_pStCTPoint[1]->M_Xpos = Temp; 
            //Y2 Position
            Temp = StrTempData[CT_READ_NO_P2+2]&0x0F;
            Temp = Temp<<8;
            Temp += StrTempData[CT_READ_NO_P2+3];
            StCTTouchStatus.M_pStCTPoint[1]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[1]->M_Ypos;
            StCTTouchStatus.M_pStCTPoint[1]->M_Ypos = Temp;            
        }
        //没有按键按下
        else
        {
//            StCTTouchStatus.M_pStCTPoint[0]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[0]->M_Xpos;
//            StCTTouchStatus.M_pStCTPoint[0]->M_Xpos = TOUCH_NO_POINT; 
//            StCTTouchStatus.M_pStCTPoint[0]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[0]->M_Ypos;
//            StCTTouchStatus.M_pStCTPoint[0]->M_Ypos = TOUCH_NO_POINT;

//            StCTTouchStatus.M_pStCTPoint[1]->M_PreXpos = StCTTouchStatus.M_pStCTPoint[1]->M_Xpos;
//            StCTTouchStatus.M_pStCTPoint[1]->M_Xpos = TOUCH_NO_POINT; 
//            StCTTouchStatus.M_pStCTPoint[1]->M_PreYpos = StCTTouchStatus.M_pStCTPoint[1]->M_Ypos;
//            StCTTouchStatus.M_pStCTPoint[1]->M_Ypos = TOUCH_NO_POINT;
            Error = ERROR_UNKNOW;
        }
    }
    
    return Error;
}


/******************************************************************************
 * FUNCTION: CT_Check_Point_Valid ( )
 * DESCRIPTION: 检测当前触摸区域是否有效
 *    Input the description of function: 
 * Input Parameters: 待对比当前有效触摸区域
 * Output Parameters: 
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Check_Point_Valid(ST_ValidPoint *pStValidPoint)
{
    uint8_t Stauts = ERROR_TOUCH_POINT_INVALID,n;
    uint16_t ValidStart, ValidEnd; 
    
    for(n = 0; n < StCTTouchStatus.M_nPoint; n++)
    {
        //检测X,Y坐标是否都在有效区域内
        if(pStValidPoint->M_ValidStartXpos > pStValidPoint->M_ValidErrRange)
        {
            ValidStart = pStValidPoint->M_ValidStartXpos - pStValidPoint->M_ValidErrRange;
        }
        else
        {
            ValidStart = pStValidPoint->M_ValidStartXpos;
        }
        ValidEnd = pStValidPoint->M_ValidEndXpos + pStValidPoint->M_ValidErrRange;
        
        if((StCTTouchStatus.M_pStCTPoint[n]->M_Xpos >= ValidStart) && (StCTTouchStatus.M_pStCTPoint[n]->M_Xpos <= ValidEnd))
        {
            if(pStValidPoint->M_ValidStartYpos > pStValidPoint->M_ValidErrRange)
            {
                ValidStart = pStValidPoint->M_ValidStartYpos - pStValidPoint->M_ValidErrRange;
            }
            else
            {
                ValidStart = pStValidPoint->M_ValidStartYpos;
            }
            ValidEnd = pStValidPoint->M_ValidEndYpos + pStValidPoint->M_ValidErrRange;

            if((StCTTouchStatus.M_pStCTPoint[n]->M_Ypos >= ValidStart) && (StCTTouchStatus.M_pStCTPoint[n]->M_Ypos <= ValidEnd))
            {
                Stauts = ERROR_TOUCH_POINT_VALID;
            }
        }
    }

    return Stauts;
}

void EXTI15_10_IRQHandler(void)
{
    FlagCTINT = SET;
    
    /* 清楚中断标志位*/
    EXTI_ClearITPendingBit(TOUCH_EXTI_Line);
}