Глава 15_Общий модуль шины I2C в серии вводных руководств Renesas MCU с отсчетом от нуля

Это руководство написано на основе платы разработки DShanMCU-RA6M5, созданной Wei Dongshan Baiwen.com . Студенты, которым оно нужно, могут получить его здесь: https://item.taobao.com/item.htm?id=728461040949 .

Получите вспомогательную информацию: https://renesas-docs.100ask.net .

Краткое изложение руководств Renesas MCU с нулевой базой : https://blog.csdn.net/qq_35181236/article/details/132779862


Глава 15. Общий модуль шины I2C

Цели этой главы

  • Используйте RASC для быстрой настройки модулей Common I2C.
  • Научитесь использовать i2c API для управления сенсорными чипами и получения контактных данных.

15.1 Использование модуля Common I2C

I2C чипа RA разделен на простой I2C и общий I2C. Простой I2C — это режим I2C модуля SCI, упомянутый в главе 8 SCI SPI этой книги. Он использует последовательную шину для имитации протокола I2C, а общий I2C, упомянутый в этой главе, представляет собой аппаратный модуль контроллера I2C, который действительно существует. внутри чипа...

Благодаря инкапсуляции FSP нет большой разницы в применении между Simple I2C и Common I2C.

15.1.1 Конфигурация модуля I2C

Чтобы настроить модуль I2C, сначала найдите «Подключение: IIC» в «Периферийные устройства» в «Конфигурация контактов» RASC, а затем выберите канал I2C в соответствии с конструкцией оборудования. Например, в этой книге в качестве SDA и SCL I2C используются P409/P410. Эти два ввода-вывода принадлежат к контактам группы A I2C2, поэтому выберите «IIC2», а затем выберите «Выбор группы контактов» в расширенной конфигурации контактов. » и включите рабочий режим, как показано на рисунке ниже:

Затем перейдите в «Стеки», чтобы добавить модуль I2C. Нажмите «Новый стек», выберите «Подключение», а затем внутри выберите «I2C Master(r_iic_master)». Цель этой главы — служить хостом для чтения данных сенсорного экрана, поэтому выберите «Мастер», как показано на рисунке ниже:

После добавления модуля I2C Master необходимо настроить его параметры. Эксперименты в этой главе настраивают параметры I2C в RASC, как показано на рисунке ниже:

  • Имя: имя модуля I2C, которое должно соответствовать стандарту строк языка C;
  • Канал: канал модуля I2C;
  • Скорость: скорость связи I2C, максимальная скорость, поддерживаемая в стандартном режиме, составляет 400 кбит/с, а максимальная скорость, поддерживаемая в быстром режиме, — 1 Мбит/с;
  • Время нарастания/спада: время, необходимое для нарастания и спада сигнала SCL;

  • Рабочий цикл: рабочий цикл линии синхронизации SCL, диапазон составляет 4–96 %, значение по умолчанию – 50 %;
  • Адрес подчиненного устройства: адрес подчиненного устройства, установленный в соответствии с подчиненным чипом;
  • Режим адреса: Режим адреса, поддерживает 7-битный и 10-битный;
  • Режим тайм-аута: режим тайм-аута обнаружения данных, поддерживает длинный и короткий режимы. Счетчик тайм-аута в длинном режиме составляет 16 бит, а счетчик тайм-аута в коротком режиме — 14 бит; когда счетчик тайм-аута переполняется и данные не обнаруживаются, связь прекращается;
  • Тайм-аут при низком уровне вероятности нежелательной почты: включить ли обнаружение тайм-аута при низком уровне вероятности нежелательной почты (по умолчанию включено);
  • Обратный вызов: имя функции обратного вызова прерывания, рекомендуется совпадать с каналом, например i2c1_callback;
  • Уровень приоритета прерывания: уровень приоритета прерывания I2C;

15.1.2 Интерпретация информации о конфигурации

Информация о конфигурации разделена на две части: информация о конфигурации контактов и информация о конфигурации модуля I2C.

После использования RASC для настройки параметров и создания проекта информация о выводах модуля будет сгенерирована в pin_data.c проекта, а информация о конфигурации модуля будет сгенерирована в hal_data.c.

  1. Информация о контактах модуля I2C

Пины участвуют в I2C, информация об их конфигурации генерируется в pin_data.c проекта. Каждый контакт, настроенный в RASC, будет генерировать элемент массива ioport_pin_cfg_t в pin_data.c, а содержимое внутри соответствует параметрам, выбранным во время настройки. код показан ниже:

const ioport_pin_cfg_t g_bsp_pin_cfg_data[] = {
    
    
    ......(省略内容)
    {
    
     .pin = BSP_IO_PORT_04_PIN_09,
      .pin_cfg = ((uint32_t) IOPORT_CFG_DRIVE_MID 
                | (uint32_t) IOPORT_CFG_PERIPHERAL_PIN 
                | (uint32_t) IOPORT_PERIPHERAL_IIC)},
    {
    
     .pin = BSP_IO_PORT_04_PIN_10,
      .pin_cfg = ((uint32_t) IOPORT_CFG_DRIVE_MID 
                | (uint32_t) IOPORT_CFG_PERIPHERAL_PIN 
                | (uint32_t) IOPORT_PERIPHERAL_IIC)},
    ......(省略内容)
};

Этот постоянный массив настраивает P5409 и P410 как функции мультиплексирования периферийных устройств I2C.

  1. Информация о конфигурации модуля I2C

Информация о конфигурации I2C будет определена в константе типа структуры i2c_master_cfg_t g_i2c_master2_cfg в файле hal_data.c. Код выглядит следующим образом:

const i2c_master_cfg_t g_i2c_master2_cfg =
{
    
    
    .channel             = 2,
    .rate                = I2C_MASTER_RATE_STANDARD,
    .slave               = 0x14,
    .addr_mode           = I2C_MASTER_ADDR_MODE_7BIT,
    ......(省略内容)
    .p_callback          = i2c2_callback,
    .p_context           = NULL,
    ......(省略内容)
    .ipl                 = (12),
    .p_extend            = &g_i2c_master2_extend,
};
  • Строка 03: Канал установлен на 2;
  • Строка 04: Скорость связи установлена ​​на стандартную скорость;
  • Строка 05: Адрес подчиненного устройства — 0x14;
  • Строка 06: Режим адреса — 7-битный;
  • Строка 08: установите имя функции прерывания на i2c2_callback;

При использовании функции открытия I2C эта константа будет использоваться для инициализации модуля I2C.

15.1.3 Функция обратного вызова прерывания

Функция с именем "i2c1_callback" используется в g_i2c_master2_cfg. Эта функция объявлена ​​только следующим образом в hal_data.h, но не реализована:

#ifndef i2c1_callback
void i2c1_callback(i2c_master_callback_args_t * p_args);
#endif

Пользователям необходимо реализовать эту функцию, например:

void i2c1_callback(i2c_master_callback_args_t * p_args)
{
    
    
    switch (p_args->event)
    {
    
    
    }
}

Параметром этой функции обратного вызова прерывания является указатель на структуру i2c_master_callback_args_t. Прототип этой структуры следующий:

typedef struct st_i2c_master_callback_args
{
    
    
    void const       * p_context;      ///< Pointer to user-provided context
    i2c_master_event_t event;          ///< Event code
} i2c_master_callback_args_t;

Член события представляет собой тип перечисления, включающий следующие типы событий:

typedef enum e_i2c_master_event
{
    
    
    I2C_MASTER_EVENT_ABORTED     = 1,  ///< A transfer was aborted
    I2C_MASTER_EVENT_RX_COMPLETE = 2,  ///< A receive operation was completed successfully
    I2C_MASTER_EVENT_TX_COMPLETE = 3   ///< A transmit operation was completed successfully
} i2c_master_event_t;

Отсюда мы можем узнать, что причинами срабатывания прерываний I2C являются: завершение передачи, завершение приема и прерывание передачи. После того, как они вызывают прерывание, вызывается функция обратного вызова для выполнения кода пользователя.

15.1.4 Интерфейс API и его применение

В заголовочном файле функции библиотеки FSP r_i2c_master_api.h модуля I2C определена структура операционной функции i2c_master_api_t хост-устройства I2C. Прототип выглядит следующим образом:

/** Interface definition for I2C access as master */
typedef struct st_i2c_master_api
{
    
    
    fsp_err_t (* open)(i2c_master_ctrl_t * const p_ctrl, 
                       i2c_master_cfg_t const * const p_cfg);
    fsp_err_t (* read)(i2c_master_ctrl_t * const p_ctrl, 
                       uint8_t * const p_dest, 
                       uint32_t const bytes,
                       bool const restart);
    fsp_err_t (* write)(i2c_master_ctrl_t * const p_ctrl, 
                        uint8_t * const p_src, 
                        uint32_t const bytes,
                        bool const restart);
    fsp_err_t (* abort)(i2c_master_ctrl_t * const p_ctrl);
    fsp_err_t (* slaveAddressSet)(i2c_master_ctrl_t * const p_ctrl, 
                                  uint32_t const slave,
                                  i2c_master_addr_mode_t const addr_mode);
    fsp_err_t (* callbackSet)(i2c_master_ctrl_t * const p_api_ctrl, 
                              void (* p_callback)(i2c_master_callback_args_t *),
                              void const * const p_context, 
                              i2c_master_callback_args_t * const p_callback_memory);
    fsp_err_t (* statusGet)(i2c_master_ctrl_t * const p_api_ctrl, 
                            i2c_master_status_t * p_status);
    fsp_err_t (* close)(i2c_master_ctrl_t * const p_ctrl);
} i2c_master_api_t;

Операции, поддерживаемые хост-устройством I2C: открытие/чтение/запись/закрытие и т. д. FSP реализует эту структуру в r_iic_master.c:

/* IIC Implementation of I2C device master interface */
i2c_master_api_t const g_i2c_master_on_iic =
{
    
    
    .open            = R_IIC_MASTER_Open,
    .read            = R_IIC_MASTER_Read,
    .write           = R_IIC_MASTER_Write,
    .abort           = R_IIC_MASTER_Abort,
    .slaveAddressSet = R_IIC_MASTER_SlaveAddressSet,
    .close           = R_IIC_MASTER_Close,
    .statusGet       = R_IIC_MASTER_StatusGet,
    .callbackSet     = R_IIC_MASTER_CallbackSet
};

В этой главе в качестве примера для анализа рассматриваются открытие, закрытие, чтение и запись хост-устройства I2C.

  1. Включите главное устройство I2C.

Прототип указателя функции для открытия хост-устройства I2C выглядит следующим образом:

/** Opens the I2C Master driver and initializes the hardware.
 * @param[in] p_ctrl    Pointer to control block. Must be declared by user. Elements are set here.
 * @param[in] p_cfg     Pointer to configuration structure.
 */
fsp_err_t (* open)(i2c_master_ctrl_t * const p_ctrl, i2c_master_cfg_t const * const p_cfg);
  • p_ctrl: указывает на блок управления хостом I2C, например g_i2c_master2_ctrl;
  • p_cfg: указывает на константу структуры конфигурации параметров хоста I2C, например g_i2c_master2_cfg;

Типом p_ctrl является структура iic_master_instance_ctrl_t. Во время связи I2C в этой структуре будет изменен статус устройства, значение адреса, статус чтения и записи, статус ответа и т. д.

Тип p_cfg — i2c_master_cfg_t. Эта структура используется для представления конфигурации хоста I2C, такой как каналы I2C, номера прерываний, функции приемопередатчика и функции обратного вызова прерываний.

Пользователи могут обратиться к следующему коду, чтобы открыть хост-устройство I2C, которое будет инициализировано внутри:

fsp_err_t err = g_i2c_master2.p_api->open(g_i2c_master2.p_ctrl, g_i2c_master2.p_cfg);
if (FSP_SUCCESS != err)
{
    
    
    printf("%s %d\r\n", __FUNCTION__, __LINE__);
    return;
}
  1. Выключите хост-устройство I2C.

Прототип указателя функции для закрытия устройства I2C выглядит следующим образом:

fsp_err_t (* close)(i2c_master_ctrl_t * const p_ctrl);

Ее параметр p_ctrl указывает на блок управления хостом I2C. Эта функция изменит состояние I2C в блоке управления на выключенное состояние.

  1. I2C функция получения данных

Прототип указателя функции приема данных I2C выглядит следующим образом:

fsp_err_t (* read)(i2c_master_ctrl_t * const p_ctrl, 
                   uint8_t * const p_dest, 
                   uint32_t const bytes,
                   bool const restart);
  • p_ctrl: указывает на блок управления хост-устройством I2C;
  • p_dest: адрес данных назначения (используется для получения данных);
  • байты: количество данных, которые необходимо получить, единица измерения — байты;
  • перезапуск: операция после получения хостом кадра данных, true — после получения кадра данных хост не отправляет сигнал остановки, а отправляет сигнал Start для продолжения передачи, false — после получения кадра данных хост подает сигнал остановки.

Разработчики могут обратиться к следующему коду для чтения данных:

fsp_err_t err = g_i2c_master2.p_api->read(g_i2c_master2.p_ctrl, buf, len, 0);
if (FSP_SUCCESS != err)
{
    
    
    printf("%s %d\r\n", __FUNCTION__, __LINE__);
    return;
}
  1. Функция отправки данных I2C

Прототип указателя функции для ведущего устройства I2C для отправки данных на ведомое устройство выглядит следующим образом:

    fsp_err_t (* write)(i2c_master_ctrl_t * const p_ctrl, 
                        uint8_t * const p_src, 
                        uint32_t const bytes,
                        bool const restart);
  • p_ctrl: выполнить блок управления хост-устройством I2C. Когда хост отправляет данные, он инициирует сигналы запуска, сигналы ответа и т. д. на основе адреса и другой информации блока управления;
  • p_dest: адрес данных назначения (используется для получения данных);
  • байты: количество отправляемых данных в байтах;
  • перезапуск: операция после отправки этого кадра данных: true означает, что сигнал Stop не будет отправлен, но сигнал Start будет отправлен немедленно - это всегда может занять шину I2C, false означает, что сигнал Stop будет отправлен (все будут отправлены). снова побороться за шину I2C);

Разработчики могут обратиться к следующему коду для отправки данных I2C:

fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, tmpbuf, 2, 0);
if (FSP_SUCCESS != err)
{
    
    
    printf("%s %d\r\n", __FUNCTION__, __LINE__);
    return;
}

15.2 Общий эксперимент с сенсорным экраном драйвера I2C

15.2.1 Подключение оборудования

В этой главе используется внешний сенсорный экран, который подключается к материнской плате с помощью кабеля FPC. Принципиальная схема I2C FPC показана ниже:

Используются контакты P409 и P410.

15.2.2 Анализ драйвера GT911

GT911 - это сенсорный чип с емкостными точками касания 5, каналами привода 26 и каналами восприятия 14. Он может одновременно определять точное положение, траекторию движения и область касания в режиме реального времени в пяти точках касания, а также в соответствии с основными управление При необходимости прочтите сенсорную информацию соответствующей точки.

Связь GT911 представляет собой стандартный протокол связи I2C, и хост должен соответствовать стандартному протоколу шины I2C, когда он взаимодействует с GT911 через I2C. Определение адреса ведомого устройства I2C GT911 показано на рисунке ниже:

Он поддерживает два адреса, какой адрес используется, зависит от уровня вывода INT после сброса GT911. Если во время сброса на выводе INT высокий уровень, адрес равен 0x14/0x28/0x29; в противном случае это 0x5D, 0xBA/0xBB.

В экспериментальной схеме в этой главе был выбран адрес 0x14.

GT911 управляется отправкой инструкций, а также чтением и записью данных.Разные инструкции поддерживают разное количество данных: одна инструкция соответствует данным одного регистра, или одна инструкция может соответствовать данным N регистров. Взяв в качестве примера команду чтения данных точки 0x8157, пользователь может непрерывно считывать 7 байтов данных (идентификатор точки касания и информацию о положении касания) после отправки команды 0x8157:

15.2.3 Драйвер GT911

Эксперимент в этой главе просто получает информацию о положении контакта. Для сенсорных устройств, поскольку основным требованием является получение информации о точках касания, эта глава будет абстрагироваться как «сенсорные устройства» и использовать структуру в drv_touch.h для описания этого типа сенсорного устройства:

typedef struct TouchDev{
    
    
    char *name;
    void (*Init)(struct TouchDev *ptDev);
    bool (*Read)(struct TouchDev *ptDev, unsigned short *pX, unsigned short *pY);
}TouchDev, *PTouchDev;

Для этого типа сенсорного устройства операции прикладного уровня включают только: инициализацию и считывание положения касания. Поэтому в структуре TouchDev имеется только два указателя на функции: Init и Read.

Для конкретных чипов сенсорного драйвера необходимо реализовать собственную структуру TouchDev. В этой главе реализуется структура TouchDev в drv_gt911.c, а затем последовательно объясняются ее функции.

  1. функция обратного вызова прерывания

Во время процесса связи I2C следующая передача должна быть завершена после завершения предыдущей передачи.Поэтому необходимо определить, была ли предыдущая передача завершена с помощью события запуска прерывания I2C.Код выглядит следующим образом:

static volatile bool gI2C2TxCplt = false;
static volatile bool gI2C2RxCplt = false;
void i2c2_callback(i2c_master_callback_args_t * p_args)
{
    
    
    switch (p_args->event)
    {
    
    
        case I2C_MASTER_EVENT_TX_COMPLETE:
        {
    
    
            gI2C2TxCplt = true;
            break;
        }
        case I2C_MASTER_EVENT_RX_COMPLETE:
        {
    
    
            gI2C2RxCplt = true;
            break;
        }
        default:
        {
    
    
            gI2C2TxCplt = gI2C2RxCplt = false;
            break;
        }
    }
}
  • Строки 07–11: Если тип события, вызывающего прерывание, является событием завершения отправки, флаг завершения отправки будет установлен в значение true;
  • Строки 12–16: Если тип события, вызывающего прерывание, является событием завершения приема, флаг завершения приема будет установлен в значение true;
  1. Функция ожидания тайм-аута трансивера

В этой главе реализованы две функции ожидания и добавлен механизм таймаута.Код выглядит следующим образом:

static void I2C2WaitTxCplt(void)
{
    
    
    uint16_t wTimeOut = 100;
    while(!gI2C2TxCplt && wTimeOut)
    {
    
    
        HAL_Delay(1);
        wTimeOut--;
    }
    gI2C2TxCplt = false;
}

static void I2C2WaitRxCplt(void)
{
    
    
    uint16_t wTimeOut = 100;
    while(!gI2C2RxCplt && wTimeOut)
    {
    
    
        HAL_Delay(1);
        wTimeOut--;
    }
    gI2C2RxCplt = false;
}
  1. Запись функции регистра GT911

При записи регистра GT911 необходимо отправить адрес регистра и данные регистра. Количество данных может варьироваться.Функция динамически выделяет память для сохранения адреса регистра и данных регистра, а затем отправляет их одновременно. Обратитесь к следующему коду:

static void GT911DrvWriteReg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    
    
    uint8_t regl = (uint8_t)(reg & 0xff);
    uint8_t regh = (uint8_t)(reg>>8);
    uint8_t * write_package = (uint8_t*)malloc((len + 2) * sizeof(uint8_t));
    memcpy(write_package, &regh, 1);
    memcpy(write_package + 1, &regl, 1);
    memcpy(write_package + 2, buf, len);
    fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, write_package, len + 2, 0);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    I2C2WaitTxCplt();
    free(write_package);
}
  • Строки 05–08: динамически распределять пакеты данных в соответствии с длиной входящих данных и упаковывать инструкции и данные так, чтобы их можно было отправить сразу, вызывая функцию записи I2C;
  • Строка 09: вызов функции записи для отправки пакета данных.После отправки данные больше не будут отправляться, поэтому последний параметр restart=0;
  1. Чтение функции регистра GT911

При чтении регистра сначала должен быть отправлен адрес регистра, а затем должны быть считаны данные. код показан ниже:

static void GT911DrvReadReg(uint16_t reg, uint8_t *buf, uint8_t len)
{
    
    
    uint8_t tmpbuf[2];

    tmpbuf[0] = (uint8_t)(reg >> 8);
    tmpbuf[1] = (uint8_t)(reg &0xff);
    fsp_err_t err = g_i2c_master2.p_api->write(g_i2c_master2.p_ctrl, tmpbuf, 2, 0);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    I2C2WaitTxCplt();
    err = g_i2c_master2.p_api->read(g_i2c_master2.p_ctrl, buf, len, 0);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    I2C2WaitRxCplt();
}
  1. Различные функции считывания идентификатора

GT911 имеет множество идентификаторов, которые могут получить пользователи. Если взять в качестве примера производственный идентификатор GT911, он требует, чтобы хост отправил команду регистрации 0x8140 в GT911, а затем прочитал 4 байта идентификационных данных. Код выглядит следующим образом:

static uint32_t GT911DrvReadProductID(void)
{
    
    
    uint32_t id = 0;
    GT911DrvReadReg(GT911_PRODUCT_ID_REG, (uint8_t*)&id ,4);
    return id;
}

Другие идентификаторы также можно реализовать, обратившись к этому методу записи.Проект 1501_i2c_touch в этой главе инкапсулирует эти функции чтения идентификаторов для читателей:

static uint32_t GT911DrvReadProductID(void);
static uint32_t GT911DrvReadVendorID(void);
static uint8_t GT911DrvReadVersion(void);
static uint8_t GT911DrvGetGSTID(void);
  1. Очистить регистр точек

После каждого чтения данных регистра точки касания данные в регистре необходимо очистить, чтобы данные в регистре можно было обновить при следующем касании. Если данные в регистре координат не очищены, при каждом чтении будет получаться фиксированное значение 0x7F.

Адрес очистки регистра координат 0x814E.Пользователю необходимо только записать ноль в этот регистр.Код следующий:

static void GT911DrvClearBuf(void)
{
    
    
    uint8_t data = {
    
    0};
    GT911DrvWriteReg(GT911_CLEARBUF_REG, (uint8_t*)&data, 1);
}
  1. Абстрактный объект устройства с сенсорным экраном GT911

Для сенсорного устройства GT911 эта глава инкапсулирована в соответствии с характеристиками его параметров для представления области касания и точек касания GT911. См. следующий дизайн кода в drv_gt911.h:

typedef enum{
    
    
    TP_ROT_NONE = 0,
    TP_ROT_90,
    TP_ROT_180,
    TP_ROT_270
} TouchRotation_t;

/**用于存放每一个触控点的id,坐标,大小**/
typedef struct TouchPointInfo{
    
    
    unsigned char id;
    unsigned short x;
    unsigned short y;
    unsigned short size;
}TouchPointInfo_t;

/**类结构体**/
typedef struct TouchDrv{
    
    
    unsigned char  ucAddr;
    unsigned short wHeight;
    unsigned short wWidth;
    TouchRotation_t tRotation;
    TouchPointInfo_t tPointsInfo[TOUCH_POINT_TOTAL]; //用于存储五个触控点的坐标
}TouchDrv_t;

В последующем проекте устройство GT911 представлено определением структурной переменной TouchDrv_t:

static struct TouchDrv gTP;
  1. Прочитайте функцию точки касания GT911

Анализируя чтение и запись данных GT911, я использовал в качестве примера чтение данных определенной точки и узнал, что одна точка имеет 7 данных данных. Для GT911 можно получить информацию по 5 точкам, а соответствующий адрес регистра отражается в форме определения макроса в drv_gt911.h:

#define GT_TP1_REG      0X814F      //第一个触摸点数据地址
#define GT_TP2_REG      0X8157      //第二个触摸点数据地址
#define GT_TP3_REG      0X815F      //第三个触摸点数据地址
#define GT_TP4_REG      0X8167      //第四个触摸点数据地址
#define GT_TP5_REG      0X816F      //第五个触摸点数据地址

При каких обстоятельствах нам необходимо считывать информацию о точках? Когда происходит событие касания. А как пользователи узнают, трогали ли GT911? Он представлен регистром:

  • Бит-7:buffer_status, 1 — есть сенсорные данные, ожидающие чтения хостом, 0 — данных нет;
  • Бит-6: большое обнаружение, 1- означает, что затронута большая площадь;
  • Бит-4:HaveKey,1-прикоснулись, 0-не прикоснулись или отпустили касание;
  • Бит-[3:0]: количество точек касания;

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

static bool GT911DrvIsTouched(TouchDrv_t * tp)
{
    
    
    uint8_t touched_state, touch_num, buffer_status;
    touched_state = GT911DrvGetGSTID();
    touch_num = touched_state & 0xf;            //触点数量
    buffer_status = (touched_state >> 7) & 1;   // 帧状态

    if(buffer_status == 1 && (touch_num <= TOUCH_POINT_TOTAL) && (touch_num > 0))
    {
    
    
        uint16_t pointers_regs[TOUCH_POINT_TOTAL] = {
    
    GT_TP1_REG, GT_TP2_REG, GT_TP3_REG, GT_TP4_REG, GT_TP5_REG};
        // 获取每个触控点的坐标值并保存
        for (int i = 0; i < touch_num; ++i)
        {
    
    
            uint8_t point_info_per_size = 7;
            uint8_t * point_info_p = malloc(point_info_per_size * sizeof(uint8_t ));
            GT911DrvReadReg(pointers_regs[i], point_info_p, point_info_per_size);

            tp->tPointsInfo[i].id = point_info_p[0];
            tp->tPointsInfo[i].x = (unsigned short)(point_info_p[1] + (point_info_p[2] << 8));
            tp->tPointsInfo[i].y = (unsigned short)(point_info_p[3] + (point_info_p[4] << 8));
            tp->tPointsInfo[i].size = (unsigned short)(point_info_p[5] + (point_info_p[6] << 8));

            free(point_info_p);

            //旋转方向
            uint16_t temp;
            switch (tp->tRotation)
            {
    
    
                case TP_ROT_NONE:
                    tp->tPointsInfo[i].x = tp->wWidth - tp->tPointsInfo[i].x;
                    tp->tPointsInfo[i].y = tp->wHeight - tp->tPointsInfo[i].y;
                    break;
                case TP_ROT_270:
                    temp = tp->tPointsInfo[i].x;
                    tp->tPointsInfo[i].x = tp->wWidth - tp->tPointsInfo[i].y;
                    tp->tPointsInfo[i].y = temp;
                    break;
                case TP_ROT_180:
//                    tp->tPointsInfo[i].x = tp->tPointsInfo[i].x;
//                    tp->tPointsInfo[i].y = tp->tPointsInfo[i].y;
                    break;
                case TP_ROT_90:
                    temp = tp->tPointsInfo[i].x;
                    tp->tPointsInfo[i].x = tp->tPointsInfo[i].y;
                    tp->tPointsInfo[i].y = tp->wHeight - temp;
                    break;
                default:
                    break;
            }
        }
        GT911DrvClearBuf();
        return true;
    }
    //必须给GT911_POINT_INFO缓冲区置0,不然读取的数据一直为128!!!!
    GT911DrvClearBuf();
    return false;
}

Кроме того, чтобы соответствовать ранее абстрактному сенсорному устройству (TouchDev), функция чтения должна быть инкапсулирована на этой основе:

static bool GT911DrvRead(struct TouchDev *ptDev, unsigned short *pX, unsigned short *pY)
{
    
    
    if(NULL == ptDev->name) return false;
    if(GT911DrvIsTouched(&gTP))
    {
    
    
        *pX = gTP.tPointsInfo[0].x;
        *pY = gTP.tPointsInfo[0].y;
        return true;
    }

    return false;
}
  1. Функция инициализации GT911

Эксперименты в этой главе не привели к более тонким настройкам GT911, поэтому его регистры не были изменены.

Функция инициализации в этой главе только инициализирует устройство I2C и считывает идентификатор и диапазон касания GT911. См. следующий код:

static void GT911DrvInit(struct TouchDev *ptDev)
{
    
    
    if(NULL == ptDev->name) return;
    uint8_t buf[4];
    gTP.ucAddr = (uint8_t)g_i2c_master2.p_cfg->slave;
    gTP.tRotation = TP_ROT_NONE;
    /* 初始化I2C驱动 */
    fsp_err_t err = g_i2c_master2.p_api->open(g_i2c_master2.p_ctrl, g_i2c_master2.p_cfg);
    if (FSP_SUCCESS != err)
    {
    
    
        printf("%s %d\r\n", __FUNCTION__, __LINE__);
        return;
    }
    /* 读ID */
    uint32_t nVendorID = GT911DrvReadVendorID();
    printf("gt911 vendor id: 0x%.4x\r\n", (int)nVendorID);
    uint32_t nProductID = GT911DrvReadProductID();
    printf("gt911 product id: 0x%.4x\r\n", (int)nProductID);
    uint8_t nVersion = GT911DrvReadVersion();
    printf("version = 0x%x\r\n", nVersion);
    GT911DrvReadReg(0x8048, buf, 2);
    gTP.wWidth = (unsigned short)((buf[1] << 8) | buf[0]);
    GT911DrvReadReg(0x804A, buf, 2);
    gTP.wHeight = (unsigned short)((buf[1] << 8) | buf[0]);
}
  1. Регистрация и приобретение сенсорных устройств

При объектно-ориентированном мышлении создается структура TouchDev gTouchDev, код следующий:

static struct TouchDev gTouchDev = {
    
    
                                    .name = "GT911",
                                    .Init = GT911DrvInit,
                                    .Read = GT911DrvRead
};

Затем верните это устройство в верхнее приложение с помощью функции:

struct TouchDev* TouchDevGet(void)
{
    
    
    return &gTouchDev;
}

15.2.4 Процедура испытания

app_test.c — тестовая программа, она распечатывает информацию о точках касания, код следующий:

void TouchAppTest(void)
{
    
    
    TouchDev *ptDev = TouchDevGet();
    if(NULL == ptDev)
    {
    
    
        printf("Error. Not Found Touch Device!\r\n");
        return;
    }
    ptDev->Init(ptDev);
    uint16_t x = 0, y = 0;
    while(1)
    {
    
    
        if(ptDev->Read(ptDev, &x, &y) == true)
        {
    
    
            printf("Touch-Position: (%d,%d)\r\n", x, y);
        }
    }
}

15.2.5 Компьютерный эксперимент

В функции hal_entry() в hal_entry.c инициализируйте тактовый таймер, инициализируйте последовательный порт отладки, а затем вызовите функцию TouchAppTest для тестирования.

При прикосновении к экрану помощник последовательного порта распечатает информацию о координатах точки, как показано на следующем рисунке:


Конец этой главы

Supongo que te gusta

Origin blog.csdn.net/qq_35181236/article/details/132789542
Recomendado
Clasificación