省赛题目:

使用指定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=1ADS_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的识别。
本设计的不足在于识别的手势数量不足,在数据采集方面,对于手势的细微差别可能会造成判决结果不准确,容差率比较小,精确度相对较低,在数据处理方面,没能达到最佳的处理方式,只采用了一种数据滤波及微调处理,还需要更为合适的数据处理与多次数据处理方式。

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

  1. 基于FDC2214的手势识别

    基于FDC2214的手势识别 1.本次题目来源于2018年全国电子设计大赛D题,要求实现对石头.剪刀.布以及数字12345的识别:同时在上述基础上实现对手势的学习. 2.硬件实现: 硬件主要采用STM ...

  2. 【毕业设计项目】基于单片机的手势识别设计与实现 - 物联网 嵌入式 stm32 c51

    文章目录 1 简介 2 实现效果 3 使用场景 4 参数说明 5 注意事项 6 最后 1 简介 Hi,大家好,这里是丹成学长,今天向大家介绍一个学长做的单片机项目 基于单片机得手势识别系统 大家可用于 ...

  3. TI杯2019年全国电子设计大赛总结

    文章目录 准备 选题 准备材料 原理设计及仿真 代码部分 摄像头模块 Arduino模块 最后 准备 在比赛开始之前,我们团队对往年的国赛题目进行了分析比较,由于博主是计算机系(之前是电子信息)的小菜 ...

  4. 陕西省ti杯竞赛题目_2016陕西省TI杯电子设计竞赛-2—竞赛实施过程说明.doc

    PAGE 2016年TI杯竞赛陕西赛区竞赛实施过程说明 竞赛的重要性以及竞赛目的 陕西省大学生德州仪器(TI)杯模拟及模数混合电路应用设计竞赛是为了培养优秀的电子信息技术类人才而开展的针对在校大学生的 ...

  5. (D题FDC2214手势识别装置)2018年全国大学生电子设计大赛(TI杯)参赛经验总结

         每次写总结开始,都想要写一段开场白,比如怀念青春,时光飞逝什么的,这次要不要例外呢? 哈哈,就是想皮一下,下面进入正题:      时光飞逝,转眼间已经成为学校里(除了研究生)最老(呆的时间 ...

  6. D题:手势识别装置 -- 2018年TI杯大学生电子设计竞赛

    D题:手势识别装置 – 2018年TI杯大学生电子设计竞赛 文章目录 D题:手势识别装置 -- 2018年TI杯大学生电子设计竞赛 1.任务 2.要求 3. 说明 1.任务 基于TI公司传感芯片FDC ...

  7. 关于开展2020年全国大学生电子设计竞赛模拟电子系统设计专题邀请赛(TI杯)的第二次通知

    官方通知 摘要:全国大学生电子设计竞赛模拟电子系统专题邀请赛(TI杯),是全国大学生电子设计竞赛在非全国竞赛年举办的一项专题邀请赛(以下简称邀请赛),希望通过竞赛促进电子信息类学科专业基础课教学内容的 ...

  8. B题:灭火飞行器(本科)-- 2018年TI杯大学生电子设计竞赛

    B题:灭火飞行器(本科)-- 2018年TI杯大学生电子设计竞赛 文章目录 B题:灭火飞行器(本科)-- 2018年TI杯大学生电子设计竞赛 1.任务 2.要求 3.说明 1.任务 基于四旋翼飞行器设 ...

  9. B题-具有自动泊车功能的电动车赛题解析TI杯2022年省级大学生电子设计竞赛联赛(10月)

    1.赛题解析-具有自动泊车功能的电动车(B题) 2.完成本赛题必备的元器件清单 3.赛题实现与动作分解视频演示 4.任务实现软件部分讲解 5.倒车/侧方入库相关的参数调节方法 6.常见问题整理 无名小 ...

最新文章

  1. python numpy加速 cupy
  2. day01_03.人人都会编程
  3. c语言指针概述,C语言指针概述.doc
  4. 传输层TCP/UDP协议
  5. 【每天一道算法题】Numeric Keypad
  6. 14003.xilinx系统移植
  7. Queue 输出数据
  8. BZOJ1022 [SHOI2008]小约翰的游戏John (博弈论)
  9. 综合能源系统通用建模及规划方法研究—笔记
  10. 《细说PHP》第四版 样章 第二章 PHP的应用与发展 1
  11. 软件工程基础作业 可行性与需求分析
  12. cmd命令查询电脑序列号_硬盘序列号查询软件_如何查看电脑硬盘序列号
  13. win10 mstsc 设置
  14. Matplotlib下plt常用指令总结
  15. 使用ssh正向连接、反向连接、做socks代理的方法
  16. win10和linux怎么切换输入法,win10系统怎么切换输入法
  17. Linux-磁盘分区,挂载
  18. 单点定位2米精度?这张卡差点干掉了RTK(内有轨迹对比图)
  19. matlab中SPI值,挣值管理(PV、EV、AC、SV、CV、SPI、CPI)记忆之我见
  20. 根据单选框的选择来决定下拉框的禁用与否

热门文章

  1. 罗振宇向左,吴晓波向右
  2. 罗振宇 知识就是力量之 怎样重新获得别人的信任
  3. 【踩坑记录】为VMware虚拟机引用主机代理
  4. NOI 题目 试题 目录 信奥 历年
  5. springboot项目脚手架
  6. 百田游戏2014笔试题——找到有序序列中某个值第一次出现的位置,并打印
  7. CHM文件无法打开的解决方法
  8. 前端通信:ajax设计方案(三)--- 集成ajax上传技术
  9. 外贸人如何使用intbell挖掘优质客户
  10. 四年级计算机走进传统节日教案,四年级走进中国传统节日的作文范文