2024艾迈斯欧司朗竞赛 - 基于dToF实现手势识别
该项目使用了自制的STM32系统板,实现了dToF传感器手势识别的设计,它的主要功能为:识别手势挥动和接近远离。
标签
嵌入式系统
STM32
开发板
手势识别
TMF8821
汽车抓狂人
更新2025-03-10
27

基于dToF的手势识别设计

测试程序视频演示


程序视频分析


手势识别视频演示



项目介绍

项目采用STM32F103C8T6和屏幕及按键组成系统板,采用TMF8821作为传感器,通过采集传感器数据并分析,再经过屏幕输出实际结果,两部分代码,一部分测试TMF8821的基础功能,一部分实现手势识别功能。

原理分析

dToF(直接飞行时间)通过测量光脉冲从发射到反射回来的时间差来计算距离。

  • 核心原理:通过发射短脉冲光(如近红外激光),并测量其从发射到被目标反射后返回传感器的时间差(Δt),利用公式d=\frac{c⋅Δt}{2} 计算距离(c为光速)。

设计框图

手册分析与代码设计

Power Up()

  1. 先给TMF882X上电
  2. 上拉使能线
    HAL_GPIO_WritePin(I2C_EN_GPIO_Port, I2C_EN_Pin, GPIO_PIN_SET);
  3. 使能寄存器(Adress: 0xE0)写入0x01,并回读0x41寄存器,获取当前可通讯状态。
    /* Power Up*/
    do{
     /* 1.Poll register ENABLE until the value 0x41 is read back. */
     I2C_SendData[0] = 0xE0;
     I2C_SendData[1] = 0x01;
     I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
     if(I2C_Status == HAL_OK)
    {
         I2C_SendData[0] = 0xE0;
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
         if(I2C_Status == HAL_OK)
        {
             I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
        }
    }
    }while(I2C_ReceData[0] != 0x41);
    /* Power Up End*/
  4. 获取当前处于的应用状态
    /* Check the Application ID */
    I2C_SendData[0] = 0x00;
    I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
    if(I2C_Status == HAL_OK)
    {
     I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
    }
    /*Check the Application ID End */

Bootloader模式

  • 对应的APP_ID == 0x80

按顺序,需要先发送下载镜像初始化指令,再读取指令准备状态,发送RAM地址信息,等待指令准备结束,再发送RAM内容,等待指令准备结束,再去发送结束标志和复位标志,等待读写APP_ID为应用ID(0x03)。

/*Image Download*/
/* DOWNLOAD_INT */
I2C_SendData[0] = 0x08;
I2C_SendData[1] = 0x14;
I2C_SendData[2] = 0x01;
I2C_SendData[3] = 0x29;
I2C_SendData[4] = 0xC1;
I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,5,0xff);
if(I2C_Status == HAL_OK)
{
 do
{
     I2C_SendData[0] = 0x08;
     I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
     if(I2C_Status == HAL_OK)
    {
         I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
    }
}while(memcmp(I2C_ReceData,ReadBack,1U));
}
/* 1.SetAddress */
I2C_SendData[0] = 0x08;
I2C_SendData[1] = 0x43;
I2C_SendData[2] = 2;
I2C_SendData[3] = (uint8_t)tmf882x_image_start;
I2C_SendData[4] = (uint8_t)(tmf882x_image_start>>8);
I2C_SendData[5] = tmf882xBootloaderChecksum(&I2C_SendData[1], 4);
I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,6,0xff);
if(I2C_Status == HAL_OK)
{
 do
{
     I2C_SendData[0] = 0x08;
     I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
     if(I2C_Status == HAL_OK)
    {
         I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
    }
}while(memcmp(I2C_ReceData,ReadBack,1U));
}
/* 2.WriteRam */
while(I2C_Status == HAL_OK && idx< tmf882x_image_length)
{
 for(chunkLen = 0;chunkLen < 128 && idx < tmf882x_image_length;chunkLen++,idx++)
{
     I2C_SendData[3 + chunkLen] = tmf882x_image[idx];
}
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x41;
 I2C_SendData[2] = chunkLen;
 I2C_SendData[3+chunkLen] = tmf882xBootloaderChecksum(&I2C_SendData[1], 2+chunkLen );
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,4+chunkLen,0xff);
 do
{
     I2C_SendData[0] = 0x08;
     I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
     if(I2C_Status == HAL_OK)
    {
         I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
    }
}while(memcmp(I2C_ReceData,ReadBack,1U));
}
/* 3.RAM remap to address 0 and continue running from RAM */
/* RAMREMAP_RESET */
I2C_SendData[0] = 0x08;
I2C_SendData[1] = 0x11;
I2C_SendData[2] = 0x00;
I2C_SendData[3] = tmf882xBootloaderChecksum(&I2C_SendData[1], 2 );
I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,4,0xff);
do
{
 I2C_SendData[0] = 0x08;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
     I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
}
}while(memcmp(I2C_ReceData,ReadBack,1U));
/*Image Download End */

Application模式

          /* Configuration Page */
 /* 1.Load the common configuration page with command LOAD_CONFIG_PAGE_COMMON */
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x16;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* 2.Check that the command is executed */
 CopyV = 0x00;
 do
{
 I2C_SendData[0] = 0x08;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
}
}while(I2C_ReceData[0] >= 0x10 && memcmp(I2C_ReceData,&CopyV,1U));
 /* 3.Check that the configuration page is loaded */
 CopyV = 0x16;
 do
{
 I2C_SendData[0] = 0x20;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,4,0xff);
}
}while(memcmp(I2C_ReceData,&CopyV,1U));
 /* 4.Change the value of the measurement period to 100m */
 I2C_SendData[0] = 0x24;
 I2C_SendData[1] = 0x64;
 I2C_SendData[2] = 0x00;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,3,0xff);
 /* 5.Select pre-defined SPAD mask 6 */
 I2C_SendData[0] = 0x34;
 I2C_SendData[1] = 0x06;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* 6.Configure the device for LOW on GPIO0 while the VCSEL is emitting light */
 I2C_SendData[0] = 0x31;
 I2C_SendData[1] = 0x03;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* 7.Write the common page to the device with command WRITE_CONFIG_PAGE */
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x15;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* 8.Check that the command is executed */
 CopyV = 0x00;
 do
{
 I2C_SendData[0] = 0x08;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
}
}while(memcmp(I2C_ReceData,&CopyV,1U));
 /* 9.Enable interrupts for results */
 I2C_SendData[0] = 0xE2;
 I2C_SendData[1] = 0x02;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* 10.Clear any old pending interrupt */
 I2C_SendData[0] = 0xE1;
 I2C_SendData[1] = 0xFF;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* Configuration Page End */

 /* Check if Firmware Supports Short Range Accuracy */
 I2C_SendData[0] = 0x03;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
}
 if(I2C_ReceData[0] == 0x6E)
{
 CheckFlg.CheckShortRange = True;
}else
{
 CheckFlg.CheckShortRange = False;
}
 /* Check Active Range */
 I2C_SendData[0] = 0x19;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
}
 if(I2C_ReceData[0] == 0x6E)
{
 CheckFlg.CheckActiveRange = SHORT_RANGE_ACCURACY;
}else if(I2C_ReceData[0] == 0x6F)
{
 CheckFlg.CheckActiveRange = LONG_RANGE_ACCURACY;
}else if(I2C_ReceData[0] == 0x00)
{
 CheckFlg.CheckActiveRange = ACCURACY_MODES_NOT_SUPPORTED;
}else
{
 CheckFlg.CheckActiveRange = None;
}
 /* Switch Between Active Ranges */
 if(CheckFlg.CheckActiveRange == SHORT_RANGE_ACCURACY)
{
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x6E;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
}else if(CheckFlg.CheckActiveRange == LONG_RANGE_ACCURACY)
{
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x6F;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
}
 /*Factory Calibration*/
 CheckFlg.StsError = True;
 while(CheckFlg.StsError)
{
 /* 1.Initiate factory calibration through command */
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x20;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 /* 2.Wait for the command to terminate */
 CopyV = 0;
 do
{
 I2C_SendData[0] = 0x08;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
}
}while((I2C_ReceData[0] == 0x01) && (memcmp(I2C_ReceData,&CopyV,1U)));
 if(I2C_ReceData[0] == 0x00)
{
 CheckFlg.StsError = False;
}
}
 /* 3.The host must read out the factory calibration data */
 CheckFlg.StsError = True;
 while(CheckFlg.StsError)
{
 I2C_SendData[0] = 0x08;
 I2C_SendData[1] = 0x19;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
 CopyV = 0;
 do
{
 I2C_SendData[0] = 0x08;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
}
}while((I2C_ReceData[0] == 0x01) && (memcmp(I2C_ReceData,&CopyV,1U)));
 if(I2C_ReceData[0] == 0x00)
{
 CheckFlg.StsError = False;
}
}
 /* 4.The host must read out the complete factory calibration page 0x20-0xDF data:0x24-0xDF*/
 I2C_SendData[0] = 0x20;
 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
 if(I2C_Status == HAL_OK)
{
 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,Factory_Page,192,0xff);
}
 /*Factory Calibration End */
// /*Factory Calibration Loading */
// /* 1.Load the factory calibration page with command */
// I2C_SendData[0] = 0x08;
// I2C_SendData[1] = 0x19;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
// /* 2.Check that the command is executed */
// CopyV = 0x00;
// do
// {
// I2C_SendData[0] = 0x08;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
// if(I2C_Status == HAL_OK)
// {
// I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
// }
// }while((I2C_ReceData[0] >= 0x10) && (memcmp(I2C_ReceData,&CopyV,1U)));
// /* 3.Check that the configuration page is loaded */
// CopyV = 0x19;
// do
// {
// I2C_SendData[0] = 0x08;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
// if(I2C_Status == HAL_OK)
// {
// I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
// }
// }while(memcmp(I2C_ReceData,&CopyV,1U));
// /* 4.Write the stored calibration data to the I²C registers 0x24-0xDF*/
// I2C_SendData[0] = 0x24;
// I2C_SendData[1] = 0x00;
// I2C_SendData[2] = 0x00;
// I2C_SendData[189] = 0x00;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,0xDF-0x24+1,0xff);
// /* 5.Write back the calibration data with command */
// I2C_SendData[0] = 0x08;
// I2C_SendData[1] = 0x15;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
// /* 6.Check that the command is executed */
// CopyV = 0x00;
// do
// {
// I2C_SendData[0] = 0x08;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
// if(I2C_Status == HAL_OK)
// {
// I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
// }
// }while((I2C_ReceData[0] >= 0x10) && (memcmp(I2C_ReceData,&CopyV,1U)));
// /*Factory Calibration Loading End */
  • 应用模式的ID为0x03
  • 应用模式下主要处理:配置页、确定可支持模式、确定当前使能的范围模式和切换使能的氛围模式,执行工厂校正,加载工厂校正结果(用于将首次校正结果在每次执行时加载进去,本次设计中每次执行都校正一次,所以不用加载校正结果)

工作模式

  • 工作模式属于Application模式,手册中并未划分这个模式。
  • 这个模式下执行dToF测量和结果读取。
/*Measure Command*/
         /* 1.Enable interrupts for results */
         I2C_SendData[0] = 0xE2;
         I2C_SendData[1] = 0x02;
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
         /* 2.Clear any old pending interrups */
         I2C_SendData[0] = 0xE1;
         I2C_SendData[1] = 0xFF;
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
         /* 3.The starting of measurements is done by issuing the command MEASURE */
         CheckFlg.StsError = True;
         while(CheckFlg.StsError)
        {
             I2C_SendData[0] = 0x08;
             I2C_SendData[1] = 0x10;
             I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
         /* 4.check that the command is accepte */
             CopyV = 0x01;
             do
            {
                 I2C_SendData[0] = 0x08;
                 I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
                 if(I2C_Status == HAL_OK)
                {
                     I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
                }
            }while((I2C_ReceData[0] >= 0x10) && (memcmp(I2C_ReceData,&CopyV,1U)));
             if(I2C_ReceData[0] == 0x01)
            {
                 CheckFlg.StsError = False;
            }
        }
         /*Measure Command End */

         /*Measure Results */
// /* 1.Wait for the INT pin to be asserted */
// while(HAL_GPIO_ReadPin(I2C_INT_GPIO_Port,I2C_INT_Pin));
         /* 2.Read out and store in variable */
         I2C_SendData[0] = 0xE1;
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
         if(I2C_Status == HAL_OK)
        {
             I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,1,0xff);
        }
         /* 3.Clear only the flagged */
         I2C_SendData[0] = 0xE1;
         I2C_SendData[1] = I2C_ReceData[0];
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
         /* 4.Read out the result data with an I²C block read */
         memset(I2C_ReceData,0x00,sizeof(I2C_ReceData));
         I2C_SendData[0] = 0x20;
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
         if(I2C_Status == HAL_OK)
        {
             I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,132,0xff);
        }
         /* 5.result data is in registers: 0x24-0xa3 */
         pGetResult = (GetResult_Typedef*)(I2C_ReceData+(0x38-0x20));
// OLED_Fill(0xFF);
         for(Result_idx = 0;Result_idx < RESULT_NUM;Result_idx ++)
        {
             TMF882x_GetResult_Value[Result_idx].distance = (pGetResult+Result_idx)->distance;
// sprintf(ShowStr,"0x%x",TMF882x_GetResult_Value[Result_idx].distance);
// OLED_ShowStr(Result_idx%6*21,Result_idx/6,ShowStr,1);
        }
         for(Result_idx = 0,pLocal=PageCollection[NowPage].PageContent->pTermContent;Result_idx<TERM_MAX;Result_idx++,pLocal=pLocal->p_next)
        {
             pLocal->TermValue = TMF882x_GetResult_Value[pLocal-Term].distance;
        }
         /*Measure Results End */
         /*StartMeasurement*/
         I2C_SendData[0] = 0x08;
         I2C_SendData[1] = 0x10;
         I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
         CopyV = 0x01;
         do
        {
             I2C_SendData[0] = 0x08;
             I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
             if(I2C_Status == HAL_OK)
            {
                 I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
            }
        }while(memcmp(I2C_ReceData,&CopyV,1U));
         /*StartMeasurement End */

// /*StopMeasurement*/
// I2C_SendData[0] = 0x08;
// I2C_SendData[1] = 0xff;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,2,0xff);
// CopyV = 0x00;
// do
// {
// I2C_SendData[0] = 0x08;
// I2C_Status = HAL_I2C_Master_Transmit(&hi2c1,0x41<<1,I2C_SendData,1,0xff);
// if(I2C_Status == HAL_OK)
// {
// I2C_Status = HAL_I2C_Master_Receive(&hi2c1,0x41<<1,I2C_ReceData,3,0xff);
// }
// }while(memcmp(I2C_ReceData,&CopyV,1U));
// /*StopMeasurement End */
  • 采用地址映射,将数组映射到结构体,从而直接通过指针操作取值
  • 由于需要多次取值,所以结束代码被注释

数据输出

  • 采用OLED输出,为了实现GUI界面,进行了简单的数据结构封装。
  • 整体分为:页面管理、项管理
    • 页面管理结构
      /*
      * 页面格式
      * | 16 * 128 | 标题
      * | 8 * 128 | 选项1
      * | 8 * 128 | 选项2
      * | 8 * 128 | 选项3
      * | 8 * 128 | 选项4
      * | 8 * 128 | 选项5
      * | 8 * 128 | 选项6
      */
      typedef struct Term{
      const uint8_t* TermName;
      uint16_t TermValue;
      #if !defined(FIXED_TERM)
      struct Term* p_pre;
      struct Term* p_next;
      #endif
      }TermStruct;
      typedef struct PageContent{
      uint8_t HeaderTitle[HEADER_MAX];
      #if defined(FIXED_TERM)
      TermStruct* TermContent[TERM_MAX]; //当固定数量且不存在滑动时采用固定数组的方法
      #else
      TermStruct* pTermContent; //当存在滑动时,需要采用循环结构来实现滑动显示,所以采用二次指针实现双向链,指向当前页面的第一个项
      TermStruct* pTermContentNow; //指向当前页面选中的项
      #endif
      int8_t Column_options; //页面选中项 (由于包括-1,表示上一溢,所以采用int8)
      void (*pTermShowFuc)(uint8_t TermOrder,volatile const TermStruct* Term,OLED_ShowReverseEnum Reverse);
      void (*pTermSelectFlushFuc)(struct PageContent* Page,SelectDirEnum SelectDir);
      void (*pTermValueFlushFuc)(struct PageContent* Page);
      }PageContentStruct;
    • 项管理结构
      typedef struct PageParam{
      PageEnum PageNum; //页面编号
      void (*pPageShowFuc)(const PageContentStruct*); //页面刷新函数
      PageContentStruct* PageContent;
      }PageParamStruct;
    • 可调用API
      void Memu_Show(const PageParamStruct* Page);                                        //刷新最初的页界面
      void Page_Show(const PageContentStruct* Page); //页面刷新函数
      void Term_Show(uint8_t TermOrder,volatile const TermStruct* Term,uint8_t Reverse); //项刷新函数
      void TermSelect_flush(PageContentStruct* Page,SelectDirEnum SelectDir); //项选择刷新函数
      void TermValue_flush(PageContentStruct* Page);

切换逻辑

执行结果

在正常工作模式下,GUI显示首页;

在切换到最底下时,出现页面刷新到新页面;

在切换到最顶上的时候,一样出现页面刷新

手势识别方法

框图

  • 手势识别主要通过对比上下变化值去确定
    • 当首端平均值在短时间内与中间值差距比较大,则认为是“T”
    • 同理,末端存在一个触发,认为是”D”
    • 同理,侧端存在一个触发,认为是“L”和“R”
    • 当全局的平均值在一个短期内急剧下降,则认为是“A”,按下
    • 当全局的平均值在一个短期内急剧上升,则认为是“B”,松开
for(Result_idx = 0;Result_idx < 3;Result_idx++)
{
 TD[Result_idx] = (TMF882x_GetResult_Value[Result_idx*3].distance+TMF882x_GetResult_Value[Result_idx*3+1].distance+TMF882x_GetResult_Value[Result_idx*3+2].distance)/3;
 BA += TD[Result_idx];
}
BA /= 3;
for(Result_idx = 0;Result_idx < 3;Result_idx++)
{
 LR[Result_idx] = (TMF882x_GetResult_Value[Result_idx].distance+TMF882x_GetResult_Value[Result_idx+3].distance+TMF882x_GetResult_Value[Result_idx+6].distance)/3;
}
if(TD[0]<TD[1] && (TD[1]-TD[0])>200)
{
 OLED_ShowStr(10,2,"T",1,NoReverse);
}else if(TD[1]>TD[2] && (TD[1]-TD[2])>200)
{
 OLED_ShowStr(10,2,"D",1,NoReverse);
}else
{
 if(LR[0]<LR[1] && (LR[1]-LR[3])>200)
{
     OLED_ShowStr(10,2,"L",1,NoReverse);
}else if(LR[1]>LR[2] && (LR[1]-LR[2])>200)
{
     OLED_ShowStr(10,2,"R",1,NoReverse);
}else
{
     if(BA > (BA_Old+200))
    {
         OLED_ShowStr(10,2,"A",1,NoReverse);
    }else if(BA_Old > (BA+200))
    {
         OLED_ShowStr(10,2,"B",1,NoReverse);
    }else
    {
// OLED_ShowStr(10,2,"S",1,NoReverse);
    }
}
}
BA_Old = BA;

效果图

  • 默认

  • 上滑

  • 下滑

  • 左滑

  • 右滑

  • 按下

  • 松开

附件下载
Prj.7z
团队介绍
西安电子科技大学芜湖研究院汽车电子工程师
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号