STM Урок 72. Touch panel FT5336. Часть 3



 

Урок 72

 

Часть 3

 

Touch panel FT5336

 

В предыдущей части занятия мы закончили писать функцию инициализации тачскрина, а также начали писать код процесса отслеживания различных действий TS.

 

Теперь нам нужна будет функция определения координат действия. Добавим её после функции TS_DetectTouch и напишем в её теле сначала несколько локальных переменных

 

//----------------------------------------

void TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y)

{

  volatile uint8_t ucReadData = 0;

  static uint16_t coord;

  uint8_t regAddressXLow = 0;

  uint8_t regAddressXHigh = 0;

  uint8_t regAddressYLow = 0;

  uint8_t regAddressYHigh = 0;

}

//----------------------------------------

 

Добавим в функцию условие

 

  uint8_t regAddressYHigh = 0;

  if(ft5336_handle.currActiveTouchIdx < ft5336_handle.currActiveTouchNb)

  {

  }

}

 

В этом условии мы проверяем, что у нас не закончились идентификаторы действий с TS.

Далее в теле условия добавим переключатель switch для реакции на вариант действия

 

if(ft5336_handle.currActiveTouchIdx < ft5336_handle.currActiveTouchNb)

{

  switch(ft5336_handle.currActiveTouchIdx)

  {

  }

}

 

 

Таких вариантов может быть не 5, а 10. У нас будет 5, так как в макросе количества максимальных действий TS у нас стоит 5. Но видимо для дальнейшего развития, а может быть в каких-то моделях это уже есть, регистров для хранения координат действия существует 10 видов. Каждый вид регистров состоит из четырёх регистров. Одна пара — для горизонтальной координаты, другая пара — для вертикальной, так как координата может быть более 256, поэтому на неё отводится 2-байтное хранилище — старший и младший байты. Поэтому вариантов у нас будет 10, как и в примере из репозитория

 

switch(ft5336_handle.currActiveTouchIdx)

switch(ft5336_handle.currActiveTouchIdx)

{

  case 0 :

    regAddressXLow = FT5336_P1_XL_REG;

    regAddressXHigh = FT5336_P1_XH_REG;

    regAddressYLow = FT5336_P1_YL_REG;

    regAddressYHigh = FT5336_P1_YH_REG;

    break;

  case 1 :

    regAddressXLow = FT5336_P2_XL_REG;

    regAddressXHigh = FT5336_P2_XH_REG;

    regAddressYLow = FT5336_P2_YL_REG;

    regAddressYHigh = FT5336_P2_YH_REG;

    break;

  case 2 :

    regAddressXLow = FT5336_P3_XL_REG;

    regAddressXHigh = FT5336_P3_XH_REG;

    regAddressYLow = FT5336_P3_YL_REG;

    regAddressYHigh = FT5336_P3_YH_REG;

    break;

  case 3 :

    regAddressXLow = FT5336_P4_XL_REG;

    regAddressXHigh = FT5336_P4_XH_REG;

    regAddressYLow = FT5336_P4_YL_REG;

    regAddressYHigh = FT5336_P4_YH_REG;

    break;

  case 4 :

    regAddressXLow = FT5336_P5_XL_REG;

    regAddressXHigh = FT5336_P5_XH_REG;

    regAddressYLow = FT5336_P5_YL_REG;

    regAddressYHigh = FT5336_P5_YH_REG;

    break;

  case 5 :

    regAddressXLow = FT5336_P6_XL_REG;

    regAddressXHigh = FT5336_P6_XH_REG;

    regAddressYLow = FT5336_P6_YL_REG;

    regAddressYHigh = FT5336_P6_YH_REG;

    break;

  case 6 :

    regAddressXLow = FT5336_P7_XL_REG;

    regAddressXHigh = FT5336_P7_XH_REG;

    regAddressYLow = FT5336_P7_YL_REG;

    regAddressYHigh = FT5336_P7_YH_REG;

    break;

  case 7 :

    regAddressXLow = FT5336_P8_XL_REG;

    regAddressXHigh = FT5336_P8_XH_REG;

    regAddressYLow = FT5336_P8_YL_REG;

    regAddressYHigh = FT5336_P8_YH_REG;

    break;

  case 8 :

    regAddressXLow = FT5336_P9_XL_REG;

    regAddressXHigh = FT5336_P9_XH_REG;

    regAddressYLow = FT5336_P9_YL_REG;

    regAddressYHigh = FT5336_P9_YH_REG;

    break;

  case 9 :

    regAddressXLow = FT5336_P10_XL_REG;

    regAddressXHigh = FT5336_P10_XH_REG;

    regAddressYLow = FT5336_P10_YL_REG;

    regAddressYHigh = FT5336_P10_YH_REG;

    break;

  default :

    break;

}

 

В данных вариантах мы записали номера регистров, соответствующих номеру (индексу) действия (или пальца) в соответствующие переменные.

Далее выходим из переключателя switch (но не из условия) и читаем данные из регистров, хранящих значения координат, а затем заносим эти данные в 16-битные переменные, а после этого инкрементируем (наращиваем на 1) индекс действия

 

      break;

    }

    ucReadData = TS_IO_Read(DeviceAddr, regAddressXLow);

    coord = (ucReadData & FT5336_TOUCH_POS_LSB_MASK) >> FT5336_TOUCH_POS_LSB_SHIFT;

    ucReadData = TS_IO_Read(DeviceAddr, regAddressXHigh);

    coord |= ((ucReadData & FT5336_TOUCH_POS_MSB_MASK) >> FT5336_TOUCH_POS_MSB_SHIFT) << 8;

    *X = coord;

    ucReadData = TS_IO_Read(DeviceAddr, regAddressYLow);

    coord = (ucReadData & FT5336_TOUCH_POS_LSB_MASK) >> FT5336_TOUCH_POS_LSB_SHIFT;

    ucReadData = TS_IO_Read(DeviceAddr, regAddressYHigh);

    coord |= ((ucReadData & FT5336_TOUCH_POS_MSB_MASK) >> FT5336_TOUCH_POS_MSB_SHIFT) << 8;

    *Y = coord;

    ft5336_handle.currActiveTouchIdx++; /* next call will work on next touch */

  }

}

 

Функция готова, вернёмся в функцию TS_GetState в наш добавленный цикл и теперь в теле данного цикла вызовем только что написанную функцию определения координат для соответствующего номера действия, записав тем самым координаты в соответствующие переменные

 

for(index=0; index < TS_State->touchDetected; index++)

{

  TS_GetXY(TS_I2C_ADDRESS, &(brute_x[index]), &(brute_y[index]));

}

 

Затем в этом же цикле запишем эти координаты уже в другие переменные, сделав поправку на ориентацию

 

  TS_GetXY(TS_I2C_ADDRESS, &(brute_x[index]), &(brute_y[index]));

  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];

  }

}

 

Произведём ещё некоторые поправки и усреднения и запишем координаты в соответствующие поля структуры статуса TS

 

      x[index] = brute_y[index];

      x_diff = x[index] > _x[index]? (x[index] - _x[index]): (_x[index] - x[index]);

      y_diff = y[index] > _y[index]? (y[index] - _y[index]): (_y[index] - y[index]);

      if ((x_diff + y_diff) > 5)

      {

        _x[index] = x[index];

        _y[index] = y[index];

      }

      TS_State->touchX[index] = x[index];

      TS_State->touchY[index] = y[index];

    }

  }

}

 

 

После функции TS_IO_Write добавим ещё одну функцию для сбора некоторой информации из TS

 

//----------------------------------------

void TS_GetTouchInfo(uint16_t DeviceAddr,

  uint32_t touchIdx,

  uint32_t * pWeight,

  uint32_t * pArea,

  uint32_t * pEvent)

{

  volatile uint8_t ucReadData = 0;

  uint8_t regAddressXHigh = 0;

  uint8_t regAddressPWeight = 0;

  uint8_t regAddressPMisc = 0;

}

//----------------------------------------

 

Добавим в данную функцию условие проверки валидности индекса действия

 

  uint8_t regAddressPMisc = 0;

  if(touchIdx < ft5336_handle.currActiveTouchNb)

  {

  }

}

 

В теле условия добавим определение индекса

 

if(touchIdx < ft5336_handle.currActiveTouchNb)

{

  switch(touchIdx)

  {

  }

}

 

Ну, и по аналогии написания предыдущей функции пробежимся по всем 10 возможным вариантам (хотя физически у нас их 5) и запишем идентификаторы регистров определённых видов действий (сила нажатия, область нажатия, вид события) в соответствующие переменные

 

switch(touchIdx)

switch(touchIdx)

{

  case 0 :

    regAddressXHigh = FT5336_P1_XH_REG;

    regAddressPWeight = FT5336_P1_WEIGHT_REG;

    regAddressPMisc = FT5336_P1_MISC_REG;

    break;

  case 1 :

    regAddressXHigh = FT5336_P2_XH_REG;

    regAddressPWeight = FT5336_P2_WEIGHT_REG;

    regAddressPMisc = FT5336_P2_MISC_REG;

    break;

  case 2 :

    regAddressXHigh = FT5336_P3_XH_REG;

    regAddressPWeight = FT5336_P3_WEIGHT_REG;

    regAddressPMisc = FT5336_P3_MISC_REG;

    break;

  case 3 :

    regAddressXHigh = FT5336_P4_XH_REG;

    regAddressPWeight = FT5336_P4_WEIGHT_REG;

    regAddressPMisc = FT5336_P4_MISC_REG;

    break;

  case 4 :

    regAddressXHigh = FT5336_P5_XH_REG;

    regAddressPWeight = FT5336_P5_WEIGHT_REG;

    regAddressPMisc = FT5336_P5_MISC_REG;

    break;

  case 5 :

    regAddressXHigh = FT5336_P6_XH_REG;

    regAddressPWeight = FT5336_P6_WEIGHT_REG;

    regAddressPMisc = FT5336_P6_MISC_REG;

    break;

  case 6 :

    regAddressXHigh = FT5336_P7_XH_REG;

    regAddressPWeight = FT5336_P7_WEIGHT_REG;

    regAddressPMisc = FT5336_P7_MISC_REG;

    break;

  case 7 :

    regAddressXHigh = FT5336_P8_XH_REG;

    regAddressPWeight = FT5336_P8_WEIGHT_REG;

    regAddressPMisc = FT5336_P8_MISC_REG;

    break;

  case 8 :

    regAddressXHigh = FT5336_P9_XH_REG;

    regAddressPWeight = FT5336_P9_WEIGHT_REG;

    regAddressPMisc = FT5336_P9_MISC_REG;

    break;

  case 9 :

    regAddressXHigh = FT5336_P10_XH_REG;

    regAddressPWeight = FT5336_P10_WEIGHT_REG;

    regAddressPMisc = FT5336_P10_MISC_REG;

    break;

  default :

    break;

}

 

Выйдем из switch (не из условия) и запросим данные значения, обратившись в соответствующие регистры по шине I2C и запишем эти значения по адресам входящих аргументов функции для дальнейшего их использования после выхода из неё 

 

    break;

  }

  ucReadData = TS_IO_Read(DeviceAddr, regAddressXHigh);

  * pEvent = (ucReadData & FT5336_TOUCH_EVT_FLAG_MASK) >> FT5336_TOUCH_EVT_FLAG_SHIFT;

  ucReadData = TS_IO_Read(DeviceAddr, regAddressPWeight);

  * pWeight = (ucReadData & FT5336_TOUCH_WEIGHT_MASK) >> FT5336_TOUCH_WEIGHT_SHIFT;

  ucReadData = TS_IO_Read(DeviceAddr, regAddressPMisc);

  * pArea = (ucReadData & FT5336_TOUCH_AREA_MASK) >> FT5336_TOUCH_AREA_SHIFT;

}

 

Фунция закончена.

Перейдём в файл ft5336.h и добавим перечисление идентификаторов событий TS

 

}TS_StatusTypeDef;

//------------------------------------------

typedef enum

{

  TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */

  TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */

  TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */

  TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */

  TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */

} TS_TouchEventTypeDef;

//------------------------------------------

 

Вернёмся в файл ft5336.c и вызовем только что написанную нами функцию в функции TS_GetState и запишем после вызова из возвращённых адресов значения в соответствующие поля статуса TS

 

  TS_State->touchY[index] = y[index];

  TS_GetTouchInfo(TS_I2C_ADDRESS, index, &weight, &area, &event);

  TS_State->touchWeight[index] = weight;

  TS_State->touchArea[index] = area;

  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;

  }

}

 

В следующей части занятия мы закончим писать функцию определения всех статусов TS и воспользуемся ей на практике, добавив определённый код для теста в бесконечном цикле.

 

 

Предыдущая часть Программирование МК STM32 Следующая часть

 

 

Исходный код

 

 

Техническая документация на драйвер TS FT5336

 

 

Отладочную плату можно приобрести здесь 32F746G-DISCOVERY

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM Touch panel FT5336

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*