STM32F7 电容触摸实现

/ 0评 / 2

因为这个F7探索板上有电容触摸的IC,而且这个直接读取坐标特别方便.用的方案是FT5336,支持5点触摸.走I2C协议.这里要说一个很多人容易犯错的地方.就是关于I2C的初始化.用模拟I2C的可以飘过,对于我这种强迫症党来说,模拟I2C几乎不能接受.这个忠告就是,初始化不要初始化两次,初始化不要初始化两次,初始化不要初始化两次!因为初始化两次,时间浪费可以不说,而且很容易引入不明BUG,真的是不明BUG啊,连官方都没法解释.所以如果你知道就是要用这个I2C,开机后就初始化吧,不要等后来再反复初始化.
为了保证能正确和触摸屏通信,通常还会读取触摸屏的ID地址,因为这个电容触摸,封闭性比较高,因此... 寄存器表不好找.找到也不太准,太气人.当然从官方定义头文件,也能看到很多.
按照官方推荐的做法,读4次ID寄存器,如果还没返回,那肯定是有问题的.

uint16_t ft5336_ReadID(uint16_t DeviceAddr)
{
  volatile uint8_t ucReadId = 0;
  uint8_t nbReadAttempts = 0;
  uint8_t bFoundDevice = 0; /* Device not found by default */
  /* At maximum 4 attempts to read ID : exit at first finding of the searched device ID */
  for(nbReadAttempts = 0; ((nbReadAttempts < 3) && !(bFoundDevice)); nbReadAttempts++)
  {
    /* Read register FT5336_CHIP_ID_REG as DeviceID detection */
    ucReadId = TS_IO_Read(DeviceAddr, FT5336_CHIP_ID_REG);
    /* Found the searched device ID ? */
    if(ucReadId == FT5336_ID_VALUE)
    {
      /* Set device as found */
      bFoundDevice = 1;
    }
  }
  /* Return the device ID value */
  return (ucReadId);
}

其他也很简单,照着移植没几分钟就好了.最重要是CTouch_GetState我自己定义的一个函数,原型如下:

uint8_t CTouch_GetState(TS_StateTypeDef *TS_State);

其实这个结构体,可以理解成所有数据:

typedef struct
{
  uint8_t  touchDetected;                /*!< Total number of active touches detected at last scan */
  uint16_t touchX[FT5336_MAX_DETECTABLE_TOUCH];      /*!< Touch X[0], X[1] coordinates on 12 bits */
  uint16_t touchY[FT5336_MAX_DETECTABLE_TOUCH];      /*!< Touch Y[0], Y[1] coordinates on 12 bits */
  uint8_t  touchWeight[FT5336_MAX_DETECTABLE_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */
  uint8_t  touchEventId[FT5336_MAX_DETECTABLE_TOUCH];     /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */
  uint8_t  touchArea[FT5336_MAX_DETECTABLE_TOUCH];   /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */
  uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */
} TS_StateTypeDef;

首先看一下有多少点已经触摸,要存起来.

TS_State->touchDetected = ft5336_TS_DetectTouch(FT5336_I2C_SLAVE_ADDRESS);

如果根本没有触摸点,就不需要反馈.所以,直接return就行,不然的话,就要获取点了.两个需求,一个是获取坐标,一个是获取手势.先说说获取手势,方式如下,很简单:

        ft5336_TS_GetGestureID(FT5336_I2C_SLAVE_ADDRESS, &gestureId);
        /* Remap gesture Id to a TS_GestureIdTypeDef value */
        switch(gestureId)
        {
        case FT5336_GEST_ID_NO_GESTURE :
            TS_State->gestureId = GEST_ID_NO_GESTURE;
            break;
        case FT5336_GEST_ID_MOVE_UP :
            TS_State->gestureId = GEST_ID_MOVE_UP;
            break;
        case FT5336_GEST_ID_MOVE_RIGHT :
            TS_State->gestureId = GEST_ID_MOVE_RIGHT;
            break;
        case FT5336_GEST_ID_MOVE_DOWN :
            TS_State->gestureId = GEST_ID_MOVE_DOWN;
            break;
        case FT5336_GEST_ID_MOVE_LEFT :
            TS_State->gestureId = GEST_ID_MOVE_LEFT;
            break;
        case FT5336_GEST_ID_ZOOM_IN :
            TS_State->gestureId = GEST_ID_ZOOM_IN;
            break;
        case FT5336_GEST_ID_ZOOM_OUT :
            TS_State->gestureId = GEST_ID_ZOOM_OUT;
            break;
        default :
            ts_status = TS_ERROR;
            break;
        } /* of switch(gestureId) */

然后循环获取坐标:

当然,实际上坐标获取后,可能是不对的,比如镜像了之类的.通过这种方法来修正.

            if(tsOrientation == TS_SWAP_NONE)
            {
                x[index] = brute_x[index];
                y[index] = brute_y[index];
            }
            if(tsOrientation & TS_SWAP_X)
            {
                x[index] = 4096 - brute_x[index];
            }
            if(tsOrientation & TS_SWAP_Y)
            {
                y[index] = 4096 - brute_y[index];
            }
            if(tsOrientation & TS_SWAP_XY)
            {
                y[index] = brute_x[index];
                x[index] = brute_y[index];
            }

因为是电容触摸,可能触摸的是一个区域,所以还需要这么获取.

            /* Get touch info related to the current touch */
            ft5336_TS_GetTouchInfo(FT5336_I2C_SLAVE_ADDRESS, index, &weight, &area, &event);
            /* Update TS_State structure */
            TS_State->touchWeight[index] = weight;
            TS_State->touchArea[index]   = area;
            /* Remap touch event */
            switch(event)
            {
            case FT5336_TOUCH_EVT_FLAG_PRESS_DOWN	:
                TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN;
                break;
            case FT5336_TOUCH_EVT_FLAG_LIFT_UP :
                TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP;
                break;
            case FT5336_TOUCH_EVT_FLAG_CONTACT :
                TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT;
                break;
            case FT5336_TOUCH_EVT_FLAG_NO_EVENT :
                TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT;
                break;
            default :
                ts_status = TS_ERROR;
                break;
            } /* of switch(event) */

经过一轮循环后,结构体就根据不同的触摸点数赋值了.然后这个结构就有用了.

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注