内容介绍
内容介绍
基于dToF的手势识别设计
测试程序视频演示
程序视频分析
手势识别视频演示
项目介绍
项目采用STM32F103C8T6和屏幕及按键组成系统板,采用TMF8821作为传感器,通过采集传感器数据并分析,再经过屏幕输出实际结果,两部分代码,一部分测试TMF8821的基础功能,一部分实现手势识别功能。
原理分析
dToF(直接飞行时间)通过测量光脉冲从发射到反射回来的时间差来计算距离。
- 核心原理:通过发射短脉冲光(如近红外激光),并测量其从发射到被目标反射后返回传感器的时间差(Δt),利用公式d=\frac{c⋅Δt}{2} 计算距离(c为光速)。
设计框图
手册分析与代码设计
Power Up()
- 先给TMF882X上电
- 上拉使能线
HAL_GPIO_WritePin(I2C_EN_GPIO_Port, I2C_EN_Pin, GPIO_PIN_SET);
- 使能寄存器(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*/ - 获取当前处于的应用状态
/* 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
查看更多
猜你喜欢
2024艾迈斯欧司朗竞赛 - 基于TMF8821的dToF传感器模块 实现手势识别该项目使用了TMF8821的dToF传感器模块,实现了手势识别的设计,它的主要功能为:可识别挥动,接近/远离等手部动作,并使用手势动作控制屏幕上的菜单功能。
冲向天空的猪
24
2024艾迈斯欧司朗竞赛 - 基于dToF的手势识别2048游戏机该项目使用了TMF8821和RP2040游戏机,实现了基于dToF的手势识别2048游戏机的设计,它的主要功能为:通过dToF传感器实时采集手势数据,并通过神经网络模型识别玩家的手势动作,从而实现控制2048游戏的功能。。
zxfeng
91
2024艾迈斯欧司朗竞赛 - 基stm32和dtof传感器实现手势识别该项目使用了stm32和dtof传感器,实现了手势识别的设计,它的主要功能为:识别手势。
田应宇
16