Как стать автором
Поиск
Написать публикацию
Обновить

Оптический датчик PAT9125

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров2.3K

Современные компьютерные мыши, тачпады, сенсорные панели и мобильная робототехника, обязаны своей точностью и отзывчивостью миниатюрным системам движения. Одним из таких является 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.

Список регистров

Адрес

Имя регистра

Доступ

Значение по умолчанию

Описание

0x00

Product_ID1

RO

0x31

Идентификатор продукта (биты [11:4])

0x01

Product_ID2

RO

0x91

Верхние 4 бита: идентификатор продукта (PID [3:0])
Нижние 4 бита: версия продукта (VID [3:0])

0x02

Motion_Status

RO

-

Информация о статусе движения

0x03

Delta_X_Lo

RO

-

Смещение по оси X, 8-битное число в формате дополнительного кода

0x04

Delta_Y_Lo

RO

-

Смещение по оси Y, 8-битное число в формате дополнительного кода

0x05

Operation_Mode

R/W

0xA0

Режим работы

0x06

Configuration

R/W

0x17

Программное отключение питания и сброс

0x09

Write_Protect

R/W

0x00

Защита от записи для предотвращения случайной перезаписи регистров

0x0A

Sleep1

R/W

0x77

Конфигурация режима сна 1

0x0B

Sleep2

R/W

0x10

Конфигурация режима сна 2

0x0D

RES_X

R/W

0x14

Настройка разрешения (CPI) по оси X

0x0E

RES_Y

R/W

0x14

Настройка разрешения (CPI) по оси Y

0x12

Delta_XY_Hi

RO

-

Старшие 4 бита данных смещения по X и Y для 12-битного формата
X = {Hi[7:4], X_Lo}
Y = {Hi[3:0], Y_Lo}

0x14

Shutter

RO

-

Индекс времени срабатывания затвора (LASER shutter)

0x17

Frame_Avg

RO

0

Средняя яркость кадра

0x19

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, &reg, 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, &reg, 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.

Теги:
Хабы:
+5
Комментарии9

Публикации

Ближайшие события