这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【DIY手势翻页笔】手势翻页笔-过程贴:课程二手势模块PAJ7620U2数据的实

共3条 1/1 1 跳转至

【DIY手势翻页笔】手势翻页笔-过程贴:课程二手势模块PAJ7620U2数据的实时读取

菜鸟
2024-06-30 21:19:45     打赏

一:模块资料介绍:PAJ7620U2 Gesture Sensor是一款基于PAJ7620U2的手势识别模块,可直接识别9种基本手势,支持I2C接口,兼容3.3V/5V电平。这里为了方式调试,我使用的是STM32硬件的IIC驱动代码,也加深了自己对IIC通讯的理解;

模块资料:

电源电压 : 3.3V/5V

工作原理:光学数组式环境亮度传感检测

通讯接口:I²C 接口,400Khz(Max)

识别速度:240Hz

工作环境光:<100K Lux(抗灯光干扰)

有效探测距离:5~15cm

检测角度范围:60°~180°

手势识别种类:内置 9 个手势类型:(上、下、左、右、前、后、顺时针旋转、逆时针旋转、挥动)

功耗:3~10mA(待机功耗电流 15u)

PAJ7620U2传感器的工作原理

 3.1.png

我们可以看到PAJ7620U2传感器内部自带 LED 驱动器(可发射红外线信号),内置有传感器感应阵列、目标信息提取阵列和手势识别阵列。另外,PAJ7620U2作为一种光学数组式传感器,其内置LED驱动器集成了环境光和光源抑制滤波器,模块基本不受环境光干扰。

红外LED手势识别原理:传感器工作时通过内部 LED 驱动器,驱动红外 LED 向外发射红外线信号,当传感器阵列在有效的距离中探测到物体时,目标信息提取阵列会对探测目标进行特征原始数据的获取,采集到的数据被保存在寄存器中,同时手势识别阵列会对原始数据进行识别处理,最后将手势结果存到寄存器中。

根据 PAJ7620U2传感器数据手册,用户可通过I²C接口总线采集信号并迅速识别出UP、Down、Right、Left等9种常用手势。另外PAJ7620U2还提供内置的接近检测功能,用于检测物体的接近或离开。

二:学习,了解IIC通讯

2.1:硬件连接方式:I²C的两根线:SCL时钟线和SDA数据线。

SCL时钟线:是为整个通信过程提供了时钟信号

SDA数据线:在每一个周期里发送0或者1,用这些0和1传输数据

软件传输:

数据线SDA以时钟线SCL作为参照。

开始信号:SCL为高电平时,SDA由高电平向低电平跳变时,开始传输数据

结束信号:SCL为高电平时,SDA由低电平向高电平跳变时,停止传输数据

应答信号:接收数据的IC 在接收完8个bit的数据之后,返回应答ack指令,表示数据已被签收。

三:实际硬件连接

1脚  GND  供电负极

2脚 VCC  供电正极 这里我设计的是5V

3脚 SDA  IIC的数据线   PB6    

4脚 SCL  IIC的时钟线      PB7 

 

电路图:

 3.2.png

 

STM32cube的配置图:

 


 

 

然后配置好之后,点击生成软件代码即可。

 

查看生成的IIC底层驱动是否正确:

/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
I2C_HandleTypeDef hi2c1;
 
/* I2C1 init function */
void MX_I2C1_Init(void)
{
 
  /* USER CODE BEGIN I2C1_Init 0 */
 
  /* USER CODE END I2C1_Init 0 */
 
  /* USER CODE BEGIN I2C1_Init 1 */
 
  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x60808CD3;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Analogue filter
  */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Digital filter
  */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */
 
  /* USER CODE END I2C1_Init 2 */
 
}
 
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */
 
  /* USER CODE END I2C1_MspInit 0 */
 
  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
    PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */
 
  /* USER CODE END I2C1_MspInit 1 */
  }
}
 
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
 
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */
 
  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();
 
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
 
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);
 
  /* USER CODE BEGIN I2C1_MspDeInit 1 */
 
  /* USER CODE END I2C1_MspDeInit 1 */
  }
}


确保配置引脚与实际接线保持一致i,这里我设置的IIC的通讯速率是100KHZ

手势模块驱动函数如下:这里我封装到了一个c文件里面,方便再次移植;

 

/*
GESTURE.c   
手势模块的底层驱动部分
功能:硬件IIC读取PAJ7602的当前状态
建立时间:2024.06.26     赵瑞聪    
适用CPU:STM32H503RB  编译器:KEIL5.38a


参考资料:
1 https://www.digikey.cn/zh/products/detail/seeed-technology-co-ltd/101020083/5775185 
2 https://www.seeedstudio.com/Grove-Gesture-PAJ7620U2.html
(文末附件中有主芯片手册)
3 PAJ7620U2手册:
https://img.dfrobot.com.cn/wiki/none/b1d7ac88927f5ffedea5a0ecf107188c.pdf
4 PAJ7620U2中文翻译:
https://blog.csdn.net/weixin_36590806/article/details/124805530 
5 参考驱动代码:
https://gitee.com/zhagyuji/stm32f4_paj7620/tree/master/OLED/PAJ7620
6 官方驱动代码库:
https://gitee.com/RT-Thread-Mirror/Gesture_PAJ7620
*/
#include "Gesture.h"
#include "paj7620.h"
#include <stdio.h>
#include <string.h>
#include "stdlib.h"
#include <stdarg.h> 

/*定义蜂鸣器、双路继电器的输出状态控制部分,直接操作对应IO口*/
#define BEEPON    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);
#define BEEPOFF   HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
#define JDQ1ON    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET);
#define JDQ1OFF   HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET);
#define JDQ2ON    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
#define JDQ2OFF   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);

extern I2C_HandleTypeDef hi2c1;

GestureData gesture;
ProximityData proximity;

GestureData gesture_key;
//初始化
const unsigned char initRegisterArray[][2] = {
	// BANK 0
	{0xEF, 0x00},
	{0x37, 0x07},
	{0x38, 0x17},
	{0x39, 0x06},
	{0x42, 0x01},
	{0x46, 0x2D},
	{0x47, 0x0F},
	{0x48, 0x3C},
	{0x49, 0x00},
	{0x4A, 0x1E},
	{0x4C, 0x20},
	{0x51, 0x10},
	{0x5E, 0x10},
	{0x60, 0x27},
	{0x80, 0x42},
	{0x81, 0x44},
	{0x82, 0x04},
	{0x8B, 0x01},
	{0x90, 0x06},
	{0x95, 0x0A},
	{0x96, 0x0C},
	{0x97, 0x05},
	{0x9A, 0x14},
	{0x9C, 0x3F},
	{0xA5, 0x19},
	{0xCC, 0x19},
	{0xCD, 0x0B},
	{0xCE, 0x13},
	{0xCF, 0x64},
	{0xD0, 0x21},
	// BANK 1
	{0xEF, 0x01},
	{0x02, 0x0F},
	{0x03, 0x10},
	{0x04, 0x02},
	{0x25, 0x01},
	{0x27, 0x39},
	{0x28, 0x7F},
	{0x29, 0x08},
	{0x3E, 0xFF},
	{0x5E, 0x3D},
	{0x65, 0x96},
	{0x67, 0x97},
	{0x69, 0xCD},
	{0x6A, 0x01},
	{0x6D, 0x2C},
	{0x6E, 0x01},
	{0x72, 0x01},
	{0x73, 0x35},
	{0x77, 0x01},
	{0xEF, 0x00},
};
#define INIT_REG_ARRAY_SIZE (sizeof(initRegisterArray) / sizeof(initRegisterArray[0]))

#define GESTURE_SIZE sizeof(gesture_arry) / 2
//手势识别初始化数组
const unsigned char gesture_arry[][2] = {

	{0xEF, 0x00},
	{0x41, 0x00},
	{0x42, 0x00},
	{0xEF, 0x00},
	{0x48, 0x3C},
	{0x49, 0x00},
	{0x51, 0x10},
	{0x83, 0x20},
	{0x9F, 0xF9},
	{0xEF, 0x01},
	{0x01, 0x1E},
	{0x02, 0x0F},
	{0x03, 0x10},
	{0x04, 0x02},
	{0x41, 0x40},
	{0x43, 0x30},
	{0x65, 0x96},
	{0x66, 0x00},
	{0x67, 0x97},
	{0x68, 0x01},
	{0x69, 0xCD},
	{0x6A, 0x01},
	{0x6B, 0xB0},
	{0x6C, 0x04},
	{0x6D, 0x2C},
	{0x6E, 0x01},
	{0x74, 0x00},
	{0xEF, 0x00},
	{0x41, 0xFF},
	{0x42, 0x01},

};

#define PROXIM_SIZE sizeof(proximity_arry) / 2
//接近检测初始化数组
const unsigned char proximity_arry[][2] = {

	{0xEF, 0x00},
	{0x41, 0x00},
	{0x42, 0x00},
	{0x48, 0x3C},
	{0x49, 0x00},
	{0x51, 0x13},
	{0x83, 0x20},
	{0x84, 0x20},
	{0x85, 0x00},
	{0x86, 0x10},
	{0x87, 0x00},
	{0x88, 0x05},
	{0x89, 0x18},
	{0x8A, 0x10},
	{0x9f, 0xf8},
	{0x69, 0x96},
	{0x6A, 0x02},
	{0xEF, 0x01},
	{0x01, 0x1E},
	{0x02, 0x0F},
	{0x03, 0x10},
	{0x04, 0x02},
	{0x41, 0x50},
	{0x43, 0x34},
	{0x65, 0xCE},
	{0x66, 0x0B},
	{0x67, 0xCE},
	{0x68, 0x0B},
	{0x69, 0xE9},
	{0x6A, 0x05},
	{0x6B, 0x50},
	{0x6C, 0xC3},
	{0x6D, 0x50},
	{0x6E, 0xC3},
	{0x74, 0x05},

};
/**************************************************************************************************
  * 函数功能: static unsigned char PAJ7620_send_byte(unsigned char dta)
  * 输入参数: data
  * 返 回 值: 1:正常 0:异常
  * 说    明: 通过IIC向模块发送一个字节
  *
***************************************************************************************************/
static unsigned char PAJ7620_send_byte(unsigned char data)
{
	
	if (HAL_I2C_Master_Transmit(&hi2c1, PAJ7620_I2C_ADDR, &data, 1, 100) != HAL_OK)
	{
		return 0;
	}
	return 1;
	
}
/**************************************************************************************************
  * 函数功能: static unsigned char PAJ7620_send_byteS(unsigned char *data, unsigned char length)
  * 输入参数: data  length
  * 返 回 值: 1:正常 0:异常
	* 说    明: 通过IIC向模块发送 长度为length 的数据
  *
***************************************************************************************************/
static unsigned char PAJ7620_send_byteS(unsigned char *data, unsigned char length)
{
	if (HAL_I2C_Master_Transmit(&hi2c1, PAJ7620_I2C_ADDR, data, length, 100) != HAL_OK)
	{
		return 0;
	}
	return 1;
}
/**************************************************************************************************
  * 函数功能: static unsigned char PAJ7620_read_byteS(unsigned char *data, unsigned char length)
  * 输入参数: data  length
  * 返 回 值: 1:正常 0:异常
	* 说    明: 通过IIC向模块读取 长度为length 的数据
  *
***************************************************************************************************/
static unsigned char PAJ7620_read_byteS(unsigned char *data, unsigned char length)
{

	/* Do the read */

	if (HAL_I2C_Master_Receive(&hi2c1, PAJ7620_I2C_ADDR, data, length, 100) != HAL_OK)
	{
		return 0;
	}
	return 1;
}

/**************************************************************************************************
  * 函数功能: static void writeReg(uint8_t addr, uint8_t value)
  * 输入参数: addr  value
  * 返 回 值: 无
	* 说    明: 通过 IIC 向模块的指定寄存器写入数据
  *
***************************************************************************************************/
static void writeReg(uint8_t addr, uint8_t value)
{
	unsigned char dta[2] = {0};
	dta[0] = addr;
	dta[1] = value;
	PAJ7620_send_byteS(dta, 2);
}

/**************************************************************************************************
  * 函数功能: static unsigned char readRegs(uint8_t addr, uint8_t *values, int size)
  * 输入参数: addr  values  size
  * 返 回 值: 无
	* 说    明: 通过 IIC 向模块的读取 指定寄存器及其该寄存器的之后的数据长度
  *
***************************************************************************************************/
static unsigned char readRegs(uint8_t addr, uint8_t *values, int size)
{
	if (PAJ7620_send_byte(addr) != 1)
		return 0;
	if (PAJ7620_read_byteS(values, size) != 1)
		return 0;
	return 1;
}
/**************************************************************************************************
  * 函数功能: static unsigned char readReg(uint8_t addr)
  * 输入参数: addr  
  * 返 回 值: 无
	* 说    明: 通过 IIC 向模块的读取 指定寄存器的数据
  *
***************************************************************************************************/
static unsigned char readReg(uint8_t addr)
{
	uint8_t values;
	readRegs(addr, &values, 1);
	return values;
}


/**************************************************************************************************
  * 函数功能: void paj7620u2_selectBank(bank_e bank)
  * 输入参数: bank  
  * 返 回 值: 无
	* 说    明: 通过 IIC 向模块的读取 指定寄存器的数据
  *
***************************************************************************************************/
void paj7620u2_selectBank(bank_e bank)
{
	switch (bank)
	{
	case BANK0:
		writeReg(PAJ_REGITER_BANK_SEL, PAJ_BANK0);
		break; // BANK0
	case BANK1:
		writeReg(PAJ_REGITER_BANK_SEL, PAJ_BANK1);
		break; // BANK1
	}
}

void GS_WakeUp()
{
	PAJ7620_send_byte(0);
}
/**************************************************************************************************
  * 函数功能: unsigned char paj7620u2_wakeup()
  * 输入参数: bank  
  * 返 回 值: 无
	* 说    明: 唤醒手势模块
  *
***************************************************************************************************/
unsigned char paj7620u2_wakeup()
{
	unsigned char data1 = 0x0a;
	unsigned char data2 = 0x0a;
	GS_WakeUp();				 // wake PAJ7620U2
	HAL_Delay(5);				 // wake time >400us
	GS_WakeUp();				 // wake PAJ7620U2
	HAL_Delay(5);				 // wake time>400us
	paj7620u2_selectBank(BANK0); //进入BANK0
	/* check ID */
	data1 = readReg(0x00); //读取id
	data2 = readReg(0x01); //读取id
	if ((data2 != 0x76) || (data1 != 0x20))
		return 0;
	return 1;
}
/**************************************************************************************************
  * 函数功能: unsigned char PAJ7620u2_init(void)
  * 输入参数:   
  * 返 回 值: 无
	* 说    明: 模块初始化
  *
***************************************************************************************************/
unsigned char PAJ7620u2_init(void)
{
	unsigned char status;
	HAL_Delay(10);
	status = paj7620u2_wakeup(); //唤醒PAJ7620U2
	if (!status)
		return 0;
	paj7620u2_selectBank(BANK0); // enter BANK0
	HAL_Delay(50);

	/* Load the registers data */
	for (uint8_t i = 0; i < INIT_REG_ARRAY_SIZE; i++)
		writeReg(initRegisterArray[i][0], initRegisterArray[i][1]); // init PAJ7620U2
	paj7620u2_selectBank(BANK0);									// enter BANK0
	return 1;
}


/**************************************************************************************************
  * 函数功能: void Gesture_Init(void)
  * 输入参数:   
  * 返 回 值: 无
	* 说    明: 模块初始化
  *
***************************************************************************************************/
void Gesture_Init(void)
{
	unsigned char i;
	paj7620u2_selectBank(BANK0); //
	for (i = 0; i < GESTURE_SIZE; i++)
	{
		writeReg(gesture_arry[i][0], gesture_arry[i][1]);
	}
	paj7620u2_selectBank(BANK0); //

	memset(&gesture, 0, sizeof(GestureData));
}

/**************************************************************************************************
  * 函数功能: void Gesture_Init(void)
  * 输入参数:   
  * 返 回 值: 无
	* 说    明: 模块初始化
  *
***************************************************************************************************/

void PAJ7620_Init(void)
{
	while (!PAJ7620u2_init()) // PAJ7620U2初始化
	{
		printf("PAJ7620U2_B Error!!!\r\n");
		HAL_Delay(500);
	}
	HAL_Delay(1000);
	printf("PAJ7620U2 OK\r\n"); //
}

unsigned char PAJ7620_Read_nByte(unsigned char addr, unsigned short len, unsigned char *buf)
{

	return readRegs(addr, &buf[0], len);
}
/**************************************************************************************************
  * 函数功能: unsigned char GetCurrentGesture(void)
  * 输入参数:   
  * 返 回 值: 无
	* 说    明: 读取模块的手势地址
  *
***************************************************************************************************/
unsigned char GetCurrentGesture(void)
{	
	uint8_t Data[2]={0,0};
	uint16_t Gesture_Data;
	
	uint8_t state ;
	uint8_t i ;
	
//	Gesture_Init();
//	此处判断读取来当前手势不为0时,进行处理
	state = PAJ7620_Read_nByte(PAJ_GET_INT_FLAG1, 2, &gesture.data[0]); //		

	if(state != 0)
	{
			Gesture_Data = (gesture.data[1]<<8) | gesture.data[0];

		switch(Gesture_Data)
		{
			
			case PAJ_UP:								BEEPON ;		printf("Up\r\n");					  break;
			case PAJ_DOWN:							BEEPOFF ;		printf("Down\r\n");					break;
			case PAJ_LEFT:							JDQ1ON ;		printf("Left\r\n");					break;
			case PAJ_RIGHT:							JDQ1OFF ;		printf("Right\r\n");        break;
			case PAJ_FORWARD:						JDQ2ON ;		printf("Forward\r\n");			break;
			case PAJ_BACKWARD:					JDQ2OFF ;		printf("Backward\r\n");			break;
			case PAJ_CLOCKWISE:					printf("Clockwise\r\n");		break;
			case PAJ_COUNT_CLOCKWISE:		printf("AntiClockwise\r\n");break;
			case PAJ_WAVE:							printf("Wave\r\n");  				break;			
			
			default: break;
		}
		Gesture_Data = 0;
	}
		return 0;
}


 

 

主函数程序如下:

 

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */

	printf("autor  by congconggege\r\n");
	HAL_Delay(1000);
	printf("PAJ7620U2 Gesture Sensor Test Program ...\r\n");
	PAJ7620_Init();
	printf("PAJ7620U2 Gesture Sensor OK \r\n");

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
			GetCurrentGesture();//
			HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
			HAL_Delay(500);			
	
  }
  /* USER CODE END 3 */
}


实物图片如下:

 3.5.png

试验效果:向上(Up)、向下(Dowm)、向左(Left)、向右(Right)、向前(Forward)、向后(Backward)、顺时针(Clockwise)、逆时针(Counterclockwise)、和挥动(Wave)。当识别到正确的手势,手势类型会打印在串口3上。

TEST02_iic.zip





关键词: STM32H750     LPAJ7620U2     手势读取    

专家
2024-07-01 06:31:15     打赏
2楼

谢谢分享


工程师
2024-07-02 06:53:23     打赏
3楼

谢谢分享


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]