这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【DIY手势翻页笔】课程二:I2C驱动+PAJ7620手势传感器

共2条 1/1 1 跳转至

【DIY手势翻页笔】课程二:I2C驱动+PAJ7620手势传感器

菜鸟
2024-07-03 19:09:15     打赏

课程一中,已经配置好了调试串口、串口打印输出,以及PA5的LED灯闪烁功能。课程二要在课 程一基础上,做如下功能:

(1)  配置好STM32的I2C外设,

(2)  开发手势传感器PAJ7620的驱动代码,读取手势识别结果

(3)  将识别的手势结果,打印到 USART3串口上输出。


一.    PAJ7620手势传感器

1.资料收集和参数性能

    本次实验使用的是seeed studio的Grove-Gesture v1.0,其官方的文档地址为:  https://wiki.seeedstudio.com/Grove-Gesture_v1.0/

 

图片1.png

     上述链接文档里,提供了基于Arduino和Raspberry PI的使用例程,但是没有基于STM32的驱动。这些示例代码是使用Python开发的,研究下这些代码可以弄清楚PAJ7620传感器的使用步骤。

    同时在页面上Resource章节,提供了 PCB图和手册的下载,手册地址如下,这也是非常重要的官方一手开发开发资料。

https://files.seeedstudio.com/wiki/Grove_Gesture_V_1.0/res/PAJ7620U2_Datasheet_V0.8_20140611.pdf

 

简单总结下硬件的基本参数:

l  内置9个手势类型:上,下,左,右,前,后,顺时针旋转,逆时针旋转,挥动。

l  支持接近检测功能,检测物体体积大小和亮度。

l  分辨率:60x60 pixels   ,每个像素的大小是:20x20 um2 , 最大支持的速率:720fps。  

l  模式:gesture / cursor / image modes

l  控制速度:在普通模式下:60~600°/s

l  通讯模式:I2C模式(for gesture/ cursor 模式):最高能达到400kbit/s

2. 工作原理

 参考资料:

    https://blog.csdn.net/weixin_36590806/article/details/124805530

    https://gitee.com/RT-Thread-Mirror/Gesture_PAJ7620

    https://gitee.com/zhagyuji/stm32f4_paj7620/tree/master/OLED/PAJ7620

     通过研究官网给出的树莓派示例代码,以及搜索到的STM32F4上的一些零零散散的代码,基本弄清楚模块使用的原理和驱动步骤。

工作原理:PAJ7620u2工作时通过内部LED驱动器,驱动红外LED向外发射红外信号,当传感器阵列在有效地距离中探测到物体时,目标信息提取阵列会对探测目标进行特征原始数据地获取,获取数据会存在寄存器中,同时手势识别阵列会对原始数据进行识别处理,最后将手势结果存到寄存器中,用户可根据I2C接口对原始数据和手势数据地结果进行读取。

 

传感器支持好几种模式。使用前需要先将固定的大片配置字节写入到特定的寄存器中,将传感器配置为“手势模式”

 

l  在PAJ7620内部有两个BANK 寄存器区域,分别是BANK0,BANK1。想访问某个bank区域下的寄存器,需要在访问前发送控制指令进入该寄存器区域,具体控制指令为:进入BANK0区域,往传感器0XEF地址写0X00;进入BANK1区域,往传感器0XEF地址写0x01。

 

l  手势识别支持9种手势,识别结果存放在手势识别寄存器:0X43,0X44中,如下图所示:

图片2.png

 

二.    硬件接线

1.  I2C引脚与开发板的接线连接

      可以使用硬件I2C外设,也可以软件翻转引脚方式实现I2C。我使用硬件I2C,具体引脚为PB6/PB7。从下方I2C的连接图上看,需要SDA和SCL都设置为开漏输出模式,且接上拉电阻。

图片3.jpg

    上图中上拉电阻是必须要有的,可以在接线时接2个物理电阻实现上拉,这样比较麻烦。另一种方法是,MCU的GPIO脚做输出时,可以通过配置实现引脚默认上拉或下拉,我们就采用这种方法。因此,后续CubeMX配置的时候,一定要将SDA和SCL的两个pin脚都修改为Pull-Up模式!!

    查看开发板的引脚手册,找到PB6和PB7,在CN10的引脚3,5,7,9四根线就可以了。

图片4.png

    这里需要提一下,传感器带的四针插头,与CN10的引脚间距不兼容。需要自己焊接,或者像我一样把自带的白色头拔下来,找两个杜邦线跳帽也拔下来,自制一个对接线,如图所示。

图片9.jpg


2.  CubeMX配置硬件I2C外设

a.点击课程1工程,打开。

b.使能I2C1,并重新配置IO口PB6/PB7为I2C1。


c.设置I2C1的IO口为上拉/输出高速。一定要记住,配置GPIO引脚为上拉模式,否则需要自己外接上拉电阻。

三.    代码部分

1.  I2C基本收发字节的函数

        这部分,CubeMX配置好外设,HAL自带了I2C通讯的基本读写字节基本功能代码,从头文件中可以查看:

图片5.png

图中头文件中,HAL_I2C_Mem_Write()和HAL_I2C_Mem_Read()就是直接对外设地址的读写函数,实现PAJ7620驱动的时候可以直接使用,非常方便。

 

2.  实现PAJ7620的驱动部分

    根据已有的代码和资料,开发驱动分为两个文件:paj7620.h/paj7620.c

    先看头文件,除了基本的手势功能定义外,主要是三个函数

图片6.png

     再看c文件中,三个函数的实现部分。第一个初始化函数paj7620_init():

//PAJ7620初始化寄存器数组:219对 {Address, value}  
uint8_t Paj7620Init_Reg_Array[][2] = {  
  {0xEF, 0x00},  {0x32, 0x29},  {0x33, 0x01},  {0x34, 0x00},  {0x35, 0x01},  
  {0x36, 0x00},  {0x37, 0x07},  {0x38, 0x17},  {0x39, 0x06},  {0x3A, 0x12},  
  {0x3F, 0x00},  {0x40, 0x02},  {0x41, 0xFF},  {0x42, 0x01},  {0x46, 0x2D},  
  {0x47, 0x0F},  {0x48, 0x3C},  {0x49, 0x00},  {0x4A, 0x1E},  {0x4B, 0x00},  
  {0x4C, 0x20},  {0x4D, 0x00},  {0x4E, 0x1A},  {0x4F, 0x14},  {0x50, 0x00},  //25
  
  {0x51, 0x10},  {0x52, 0x00},  {0x5C, 0x02},  {0x5D, 0x00},  {0x5E, 0x10},  
  {0x5F, 0x3F},  {0x60, 0x27},  {0x61, 0x28},  {0x62, 0x00},  {0x63, 0x03},  
  {0x64, 0xF7},  {0x65, 0x03},  {0x66, 0xD9},  {0x67, 0x03},  {0x68, 0x01},  
  {0x69, 0xC8},  {0x6A, 0x40},  {0x6D, 0x04},  {0x6E, 0x00},  {0x6F, 0x00},  
  {0x70, 0x80},  {0x71, 0x00},  {0x72, 0x00},  {0x73, 0x00},  {0x74, 0xF0},  //50
  
  {0x75, 0x00},  {0x80, 0x42},  {0x81, 0x44},  {0x82, 0x04},  {0x83, 0x20},  
  {0x84, 0x20},  {0x85, 0x00},  {0x86, 0x10},  {0x87, 0x00},  {0x88, 0x05},  
  {0x89, 0x18},  {0x8A, 0x10},  {0x8B, 0x01},  {0x8C, 0x37},  {0x8D, 0x00},  
  {0x8E, 0xF0},  {0x8F, 0x81},  {0x90, 0x06},  {0x91, 0x06},  {0x92, 0x1E},  
  {0x93, 0x0D},  {0x94, 0x0A},  {0x95, 0x0A},  {0x96, 0x0C},  {0x97, 0x05},  //75
  
  {0x98, 0x0A},  {0x99, 0x41},  {0x9A, 0x14},  {0x9B, 0x0A},  {0x9C, 0x3F},  
  {0x9D, 0x33},  {0x9E, 0xAE},  {0x9F, 0xF9},  {0xA0, 0x48},  {0xA1, 0x13},  
  {0xA2, 0x10},  {0xA3, 0x08},  {0xA4, 0x30},  {0xA5, 0x19},  {0xA6, 0x10},  
  {0xA7, 0x08},  {0xA8, 0x24},  {0xA9, 0x04},  {0xAA, 0x1E},  {0xAB, 0x1E},  
  {0xCC, 0x19},  {0xCD, 0x0B},  {0xCE, 0x13},  {0xCF, 0x64},  {0xD0, 0x21},  //100
  
  {0xD1, 0x0F},  {0xD2, 0x88},  {0xE0, 0x01},  {0xE1, 0x04},  {0xE2, 0x41},  
  {0xE3, 0xD6},  {0xE4, 0x00},  {0xE5, 0x0C},  {0xE6, 0x0A},  {0xE7, 0x00},  
  {0xE8, 0x00},  {0xE9, 0x00},  {0xEE, 0x07},  {0xEF, 0x01},  {0x00, 0x1E},  
  {0x01, 0x1E},  {0x02, 0x0F},  {0x03, 0x10},  {0x04, 0x02},  {0x05, 0x00},  
  {0x06, 0xB0},  {0x07, 0x04},  {0x08, 0x0D},  {0x09, 0x0E},  {0x0A, 0x9C},  //125
  
  {0x0B, 0x04},  {0x0C, 0x05},  {0x0D, 0x0F},  {0x0E, 0x02},  {0x0F, 0x12},  
  {0x10, 0x02},  {0x11, 0x02},  {0x12, 0x00},  {0x13, 0x01},  {0x14, 0x05},  
  {0x15, 0x07},  {0x16, 0x05},  {0x17, 0x07},  {0x18, 0x01},  {0x19, 0x04},  
  {0x1A, 0x05},  {0x1B, 0x0C},  {0x1C, 0x2A},  {0x1D, 0x01},  {0x1E, 0x00},  
  {0x21, 0x00},  {0x22, 0x00},  {0x23, 0x00},  {0x25, 0x01},  {0x26, 0x00},  //150
  
  {0x27, 0x39},  {0x28, 0x7F},  {0x29, 0x08},  {0x30, 0x03},  {0x31, 0x00},  
  {0x32, 0x1A},  {0x33, 0x1A},  {0x34, 0x07},  {0x35, 0x07},  {0x36, 0x01},  
  {0x37, 0xFF},  {0x38, 0x36},  {0x39, 0x07},  {0x3A, 0x00},  {0x3E, 0xFF},  
  {0x3F, 0x00},  {0x40, 0x77},  {0x41, 0x40},  {0x42, 0x00},  {0x43, 0x30},  
  {0x44, 0xA0},  {0x45, 0x5C},  {0x46, 0x00},  {0x47, 0x00},  {0x48, 0x58},  //175
  
  {0x4A, 0x1E},  {0x4B, 0x1E},  {0x4C, 0x00},  {0x4D, 0x00},  {0x4E, 0xA0},  
  {0x4F, 0x80},  {0x50, 0x00},  {0x51, 0x00},  {0x52, 0x00},  {0x53, 0x00},  
  {0x54, 0x00},  {0x57, 0x80},  {0x59, 0x10},  {0x5A, 0x08},  {0x5B, 0x94},  
  {0x5C, 0xE8},  {0x5D, 0x08},  {0x5E, 0x3D},  {0x5F, 0x99},  {0x60, 0x45},  
  {0x61, 0x40},  {0x63, 0x2D},  {0x64, 0x02},  {0x65, 0x96},  {0x66, 0x00},  //200
  
  {0x67, 0x97},  {0x68, 0x01},  {0x69, 0xCD},  {0x6A, 0x01},  {0x6B, 0xB0},  
  {0x6C, 0x04},  {0x6D, 0x2C},  {0x6E, 0x01},  {0x6F, 0x32},  {0x71, 0x00},  
  {0x72, 0x01},  {0x73, 0x35},  {0x74, 0x00},  {0x75, 0x33},  {0x76, 0x31},  
  {0x77, 0x01},  {0x7C, 0x84},  {0x7D, 0x03},  {0x7E, 0x01},                 //219
};  

//PAJ7620U2初始化,返回0则初始化失败  
uint8_t paj7620_init(void)  
{  
    uint8_t i,State,n;  
    State = 0;  
	
	//写入BANK0区域前, 先向 0xEF 地址写0
    while(HAL_OK != HAL_I2C_Mem_Write(&hi2c1, PAJ7620_I2C_ADDRESS, PAJ_BANK_SELECT, I2C_MEMADD_SIZE_8BIT, &State, 1, 500))  
    {  
        HAL_Delay(5);  
        //printf("paj7620_init err: 1 \r\n"); 
		msg="paj7620_init err: 1 \r\n";
		HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen( msg),100);
    }  
  
    for(i=0; i<219; i++)  
    {  
		//循环向BANK1中写入配置字节,共219字节
        while(HAL_OK != HAL_I2C_Mem_Write(&hi2c1, PAJ7620_I2C_ADDRESS, Paj7620Init_Reg_Array[i][0], I2C_MEMADD_SIZE_8BIT, &Paj7620Init_Reg_Array[i][1], 1, 500))  
        {  
            HAL_Delay(5);  
            //printf("paj7620_init err: 2 \r\n");  
			msg="paj7620_init err: 2 \r\n";
			HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen( msg),100);
        }  
        HAL_Delay(5);  
    }  
    
	//读取BANK0区域前, 先向 0xEF 地址写0
    while(HAL_OK != HAL_I2C_Mem_Write(&hi2c1, PAJ7620_I2C_ADDRESS, PAJ_BANK_SELECT, I2C_MEMADD_SIZE_8BIT,&State,1,500))  
    {  
        HAL_Delay(5);  
        //printf("paj7620_init err: 3 \r\n");  
		msg="paj7620_init err: 3 \r\n";
		HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen( msg),100);
    }  
    HAL_Delay(5);  
      
	//读取地址0x32内存的值,存入n中
    while(HAL_OK != HAL_I2C_Mem_Read(&hi2c1, PAJ7620_I2C_ADDRESS, 0x32, I2C_MEMADD_SIZE_8BIT, &n, 1, 500))  
    {  
        HAL_Delay(5);  
        //printf("paj7620_init err: 4 \r\n"); 
		msg="paj7620_init err: 4 \r\n";
		HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen( msg),100);		
    }  
      
    if(n != 0x29)  
    {  
        return 0;  
    }  
      
    return 1;  
}

第二个函数,手势识别 getGesture()

//检测手势并输出  
uint16_t getGesture(void)  
{     
    uint8_t Data[2]={0,0};  
    uint16_t Gesture_Data;  
    HAL_I2C_Mem_Read(&hi2c1, PAJ7620_I2C_ADDRESS, PAJ_INT_FLAG1, I2C_MEMADD_SIZE_8BIT, &Data[0], 1, 500);  
    HAL_Delay(5);  
   
    HAL_I2C_Mem_Read(&hi2c1, PAJ7620_I2C_ADDRESS, PAJ_INT_FLAG2, I2C_MEMADD_SIZE_8BIT, &Data[1], 1, 500);  
    HAL_Delay(5);  
   
    Gesture_Data = (Data[1]<<8) | Data[0];  
    //printf("\n %x \r\n", Gesture_Data); 
	
    return 	Gesture_Data;

}

第三个函数,来应用手势识别结果搞事情。我这里是打印识别结果到串口3输出,函数为 usart_print_gesture():

void usart_print_gesture(uint16_t status)       //通过串口打印手势信息  
{
	if(status == PAJ_ZERO)  //未检测到任何手势
	{
		return;
	}
	
	switch(status)  
    {  
		case PAJ_UP:                   msg="Up\r\n";               break;  
		case PAJ_DOWN:                 msg="Down\r\n";             break;  
		case PAJ_LEFT:                 msg="Left\r\n";             break;  
		case PAJ_RIGHT:                msg="Right\r\n";            break;  
		case PAJ_FORWARD:              msg="Forward\r\n";          break;  
		case PAJ_BACKWARD:             msg="Backward\r\n";         break;  
		case PAJ_CLOCKWISE:            msg="Clockwise\r\n";        break;  
		case PAJ_COUNT_CLOCKWISE:      msg="AntiClockwise\r\n";    break;  
		case PAJ_WAVE:                 msg="Wave\r\n";             break;  
		default:  					   msg="Error Gesture value ~~~\r\n";
    }  
	
	//通过调试串口,打印消息msg
    HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen( msg),100);
}

 

3.      主函数中调用手势识别功能

    在进入while循环之前,先调用paj7620的初始化函数

图片7.png

如上图,根据初始化结果,打印出 error 或者 OK信息。

 

     然后在while循环里,调用手势检测函数,并打印结果到串口:

图片8.png

 

四 测试结果

代码编译下载,看下测试结果(b站视频)。 手势检测还是非常灵敏的!

   https://www.bilibili.com/video/BV1SH4y1F7Cf?p=2

附完整工程源代码:

 GestureDemo.rar

五. 视频讲解:

       https://www.bilibili.com/video/BV1SH4y1F7Cf?p=3




关键词: PAJ7620     I2C     手势传感器    

高工
2024-07-15 21:00:42     打赏
2楼

很喜欢up的视频


共2条 1/1 1 跳转至

回复

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