TI杯基于FDC2214的手势识别设计(黑龙江省赛)

省赛题目:

使用指定IC,完成对手势1,2,3,4,5,石头,剪刀,布的识别,详细的文本文件大家可以在网上搜一下。
多说一句,这个题目没什么难度,最锻炼人的就是当时读技术手册

前言及大概完成思路:

电子设备的发展,智能化必不可少,手势识别控制也将成为一种趋势。本设计基于STM32F103单片机控制,手势识别分为两种模式,分别实现对特定数量,手型的手势识别,包括手势:石头、剪刀、布、1、2、3、4、5。本设计首先进行被测试者手势信息采集,利用IIC协议读取数据,读取数据寄存器有效值,其次使用软件实现数据处理,最后通过测试与调试完成特定手势的识别。该系统由STM32单片机,FDC2214电容检测模块,TFTLCD显示屏,手势数据采集平台,电源构成。读取FDC2214数据并处理,最终利用TFTLCD显示出判决结果。

硬件需求及资料

1)STM32精英版(带按键)
2)FDC2214及其外围电路组成的模组
3)手势识别的平台(覆铜金属片),跟手差不多大小
4)TFTLCD显示屏
5)FDC2214IC的datasheet(中英文结合比较好)
6)若干杜邦线
如图
在这里插入图片描述
实物图(有点差距):
在这里插入图片描述
在前面的博客我经常强调,跟硬件打交道,思路很重要,应该放在首位,也就是一整套的流程:

流程梳理:

总体方案设计
在这里插入图片描述
采用了STM32单片机为核心的控制芯片,数据读取原理与实现方案。
原理框图:
在这里插入图片描述
除了含有STM32控制芯片的最小系统外,需要外部供电电源,显示数据的2.8寸TFTLCD的显示屏,采集数据的FDC2214数据处理芯片,外连手势感应平面,数据采集的IO口选择都要根据实际情况进行调整。
2.
程序流程
流程图手势识别流程图
在这里插入图片描述
LCD软件流程图
在这里插入图片描述
3.
硬件连接
按键及TFTLCD引脚连接
在这里插入图片描述在这里插入图片描述
FDC2214原理框图
在这里插入图片描述
实物图:
反面
在这里插入图片描述
正面:
在这里插入图片描述
当然网上也有很多设计其他外围电路的方式,大同小异
FDC2214与镀金属连接:
在这里插入图片描述
连接黄色图标处就是我们的INTA0
IC的外围电路已经有了,也不需要再去设计,硬件连接,我就列举一下:
通过外围电路引出的引脚:

VCC,GND,SCL,SDA,INTB,ADDR,SD,GND及检测感应的INT0A,INT0B~INT3A,INT3B;

大致框架说完了,那么就要开始我们的比赛了:

读fdc2214的DATASHEET(不然什么都不知道到)

对我之前来说,fdc2214是一个全新的IC,想要知道怎么用,硬件规格是怎么样的,这是嵌入式必须应该会的,到以后发展到写内核驱动,也是需要读datasheet的;
为什么要读数据手册:

通信方式,数据位置,数据格式,IC初始化,配置,等等都不清楚,这些只有数据手册上有;
数据手册及资料,我会上传。
通过阅读数据手册,我获取到了的信息量:
1)通信方式采用IIC方式
2)mcu与外设连接方式选择,及与传感器平面连接方式选择
3)各个寄存器的配置,可操作进行数据操作的事件间隔、权限
关于寄存器的配置,应该是比较重要的。
根据公式,获得寄存器配置值

FDC2214传感器与主控芯片连接框图,从图上可以看到,手势检测平台基本原理是LC谐振电路,一个可变变容金属导板并联谐振电路电容,每当手势的接近,电容发生改变,导致回路频率发生改变,频率与电容电感的关系:
在这里插入图片描述
L——谐振电路电感值
C——谐振电路电容值
可以算出没有识别时的频率值
进一步细化清晰的可以看到,手势感应平面的电容是与模块内部电容属于并联,根据电容并联公式可得:
在这里插入图片描述
共同组成总电容值改变整体震动频率,根据检测频率的改变,计算出电容值的变化量,根据公式。在数据手册中,可以得到,FDC2214的数据输出公式:
在这里插入图片描述
在这里插入图片描述——参考频率
式中 ——谐振电路频率
在这里,我选择的方式是单通道方式:
在这里插入图片描述
时钟寄存器配置
通过上面的数据寄存器公式,基本所有OI口,外设接口都需要时钟的配置,这是实验项目的基础,这往往也是容易忽略的细节,在数据手册中FDC2214的时钟配置,在此模块中,关键的频率有在这里插入图片描述在这里插入图片描述在这里插入图片描述这三个,频率测量参考时钟来自,使用外部的时钟源,这有利于得到稳定精确的频率,内部振荡器可用于低成本,精确度要求不高的应用。在这里插入图片描述在这里插入图片描述由寄存器控制,在这里插入图片描述式中在这里插入图片描述 ——外部频率源
在这里插入图片描述式中 在这里插入图片描述——谐振电路频率
模式配置
采用单通道配置,CONFIG寄存器,具体信息为有效频道选择,睡眠模式,传感器激活模式选择。选择参考频率源,高电流传感器驱动器。
数据寄存器:
通过独处样本寄存器值可获得数据,由DATA_CHX控制,数值为寄存器的16位结果的12个MSB,为了确保数据的真实性,按照手册要求,需要先读取DATA_CHX(16位结果的12位有效MSB),然后再读取同一通道的DATA_LSB_CHX寄存器值。
稳定时间寄存器:
稳定时间寄存器配置
在这里插入图片描述
具体参数应参照detasheet,就不详细说明
转换时间
在这里插入图片描述
具体参数应参照detasheet,就不详细说明
电流驱动控制寄存器:
驱动电流及其配置,CONFIG状态寄存器,具体信息为通道0传感器频率选择,通道0参考分频器设置。
状态寄存器
STATUS_CONFIG状态寄存器,读取状态位为读取数据做准备。
Deglitch
在MUX_CONFIG寄存器配置滤波。
重置寄存器
RESET_DEV寄存器配置IC重置
设备地址选择
当ADDR接高电平,fdc2214地址为0x2b,反之为0x2a
根据数据手册,列出了所有适合单端配置的寄存器,当然你可以根据手册里建议的(手册里建议的是单通道的,我也是使用的单通道),采用建议值,也可以根据公式换算,取得配置值。

软件编写

软件模拟IIC
关于IIC的时序模拟,按键,TFTLCD我前面的博客有详细讲解,我这里就列出IIC函数名即可:

void IIC_Init(void);              
void IIC_Start(void);				
void IIC_Stop(void);	  			
void IIC_Send_Byte(u8 txd);			
u8 IIC_Read_Byte(unsigned char ack);
u8 IIC_Wait_Ack(void); 				
void IIC_Ack(void);					
void IIC_NAck(void);				
void ADS_delay(void);
void ADS_clock(void)

其中

void ADS_delay(void) 
{
    
      
  unsigned char i;    
  for(i=0;i<40;i++); 
}
void ADS_clock(void)  
{
    
          
  IIC_SCL=1;//SCL=1
  ADS_delay(); 
  IIC_SCL=0;//SCL=0 
  ADS_delay();   
}

就不再详细讲解,上面初始化结束了总线协议,并未针对特定的IC,所以,使用协议来初始化fdc2214
FDC2214初始化
由协议得,我们采用的寄存器地址都是8位的,我们先宏定义好要使的寄存器,都是可能要初始化配置的

#define FDC2X14_Address 0x2A//器件地址
#define FDC2X14_W FDC2X14_Address<<1
#define FDC2X14_R (FDC2X14_Address<<1)+1
#define DATA_CH0 0x00
#define DATA_LSB_CH0 0x01
#define RCOUNT_CH0 0x08
#define SETTLECOUNT_CH0 0x10
#define CLOCK_DIVIDERS_C_CH0 0x14
#define STATUS 0x18
#define ERROR_CONFIG 0x19
#define CONFIG 0x1A
#define MUX_CONFIG 0x1B
#define RESET_DEV 0x1C
#define DRIVE_CURRENT_CH0 0x1E
#define MANUFACTURER_ID 0x7E
#define DEVICE_ID 0x7F

寄存器配置函数,参数位要写入的寄存器地址,要写入的高八位数据及低八位数据,用于配置寄存器

void SetFDC2X14(u8 Address,u8 MSB,u8 LSB)
{
    
    
	IIC_Start(); 
  IIC_Send_Byte(FDC2X14_W);
  IIC_Wait_Ack();
  ADS_delay();
	IIC_Send_Byte(Address);
	IIC_Wait_Ack();
  ADS_delay();
	IIC_Send_Byte(MSB);
	IIC_Wait_Ack();
  ADS_delay();
	IIC_Send_Byte(LSB);
	IIC_Wait_Ack();
  ADS_delay();
	IIC_Stop();
	ADS_delay();
}

读取数据寄存器的32位数据

unsigned int ReadFDC2X14(u8 firstAddress,u8 secondAddress)
{
    
    
	 unsigned int temp;
  u8 result[4];
  IIC_Start(); 
  IIC_Send_Byte(FDC2X14_W);
  IIC_Wait_Ack();
  ADS_delay();
	IIC_Send_Byte(firstAddress);
	IIC_Wait_Ack();
	ADS_delay();
	IIC_Stop();
	ADS_delay();
	
	IIC_Start();
	IIC_Send_Byte(FDC2X14_R);
  IIC_Wait_Ack();
  ADS_delay();
  result[0]=IIC_Read_Byte(1);
	result[0] = result[0]<<4;
	result[0] = result[0]>>4;
  IIC_Ack(); 
	ADS_delay();
  result[1]=(IIC_Read_Byte(1));         
	IIC_Ack(); 
	IIC_Stop();
	ADS_delay();
	
	IIC_Start(); 
  IIC_Send_Byte(FDC2X14_W);
  IIC_Wait_Ack();
  ADS_delay();
	IIC_Send_Byte(secondAddress);
	IIC_Wait_Ack();
	ADS_delay();
	IIC_Stop();
	ADS_delay();
	
	IIC_Start();
	IIC_Send_Byte(FDC2X14_R);
  IIC_Wait_Ack();
  ADS_delay();
  result[2]=IIC_Read_Byte(1);
  IIC_Ack(); 
	ADS_delay();
  result[3]=(IIC_Read_Byte(1));         
	IIC_Ack(); 
	IIC_Stop();
	ADS_delay();
	
  temp = (unsigned int)(((result[0]<< 24) | (result[1] << 16) | (result[2] << 8) | (result[3] & 0xff)));  
  return(temp); 
}

构造出通道的数据读取函数:

int FDC2X14ReadCH(u8 index)
{
    
    
	int result;
	switch(index)
	{
    
    
		case 0x01:
			result = ReadFDC2X14(DATA_CH0,DATA_LSB_CH0);
			break;
		case 0x02:
			result = ReadFDC2X14(DATA_CH1,DATA_LSB_CH1);
			break;
		case 0x03:
			result = ReadFDC2X14(DATA_CH2,DATA_LSB_CH2);
			break;
		case 0x04:
			result = ReadFDC2X14(DATA_CH3,DATA_LSB_CH3);
			break;
	}
	return result;
}

这样就可以初始化fdc2214了:

void FDC2X14_Init(void)
{
    
    
	IIC_Init();
	SetFDC2X14(RCOUNT_CH0,0x30,0xCB);
	SetFDC2X14(RCOUNT_CH1,0x30,0xCB);
	SetFDC2X14(CLOCK_DIVIDERS_C_CH0,0x20,0x01);
	SetFDC2X14(CLOCK_DIVIDERS_C_CH1,0x20,0x01);	
	SetFDC2X14(SETTLECOUNT_CH0,0x00,0x19);
	SetFDC2X14(SETTLECOUNT_CH1,0x00,0x19);
	SetFDC2X14(ERROR_CONFIG,0x00,0x00);
	SetFDC2X14(MUX_CONFIG,0x82,0x0c);
	SetFDC2X14(DRIVE_CURRENT_CH0,0x50,0x00);
	SetFDC2X14(DRIVE_CURRENT_CH1,0x50,0x00);
	SetFDC2X14(CONFIG,0x16,0x01);
}

我部分参考了datasheet的建议值,其他的有变动和更改,在主函数中调用初始化函数即可

主函数mian.c

#include "delay.h"
#include "sys.h"
#include "usart.h"	
#include "timer.h"
#include "wdg.h"
#include "spi.h"
#include "Data_sampling.h"
#include "FDC2X14.h"
#include "lcd.h"
#include "key.h"
#include "beep.h"
#include "chao.h"

#include <math.h>
float hq;
float A=0.0;
float B=0.0;
float C=0.0;
float D=0.0;
float E=0.0;
float t=0.0;

unsigned char text1=0,text2=0,text3=0;

float A1,A2,A3,A4;		

 int main(void)
 {
    
    	
	NVIC_Configuration(); 	
	delay_init();	    	 
	uart1_init(115200);	 
	FDC2X14_Init();
	KEY_Init();          
  LCD_Init();
	BEEP_Init();  
	POINT_COLOR=RED;
	LCD_ShowString(10,10,240,320,16,"stm32+fdc2214");
	while(1)
	{
    
    
	hq=FDC2X14ReadCH(1);
	LCD_ShowNum(115,10,hq,15,16);	
	printf("%d\r\n",FDC2X14ReadCH(1));
		
    if(KEY0==0)
		{
    
     
			delay_ms(10);
		  if(KEY0==0)
			{
    
    text1=1;			
			}
		}
		if(KEY1==0)
		{
    
     
			delay_ms(10);
		  if(KEY1==0)
			{
    
    text2=1;			
			}
		}
		if(WK_UP==1)
		{
    
    
			delay_ms(10);
			if(WK_UP==1)
			{
    
    
				text3=1;
			}
		}


		while(text1)
		{
    
    	

		 	LCD_ShowString(25,45,240,320,16,"Show your hand");	   	
			delay_ms(1500);			                                
			A=FDC2X14ReadCH(1);                                               
		  LCD_ShowString(25,70,240,320,16,"Rock:yes");
			BEEP=!BEEP;                                         
			delay_ms(100);
			BEEP=!BEEP;		
			delay_ms(1500);			                              
			B=FDC2X14ReadCH(1);                                                  
		  LCD_ShowString(25,95,240,320,16,"Paper:yes");
			BEEP=!BEEP;                                        
			delay_ms(100);
			BEEP=!BEEP;		
			delay_ms(1500);			                                
			C=FDC2X14ReadCH(1);                                                  
		  LCD_ShowString(25,120,240,320,16,"Scissors:yes");
			BEEP=!BEEP;                                        
			delay_ms(100);
			BEEP=!BEEP;
			printf("%d\r\n",FDC2X14ReadCH(1));
      while(1)
			{
    
    
	        hq=FDC2X14ReadCH(1);	
				LCD_ShowNum(25,145,A,15,16);
				LCD_ShowNum(25,170,B,15,16);
				LCD_ShowNum(25,195,C,15,16);
				LCD_ShowNum(50,245,hq,15,16);
			 if(hq>(A-100000.0)&&(hq<(A+100000.0)))
			 {
    
    
		  	 LCD_ShowString(25,220,240,320,16,"RESULT:Rock    ");
			   
			 }	        
			  if(hq>(B-150000.0)&&(hq<(B+150000.0)))
				{
    
    
					LCD_ShowString(25,220,240,320,16,"RESULT:Paper    ");	
					
				}         
			  if(hq>(C-150000.0)&&(hq<(C+150000.0)))
				{
    
    	
					LCD_ShowString(25,220,240,320,16,"RESULT:Scissors    ");	
				}        
				if(hq>16600000.0)
				{
    
      
							LCD_ShowString(25,220,240,320,16," RESULT:                      ");          
				}
			printf("\r\n %d \r\n",FDC2X14ReadCH(1));
			}				
			
		}
		while(text2)
		{
    
    	

		 	LCD_ShowString(15,30,240,320,16,"Show your hand");	   	
			delay_ms(1500);			                                
			A=FDC2X14ReadCH(1);                                                
		  LCD_ShowString(15,50,240,320,16,"One:yes");
			BEEP=!BEEP;                                          
			delay_ms(100);
			BEEP=!BEEP;		
			delay_ms(1500);
			delay_ms(1500);
			B=FDC2X14ReadCH(1);  			
		  LCD_ShowString(15,70,240,320,16,"Two:yes");
			BEEP=!BEEP;                                        
			delay_ms(100);
			BEEP=!BEEP;		
			delay_ms(1500);
			delay_ms(1500);		
			C=FDC2X14ReadCH(1);                                                  
		  LCD_ShowString(15,90,240,320,16,"Three:yes");
			BEEP=!BEEP;                                          
			delay_ms(100);
			BEEP=!BEEP;
			delay_ms(1500);
			delay_ms(1500);
			
			D=FDC2X14ReadCH(1);                                                 
		  LCD_ShowString(15,110,240,320,16,"Four:yes");
			BEEP=!BEEP;                                          
			delay_ms(100);
			BEEP=!BEEP;
			delay_ms(1500);
			delay_ms(1500);
			
			E=FDC2X14ReadCH(1);                                                 
		  LCD_ShowString(15,130,240,320,16,"Five:yes");
			BEEP=!BEEP;                                          
			delay_ms(100);
			BEEP=!BEEP;
			delay_ms(1500);
			printf("%d\r\n",FDC2X14ReadCH(1));
			A1=(A-B)/2;
			A2=(B-C)/2;
			A3=(C-D)/2;
			A4=(D-E)/2;
		while(1){
    
    
					hq=FDC2X14ReadCH(1);	
					LCD_ShowNum(25,150,A,15,16);
					LCD_ShowNum(25,170,B,15,16);
					LCD_ShowNum(25,190,C,15,16);
					LCD_ShowNum(25,210,D,15,16);
					LCD_ShowNum(25,230,E,15,16);
					LCD_ShowNum(25,250,hq,15,16);
					     if((hq>E-A4)&&(hq<E+A4))
					{
    
    	  
						LCD_ShowString(25,270,240,320,16,"RESULT:5");
					}
					    if((hq>B-A1)&&(hq<B+A2))
					{
    
    				
							LCD_ShowString(25,270,240,320,16,"RESULT:2");
					}
							if((hq>A-A1)&&(hq<A+A1))
					{
    
      
							LCD_ShowString(25,270,240,320,16,"RESULT:1");           
					}
							if((hq>C-120000)&&(hq<C+110000))
					{
    
      
							LCD_ShowString(25,270,240,320,16,"RESULT:3");            
					}
							if((hq>D-A3)&&(hq<D+A4))
					{
    
      
							LCD_ShowString(25,270,240,320,16,"RESULT:4");            
					}
							if(hq>16800000.0)
					{
    
      
							LCD_ShowString(25,270,240,320,16,"RESULT:          ");            
					}
					}
	    }
}
}

测试流程:

先进行数据采集,再进行手势识别,已经采集了被测试者的手势信息且在测试时与采集时的手型不应差距过大,将会造成识别失败。具体流程,可根据代码梳理,比较简单

测试结果:

为了让读者有更好的体验,我这里加上了测试样例:
(1)模式一:
在这里插入图片描述
在这里插入图片描述
图5-2 比划“布”手势及显示
如图5-2所示,被测试者比划“布”手势放置于镀金属塑料板上该图为手势识别“布”及其显示结果。
在这里插入图片描述
在这里插入图片描述
图5-3 比划“石头”手势及显示
如图5-3所示,被测试者比划“石头”手势放置于镀金属塑料板上该图为手势识别“石头”及其显示结果。
在这里插入图片描述
在这里插入图片描述
图5-4 识别“剪刀”手势及显示
如图5-4所示,被测试者比划“剪刀”手势放置于镀金属塑料板上该图为手势识别“剪刀”及其显示剪刀的英文“scissors”。
模式二:
在这里插入图片描述
在这里插入图片描述
图5-5 比划“1”手势及显示
如图5-5所示,被测试者比划“1”手势放置于镀金属塑料板上该图为手势识别“1”及其显示结果。
在这里插入图片描述
在这里插入图片描述
图5-6 比划“2”手势及显示
如图5-6所示,被测试者比划“2”手势放置于镀金属塑料板上该图为手势识别“2”及其显示结果。
在这里插入图片描述
在这里插入图片描述
图5-7 比划“3”手势及显示
如图5-7所示,被测试者比划“3”手势放置于镀金属塑料板上该图为手势识别“3”及其显示结果。
在这里插入图片描述
在这里插入图片描述
图5-8 比划“4”手势及显示
如图5-8所示,被测试者比划“4”手势放置于镀金属塑料板上该图为手势识别“4”及其显示结果。
在这里插入图片描述
在这里插入图片描述
图5-9 比划“5”手势及显示
如图5-9所示,被测试者比划“5”手势放置于镀金属塑料板上该图为手势识别“5”及其显示结果。

接论:

本设计原理是一个数据采集,存储,传输,处理,显示的过程。本设计手势识别模式分为两种模式,分别实现对特定手势的识别。控制芯片采用的是STM32F103ZET6单片机,具有高性能数据处理能力,支持多模式的外设扩展。该系统除STM32单片机外,还有FDC2214电容检测模块,具有高灵敏电容值检测能力,体积小,多种数据采集模式提供选择。TFTLCD显示屏能完成数字符号显示以及彩色图片显示,5伏供电电源及金属板手势数据采集平台构成。技术核心是采用IIC技术获取数据寄存器数据,传输数据到MCU,经过对数据的滤波等数据处理方式,最终采用TFTLCD显示出能够识别的手势结果。在同一种模式下,每种手势感应对应不同的频率值,根据LC震荡电路求出变化电容值,根据临近变化电容值的(大概)最小区别软件编程,从而实现对手势模式一:石头,剪刀,布,模式二:1、2、3、4、5的识别。
本设计的不足在于识别的手势数量不足,在数据采集方面,对于手势的细微差别可能会造成判决结果不准确,容差率比较小,精确度相对较低,在数据处理方面,没能达到最佳的处理方式,只采用了一种数据滤波及微调处理,还需要更为合适的数据处理与多次数据处理方式。

猜你喜欢

转载自blog.csdn.net/weixin_42271802/article/details/106497827