
Современные компьютерные мыши, тачпады, сенсорные панели и мобильная робототехника, обязаны своей точностью и отзывчивостью миниатюрным системам движения. Одним из таких является PAT9125 — это высокоточный двухосевой оптический датчик, способный с невероятной точностью отслеживать перемещение по различным поверхностям.
PAT9125 представляет собой интеллектуальный датчик, в основе которого — микроскопическая камера и инфракрасная подсветка. Он реализует текстуру поверхности под собой, фиксируя мельчайшие смещения и на основе полученных данных изображений рассчитывает вектор движения. Благодаря высокой кадровой частоте, датчик способен точно отслеживать даже быстрое перемещение, сохраняя стабильность и минимальную задержку.
Основные характеристики:
-
Количество осей: 2 (X и Y);
-
Разрешение: до 1200 CPI (Counts Per Inch);
-
Интерфейсы связи: I2C и SPI;
-
Скорость кадров: до 2300 FPS (кадров в секунду);
-
Рабочее расстояние: около 1.2мм ± 0.2мм от поверхности.
Применение и обработка данных
Считывание данных с датчика по I2C и SPI — интерфейсам, дает доступ к приращениям по осям X и Y. Эти значения можно использовать для расчета абсолютного перемещения, а при необходимости — перевести в сантиметры или метры, учитывая установленное разрешение (CPI), Таким образом, PAT9125 может эффективно выполнять роль оптического энкодера, позволяя измерять расстояние, путь и даже направление движения.
Пример схемы электрической принципиальной, подключение к микроконтроллеру STM32F103 по интерфейсу I2C.
|
Список регистров |
|||||
|
|
|
|
Значение по умолчанию |
Описание |
|
|
|
|
|
|
|
|
|
|
Product_ID2 |
RO |
0x91 |
Верхние 4 бита: идентификатор продукта (PID [3:0]) |
|
|
|
Motion_Status |
RO |
— |
Информация о статусе движения |
|
|
|
Delta_X_Lo |
RO |
— |
Смещение по оси X, 8-битное число в формате дополнительного кода |
|
|
|
Delta_Y_Lo |
RO |
— |
Смещение по оси Y, 8-битное число в формате дополнительного кода |
|
|
|
Operation_Mode |
R/W |
0xA0 |
Режим работы |
|
|
|
Configuration |
R/W |
0x17 |
Программное отключение питания и сброс |
|
|
|
Write_Protect |
R/W |
0x00 |
Защита от записи для предотвращения случайной перезаписи регистров |
|
|
|
Sleep1 |
R/W |
0x77 |
Конфигурация режима сна 1 |
|
|
|
Sleep2 |
R/W |
0x10 |
Конфигурация режима сна 2 |
|
|
|
RES_X |
R/W |
0x14 |
Настройка разрешения (CPI) по оси X |
|
|
|
RES_Y |
R/W |
0x14 |
Настройка разрешения (CPI) по оси Y |
|
|
|
Delta_XY_Hi |
RO |
— |
Старшие 4 бита данных смещения по X и Y для 12-битного формата |
|
|
|
Shutter |
RO |
— |
Индекс времени срабатывания затвора (LASER shutter) |
|
|
|
Frame_Avg |
RO |
0 |
Средняя яркость кадра |
|
|
|
Orientation |
R/W |
0x04 |
Настройка ориентации чипа |
|
Реализация программного кода (Настройка, прием данных, конвертация) PAT9125 и микроконтроллера STM32F103.
Настройка в CubeIDE
Выберем I2C и выставим параметры:
-
I2C Speed Mode: Standard Mode;
-
I2C Speed Frequency(KHz): 100.

Создание переменных и определение макросов
#define PAT9125_I2C_ADDR (0x79<<1) // Адрес датчика (если ID_SEL = NC) (0x79<<1) (0x73 << 1) #define REG_PRODUCT_ID 0x00 // Регистр идентификатора продукта #define REG_MOTION_BURST 0x02 // Регистр для чтения движения Режим BURST чтения #define REG_DELTA_X_LO 0x03 // 8-битный формат #define REG_DELTA_Y_LO 0x04 // 8-битный формат #define REG_DELTA_XY_HI 0x12 // 12-битный формат #define REG_X_CPI 0x0D // регистр CPI по X #define REG_Y_CPI 0x0E // регистр CPI по Y #define NOISE_THRESHOLD_CM 0.01f // Фильтр шума (1 мм) #define CPI 700.0f // Разрешение датчика (Counts Per Inch) 720 #define INCH_TO_MM 25.4f // 1 дюйм = 25.4 мм #define INCH_TO_CM 2.54f // 1 дюйм = 2.54 см #define USE_12BIT_FORMAT // 12-битный формат #define I2C_RX_BUFFER_SIZE 16//Основной буфер для данных Нужно 5 байт: [MOTION, Delta_X_LO, Delta_Y_LO, SQUAL, Delta_XY_HI] uint8_t i2c_rx_buffer[I2C_RX_BUFFER_SIZE]={0,}; int32_t total_x = 0; // отсчеты по х int32_t total_y = 0; // отсчеты по y int32_t motion_flag =0; static uint16_t delta_x_lo =0; static uint16_t delta_y_lo =0; static uint16_t delta_xy_hi =0; float delta_x_cm = 0.0f; //Данные по x в см float delta_y_cm = 0.0f; //Данные по y в см float flow_vel_x_cop_ab = 0.0f;//Данные по x в мм float flow_vel_y_cop_ab = 0.0f;//Данные по y в мм float beta_rad = 0.0f; //Угловая скорость в радианах
Метод PAT9125_Init
В данном методе производится инициализация датчика:
-
Считывание ID и проверка доступности устройства;
-
Установление разрешения CPI, через метод PAT9125_SetCpi().
void PAT9125_Init() { uint8_t product_id = PAT9125_ReadReg(REG_PRODUCT_ID); if (product_id != 0x31) { // Ожидаемый ID датчика printf("%s", message_test_1); } else { /* * Значение 0x7F (127) ≈ 500 CPI (базовое значение). Значение 0xBC (188) ≈ 1000 CPI. Значение 0xDE (222) ≈ 1500 CPI. Значение 0xFF (255) ≈ 2000 CPI (максимальное).*/ PAT9125_SetCPI(0xBC);// Установлено 1000 CPI printf("%s", message_test_2); } }
Метод PAT9125_SetCPI
Данный метод, устанавливает заданный CPI в регистры X[0x0D] и Y[0x0E], считывает один байт из регистра датчика PAT9125 по I2C, (выставлено 1000 CPI, что эквивалентно 0.0254 мм/отсчет).
void PAT9125_SetCPI(uint16_t cpi_value){ uint8_t data[2]; // Устанавливаем X-CPI data[0] = REG_X_CPI; data[1] = cpi_value; HAL_I2C_Master_Transmit(&hi2c1, PAT9125_I2C_ADDR, data, 2, HAL_MAX_DELAY); // Устанавливаем Y-CPI data[0] = REG_Y_CPI; HAL_I2C_Master_Transmit(&hi2c1, PAT9125_I2C_ADDR, data, 2, HAL_MAX_DELAY); }
Метод PAT9125_ReadReg
Считывает один байт из регистра датчика PAT9125 по I2C (используется для чтения текущих значений (идентификатора устройства, данных движения и т.д.)).
uint8_t PAT9125_ReadReg(uint8_t reg) { uint8_t data = 0;// от функции PAT9125_ReadReg HAL_I2C_Master_Transmit(&hi2c1, PAT9125_I2C_ADDR, ®, 1, HAL_MAX_DELAY); HAL_I2C_Master_Receive(&hi2c1, PAT9125_I2C_ADDR, &data, 1, HAL_MAX_DELAY); return data; }
Метод PAT9125_WriteReg
Данный метод, записывает значение value в регистр reg датчика PAT9125, используется для настройки параметров датчика, например (Установка CPI-разрешения).
void PAT9125_WriteReg(uint8_t reg, uint8_t value) { uint8_t data[2] = {reg, value}; HAL_I2C_Master_Transmit(&hi2c1, PAT9125_I2C_ADDR, data, 2, HAL_MAX_DELAY); }
Метод PAT9125_ReadMotion
Данный метод, считывает информацию о перемещении по осям X и Y из датчика (режим Burst Read), так же обновляет общее смещение total_x, total_y, и вызывает функцию обновления общего пройденного пути, простыми словами (используется каждый раз, когда нужно получить новые данные движения с датчика).
Поддерживает форматы:
-
8-битный формат и 12-битный (определяется макросом USE_12BIT_FORMAT), для работы в 8-битном формате, просто закоментируйте макрос(#define USE_12BIT_FORMAT), в режиме 12-бит, данные собираются из старших и младших байтов и расширяются до знакового значения.
void PAT9125_ReadMotion(int16_t *delta_x, int16_t *delta_y) { uint8_t reg = REG_MOTION_BURST; // Отправляем команду BURST READ if (HAL_I2C_Master_Transmit(&hi2c1, PAT9125_I2C_ADDR, ®, 1, HAL_MAX_DELAY) != HAL_OK) { printf("Ошибка передачи I2C!\n"); return; } // Читаем сразу 5 байт данных (MOTION, Delta_X_LO, Delta_Y_LO, SQUAL, Delta_XY_HI) if (HAL_I2C_Master_Receive(&hi2c1, PAT9125_I2C_ADDR, i2c_rx_buffer, I2C_RX_BUFFER_SIZE, HAL_MAX_DELAY) != HAL_OK) { printf("Ошибка приёма I2C!\n"); return; } delta_x_lo = i2c_rx_buffer[1]; // Delta_X (младший байт) delta_y_lo = i2c_rx_buffer[2]; // Delta_Y (младший байт) delta_xy_hi = i2c_rx_buffer[4]; // Delta_XY_Hi (старшие 4 бита X и Y) #ifdef USE_12BIT_FORMAT // Если используем 12-битный формат delta_xy_hi = PAT9125_ReadReg(REG_DELTA_XY_HI); // Формируем 12-битные значения *delta_x = (int16_t)(((delta_xy_hi & 0xF0) << 4) | delta_x_lo); *delta_y = (int16_t)(((delta_xy_hi & 0x0F) << 8) | delta_y_lo); // Расширяем знаковый бит для 12-битного числа (если отрицательное) if (*delta_x & 0x0800) *delta_x |= 0xF000; if (*delta_y & 0x0800) *delta_y |= 0xF000; #else // 8-битный формат (если нужно) *delta_x = (int8_t)delta_x_lo; *delta_y = (int8_t)delta_y_lo; #endif total_x += *delta_x; total_y += *delta_y; UpdateTotalDistance(total_x,total_y); }
Метод ProcessMotionData
Данный метод является основным обработчиком движения, вызывает метод PAT9125_ReadMotion, обрабатывает данные и формирует строки для вывода по UART.
void ProcessMotionData(void) { HAL_Delay(1);//чтобы HAL_GetTick() не выдавал ноль uint32_t ms = HAL_GetTick(); PAT9125_ReadMotion(&dx, &dy); /** Данные после выполнения метода PAT9125_ReadMotion * total_x - Отсчеты по x * total_y - Отсчеты по y * delta_x_cm - данные по x в см * delta_x_cm - данные по y в см * total_distance_cm - общий пройденный путь в см */ //-------------В данном куске кода работа предназначена для CartScan--------------- float time_sec = ms/1000.0f;//перевод в секунды flow_vel_x_cop_ab = delta_x_cm * 10.0f; flow_vel_y_cop_ab = delta_y_cm * 10.0f; position_x_m_cop_long = (long)roundf(flow_vel_x_cop_ab); position_y_m_cop_long = (long)roundf(flow_vel_y_cop_ab); total_path_m_cop = total_distance_cm*10.0f; total_path_m_cop_long = (long)roundf(total_path_m_cop); beta_rad = calculateBetaRadians(delta_x_cm, delta_y_cm)*10.0f;//получение угла в радианах }
Метод UpdateTotalDistance
Данный метод вычисляет прирост пройденного пути на основе новых данных смещения и обновляет общий путь total_distance_cm
void UpdateTotalDistance(int32_t delta_x, int32_t delta_y) { // Переводим X и Y в см delta_x_cm = convert_to_cm(delta_x, CPI); delta_y_cm = convert_to_cm(delta_y, CPI); // Фильтруем шум (игнорируем слишком маленькие изменения) if (fabsf(delta_x_cm) < NOISE_THRESHOLD_CM) delta_x_cm = 0; if (fabsf(delta_y_cm) < NOISE_THRESHOLD_CM) delta_y_cm = 0; // Проверяем, изменились ли данные bool is_moving = (delta_x != last_delta_x || delta_y != last_delta_y); // Вычисляем пройденный путь (Только если датчик двигается) if (is_moving) { float delta_distance = sqrtf(delta_x_cm * delta_x_cm + delta_y_cm * delta_y_cm); total_distance_cm += delta_distance/720.0f; } last_delta_x = delta_x; last_delta_y = delta_y; }
Метод convert_to_cm
Преобразует значение смещения из отсчетов в сантиметры, используя установленное разрешение CPI
float convert_to_cm(int32_t delta, float cpi) { return (float)delta * INCH_TO_CM / cpi; }
Метод calculateBetaRadians
Данный метод вычисляет угол направления движения по данным X и Y
float calculateBetaRadians(float flow_vel_x, float flow_vel_y) { return atan2(flow_vel_y, flow_vel_x); // Угол в радианах }
Главный метод
Запускается в главном цикле while.
void proj_main() { HAL_Delay(1);//чтобы HAL_GetTick() не выдавал ноль PAT9125_Init(); while (1){ ProcessMotionData(); }//while (1) }
Итоговый вывод
Это полноценный драйвер + обработчик данных с датчика PAT9125, включающий:
-
Считывание и обработку данных о движении;
-
Перевод в физические единицы (см, мм, радианы);
-
Калибровка чувствительности
В целом, PAT9125 — это пример того, как миниатюрные технологии могут обеспечить высочайшую точность в системах, где важна каждая микронная деталь, благодаря своей компактности, энергоэффективности и простоте интеграции, он становится идеальным выбором для современных устройств ввода и мобильных систем позиционирования.
Если статья показалась Вам интересной, буду рад выпустить для Вас еще множество статей расследований по всевозможным видам устройств, так что, если не хотите их пропустить – буду благодарен за подписку на мой ТГ-канал: https://t.me/ChipCraft.
ссылка на оригинал статьи https://habr.com/ru/articles/935020/
Добавить комментарий