前言

本文是18年电赛赛题之一。本装置采用STM32F103与FDC2214通信,FDC2214极板与手构成的电容数值,经过FDC2214转换,传入MCU算法判断,在LCD显示出相应的手势。

方案

用FDC2214的一个电容检测端口接上铜板,铜板上放一块透明的聚氯乙烯(PVC)塑料板,手相当于另外一个极板,放在PVC塑料板上,但是不同的手势会使得极板的面积不同,因此与电容感应板之间产生的电容大小不同,因此根据一特性设置不同的阈值从而达到分辨不同手势的目的获取不同的电容数据,通过IIC发送给89C51,用芯片内储存的数据与采集的数据比较判断出相应的手势显示在lcd12864上;训练模式中,采集两次数据,求得平均值,选择好储存的手势,储存起来,然后返回判决模式,进入采集,判断。

系统流程图

主要程序

#include "bsp_fdc2214.h"
#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
#include "bsp_iic.h"
#include "usart.h"
#include "key.h"
#include "lcd.h"
#include "timer.h"

u32 chvalue; //传感器采集过来的数据
u8 num[11]; //数据字符串 显示到lcd的字符串数组
u8 keyvalue = 0;
u32 valuebuf[10] = {
9254000, 9140000, 9030000, 9010000, 8992000, 8986000
}; //存储 0-5根手指的值

void getvalue() //获取传感器数据并输出
{
chvalue = FDC2X14ReadCH(1); //多通道需要调整FDC2X14ReadCH(x)
printf("CH0=%d\n", chvalue); //串口输出
num[10] = '\0';
num[9] = chvalue % 10 + '0';
num[8] = chvalue / 10 % 10 + '0';
num[7] = chvalue / 100 % 10 + '0';
num[6] = chvalue / 1000 % 10 + '0';
num[5] = chvalue / 10000 % 10 + '0';
num[4] = chvalue / 100000 % 10 + '0';
num[3] = chvalue / 1000000 % 10 + '0';
num[2] = chvalue / 10000000 % 10 + '0';
num[1] = chvalue / 100000000 % 10 + '0';
num[0] = chvalue / 1000000000 % 10 + '0';
LCD_ShowString(180, 80, 210, 24, 24, num); //显示调试数据 到屏幕顶端
}

int main(void) {
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200);
KEY_Init(); //初始化与按键连接的硬件接口
LCD_Init();
IIC_Init();
InitSingleFDC2214(); //初始化单通道
//InitMultiFDC2214();//初始化多通道
TIM3_Int_Init(999, 7199); //10Khz的计数频率,计数到1000为100ms
POINT_COLOR = BLACK;
LCD_ShowString(168, 40, 210, 24, 24, "FDC2214 DATA");

while (1) {
getvalue();
LCD_ShowString(10, 400, 180, 24, 24, "Judgment mode");
LCD_ShowString(300, 400, 180, 24, 24, "Training mode");

if (keyvalue == 3) {
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
while (1) {
LCD_ShowString(10, 400, 180, 24, 24, "finger-guess");
LCD_ShowString(300, 400, 180, 24, 24, "finger-row");
LCD_ShowString(220, 600, 80, 24, 24, "exit");
if (keyvalue == 3) {
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
while (1) {
getvalue(); //获取fdc2214数据并输出
if (chvalue > valuebuf[2] - 15000 & chvalue < valuebuf[2] + 30000)
LCD_ShowString(220, 600, 80, 24, 24, "scissor"); //剪刀
else if (chvalue > valuebuf[0] - 15000 & chvalue < valuebuf[0] + 30000)
LCD_ShowString(220, 600, 80, 24, 24, "stone "); //石头
else if (chvalue > valuebuf[5] - 30000 & chvalue < valuebuf[5] + 15000)
LCD_ShowString(220, 600, 80, 24, 24, "cloth "); //布
else if (keyvalue == 2) {
keyvalue = 0;
LCD_Fill(220, 600, 310, 624, WHITE); //清除,石头剪刀,布的显示
break;
} else {
LCD_Fill(220, 600, 310, 624, WHITE);
}
}
} else if (keyvalue == 1) {
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
while (1) {
getvalue(); //获取fdc2214数据并输出
if (chvalue > valuebuf[1] - 10000 & chvalue < valuebuf[1] + 10000)
LCD_ShowString(240, 600, 80, 24, 24, "1"); // 1
else if (chvalue > valuebuf[2] - 8000 & chvalue < valuebuf[2] + 10000)
LCD_ShowString(240, 600, 80, 24, 24, "2"); //2
else if (chvalue > valuebuf[3] - 3000 & chvalue < valuebuf[3] + 8000)
LCD_ShowString(240, 600, 80, 24, 24, "3"); //3
else if (chvalue > valuebuf[4] - 3000 & chvalue < valuebuf[4] + 3000)
LCD_ShowString(240, 600, 80, 24, 24, "4"); //4
else if (chvalue > valuebuf[5] - 10000 & chvalue < valuebuf[5] + 3000)
LCD_ShowString(240, 600, 80, 24, 24, "5"); //5
else if (keyvalue == 2) {
keyvalue = 0;
LCD_Fill(220, 600, 310, 624, WHITE); //清除1.2.3.4.5的显示
break;
} else {
LCD_Fill(220, 600, 310, 624, WHITE);
}
}
} else if (keyvalue == 2) {
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
break;
}
}


} else if (keyvalue == 1) {
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
while (1) {
LCD_ShowString(10, 400, 180, 24, 24, "train-guess");
LCD_ShowString(300, 400, 180, 24, 24, "train-row");
LCD_ShowString(220, 600, 80, 24, 24, "exit");
if (keyvalue == 3) //进入猜拳训练
{
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
while (1) {
LCD_ShowString(10, 400, 480, 24, 24, "Press the button key-up when finished");
LCD_ShowString(220, 600, 80, 24, 24, "exit");
if (keyvalue == 4) {
keyvalue = 0;
LCD_Fill(10, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
getvalue();
while (1) {
LCD_ShowString(10, 400, 480, 24, 24, "key0-stone key1-scissor key2-cloth");
if (keyvalue == 1) {
keyvalue = 0;
valuebuf[0] = chvalue;
break;
} else if (keyvalue == 2) {
keyvalue = 0;
valuebuf[2] = chvalue;
break;
} else if (keyvalue == 3) {
keyvalue = 0;
valuebuf[5] = chvalue;
break;
}
}
} else if (keyvalue == 2) {
keyvalue = 0;
LCD_Fill(10, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
break;
}
}
} else if (keyvalue == 1) //进入划拳训练
{
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
while (1) {
LCD_ShowString(10, 400, 480, 24, 24, "Press the button key-up when finished");
LCD_ShowString(220, 600, 80, 24, 24, "exit");
if (keyvalue == 4) {
keyvalue = 0;
LCD_Fill(10, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
getvalue();
while (1) {
LCD_ShowString(10, 400, 480, 24, 24, "key0-1or2 key1-3or4 key2-5");
if (keyvalue == 1) {
keyvalue = 0;
LCD_Fill(10, 400, 480, 424, WHITE);
while (1) {
LCD_ShowString(10, 400, 180, 24, 24, "key0-1 key1-2");
if (keyvalue == 1) {
keyvalue = 0;
valuebuf[1] = chvalue; //存1
break;
}
if (keyvalue == 2) {
keyvalue = 0;
valuebuf[2] = chvalue; //存2
break;
}
}
break;
} else if (keyvalue == 2) {
keyvalue = 0;
LCD_Fill(10, 400, 480, 424, WHITE);
while (1) {
LCD_ShowString(10, 400, 180, 24, 24, "key0-3 key1-4");
if (keyvalue == 1) {
keyvalue = 0;
valuebuf[3] = chvalue; //存3
break;
}
if (keyvalue == 2) {
keyvalue = 0;
valuebuf[4] = chvalue; //存4
break;
}
}
break;
} else if (keyvalue == 3) {
keyvalue = 0;
valuebuf[5] = chvalue; //存5
break;
}
}
} else if (keyvalue == 2) {
keyvalue = 0;
LCD_Fill(10, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
break; //退出划拳训练
}
}
} else if (keyvalue == 2) //退出训练模式
{
keyvalue = 0;
LCD_Fill(10, 400, 200, 424, WHITE);
LCD_Fill(300, 400, 480, 424, WHITE);
LCD_Fill(220, 600, 310, 624, WHITE);
break;
}
}
}
delay_ms(100); //最外层循环延时
}
}

//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIMx更新中断标志

keyvalue = KEY_Scan(0); //得到键值

}
}

总结

抗干扰能力不强,需要优化算法提高抗干扰能力。


有任何疑问和想法,欢迎在评论区与我交流。