基於FDC2214感測器的手勢識別裝置(MSP430)
阿新 • • 發佈:2019-01-08
今年的江蘇省電賽,我們選擇了手勢識別裝置(D題)。
裝置使用MSP430F5529開發板,TI的FDC2214電容感測器,外設使用4*4矩陣按鍵進行功能切換、數碼管顯示感測器數值、LED燈顯示手勢狀態。
FDC2214是4路輸入電容感測器,我們使用覆銅板平均分成八分,構成四路差分結構,識別結果比較穩定。
以下是實現程式碼:
#include "bsp.h" #define delaytime 250 //檢測到手勢後延時檢測比較時間 毫秒 #define Stable 10 //穩定後數值變化範圍 //#define scissors 500 //手勢剪刀分界 #define num0_1 400 //開始判斷的分界 #define rock 1900 //手勢剪刀石頭的分界 #define paper 2900 //手勢石頭布的分界 #define num1_2 800 //手勢數值1和2的分界 #define num2_3 1150 //手勢數值2和3的分界 #define num3_4 1450 //手勢數值3和4的分界 #define num4_5 1950 //手勢數值4_5的分界 #define ratio 6 //讀數右移位數 #define s1 0.67 //第1通道係數 #define s2 1 //第2通道係數 #define s3 1 //第3通道係數 #define s4 0.82 //第4通道係數 #define numfun5 50 //功能5 燈開始亮分界 #define Led0_off P3OUT |=BIT0 #define Led1_off P3OUT |=BIT1 #define Led2_off P3OUT |=BIT2 #define Led3_off P3OUT |=BIT3 #define Led4_off P3OUT |=BIT4 #define Led5_off P3OUT |=BIT5 #define Led6_off P3OUT |=BIT6 #define Led7_off P3OUT |=BIT7 #define Led0_on P3OUT &=~BIT0 #define Led1_on P3OUT &=~BIT1 #define Led2_on P3OUT &=~BIT2 #define Led3_on P3OUT &=~BIT3 #define Led4_on P3OUT &=~BIT4 #define Led5_on P3OUT &=~BIT5 #define Led6_on P3OUT &=~BIT6 #define Led7_on P3OUT &=~BIT7 #define buzzer_off P2OUT |=BIT0 #define buzzer_on P2OUT &=~BIT0 unsigned long int temp0_zero, temp1_zero, temp2_zero, temp3_zero; unsigned char numf = 0, numf1 = 0; unsigned char key1_f = 0, key2_f = 0, key3_f = 0, key4_f = 0, key5_f = 0; unsigned char key6_f = 0, key7_f = 0, key8_f = 0, key9_f = 0, key10_f = 0; unsigned char key11_f = 0, key12_f = 0, key13_f = 0, key14_f = 0, key15_f = 0; unsigned char key16_f = 0, key3_f_x = 1, key4_f_x = 1; unsigned char delayf = 1, ms_f = 0; unsigned int rock_p, paper_p; unsigned int num1_2_p, num2_3_p, num3_4_p, num4_5_p; unsigned int scissors_s, rock_s, paper_s; unsigned int num0_1_s, num1_2_s, num2_3_s, num3_4_s, num4_5_s; float temp_f; int main(void) { unsigned int temp, temp0_h, temp0_l, temp1_h, temp1_l, temp2_h, temp2_l, temp3_h, temp3_l; unsigned long int temp0, temp1, temp2, temp3; unsigned int temp_pr = 0, Difference = 0; // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; P3DIR = 0xff; P2DIR = 0xff; buzzer_off; P3OUT = 0xff; bsp_Init(); Init_Keypad(); _EINT(); Initdisplay(); delay_ms(500); delay_ms(500); //開機清零 temp0_h = ReadRegfdc2214(0x00); //讀取第1通道的值 temp0_l = ReadRegfdc2214(0x01); //讀取第1通道的值 temp0 = temp0_h; temp0 = (temp0 << 16) + temp0_l; temp0_zero = temp0; temp1_h = ReadRegfdc2214(0x02); //讀取第2通道的值 temp1_l = ReadRegfdc2214(0x03); //讀取第2通道的值 temp1 = temp1_h; temp1 = (temp1 << 16) + temp1_l; temp1_zero = temp1; temp2_h = ReadRegfdc2214(0x04); //讀取第3通道的值 temp2_l = ReadRegfdc2214(0x05); //讀取第3通道的值 temp2 = temp2_h; temp2 = (temp2 << 16) + temp2_l; temp2_zero = temp2; temp3_h = ReadRegfdc2214(0x06); //讀取第4通道的值 temp3_l = ReadRegfdc2214(0x07); //讀取第4通道的值 temp3 = temp3_h; temp3 = (temp3 << 16) + temp3_l; temp3_zero = temp3; while (1) { //讀取4通道資料 temp0_h = ReadRegfdc2214(0x00); //讀取第1通道的值 temp0_l = ReadRegfdc2214(0x01); //讀取第1通道的值 temp0 = temp0_h; temp0 = (temp0 << 16) + temp0_l; if (temp0_zero > temp0) temp0 = temp0_zero - temp0; else temp0 = 0; temp0 = temp0 >> ratio; temp1_h = ReadRegfdc2214(0x02); //讀取第2通道的值 temp1_l = ReadRegfdc2214(0x03); //讀取第2通道的值 temp1 = temp1_h; temp1 = (temp1 << 16) + temp1_l; if (temp1_zero > temp1) temp1 = temp1_zero - temp1; else temp1 = 0; temp1 = temp1 >> ratio; temp2_h = ReadRegfdc2214(0x04); //讀取第3通道的值 temp2_l = ReadRegfdc2214(0x05); //讀取第3通道的值 temp2 = temp2_h; temp2 = (temp2 << 16) + temp2_l; if (temp2_zero > temp2) temp2 = temp2_zero - temp2; else temp2 = 0; temp2 = temp2 >> ratio; temp3_h = ReadRegfdc2214(0x06); //讀取第4通道的值 temp3_l = ReadRegfdc2214(0x07); //讀取第4通道的值 temp3 = temp3_h; temp3 = (temp3 << 16) + temp3_l; if (temp3_zero > temp3) temp3 = temp3_zero - temp3; else temp3 = 0; temp3 = temp3 >> ratio; temp_f = temp0 * s1 + temp1 * s2 + temp2 * s3 + temp3 * s4; //求4通道讀數之和 temp = (unsigned int )temp_f; if(key5_f)//功能5 { if(temp0>numfun5)Led1_on; else Led1_off; if(temp1>numfun5)Led3_on; else Led3_off; if(temp2>numfun5)Led5_on; else Led5_off; if(temp3>numfun5)Led7_on; else Led7_off; if((temp0>numfun5)&&(temp1>numfun5)){Led2_on;}//Led1_off;Led3_off; else Led2_off; if((temp1>numfun5)&&(temp2>numfun5)){Led4_on;}//Led3_off;Led5_off; else Led4_off; if((temp2>numfun5)&&(temp3>numfun5)){Led6_on;}//Led5_off;Led7_off; else Led6_off; } //按鍵訊號處理 if ((key3_f == 1) && key9_f)//功能3訓練 鍵9 :剪刀資料儲存 { scissors_s = temp; Led5_on; key9_f = 0; } if ((key3_f == 1) && key10_f)//功能3訓練 鍵10 :石頭資料儲存 { rock_s = temp; Led6_on; key10_f = 0; } if ((key3_f == 1) && key11_f)//功能3訓練 鍵11 :布資料儲存 { paper_s = temp; Led7_on; key11_f = 0; } if ((key3_f == 2) && (key3_f_x))//功能3工作 { key3_f_x = 0; key9_f = 0; key10_f = 0; key11_f = 0; Led5_off; Led6_off; Led7_off; paper_p = (paper_s + rock_s) / 2; //設定布和石頭分界 rock_p = (rock_s + scissors_s) / 2; //設定剪刀和石頭分界 } if ((key4_f == 1) && key12_f)//功能4訓練 鍵12 :1資料儲存 { num0_1_s = temp; Display_l(1); key12_f = 0; } if ((key4_f == 1) && key13_f)//功能4訓練 鍵13 :2資料儲存 { num1_2_s = temp; Display_l(2); key13_f = 0; } if ((key4_f == 1) && key14_f)//功能4訓練 鍵14 :3資料儲存 { num2_3_s = temp; Display_l(3); key14_f = 0; } if ((key4_f == 1) && key15_f)//功能4訓練 鍵15 :4資料儲存 { num3_4_s = temp; Display_l(4); key15_f = 0; } if ((key4_f == 1) && key16_f)//功能4訓練 鍵16 :5資料儲存 { num4_5_s = temp; Display_l(5); key16_f = 0; } if ((key4_f == 2) && (key4_f_x))//功能4工作 { key4_f_x = 0; key12_f = 0; key13_f = 0; key14_f = 0; key15_f = 0; key16_f = 0; Display_l(16); num1_2_p = (num0_1_s + num1_2_s) / 2;//設定1和2分界 num2_3_p = (num1_2_s + num2_3_s) / 2;//設定2和3分界 num3_4_p = (num2_3_s + num3_4_s) / 2;//設定3和4分界 num4_5_p = (num3_4_s + num4_5_s) / 2;//設定4和5分界 } //4種工作狀態 if ((key1_f) || (key2_f) || (key3_f == 2) || (key4_f == 2)) { if (temp > num0_1) //如果數值大於下限,開始判別是哪個手勢 { temp_pr = temp;//記錄第一次資料,延時 delay_ms(delaytime);//延時設定時間 temp0_h = ReadRegfdc2214(0x00); //讀取第1通道的值 temp0_l = ReadRegfdc2214(0x01); //讀取第1通道的值 temp0 = temp0_h; temp0 = (temp0 << 16) + temp0_l; if (temp0_zero > temp0) temp0 = temp0_zero - temp0; else temp0 = 0; temp0 = temp0 >> ratio; temp1_h = ReadRegfdc2214(0x02); //讀取第2通道的值 temp1_l = ReadRegfdc2214(0x03); //讀取第2通道的值 temp1 = temp1_h; temp1 = (temp1 << 16) + temp1_l; if (temp1_zero > temp1) temp1 = temp1_zero - temp1; else temp1 = 0; temp1 = temp1 >> ratio; temp2_h = ReadRegfdc2214(0x04); //讀取第3通道的值 temp2_l = ReadRegfdc2214(0x05); //讀取第3通道的值 temp2 = temp2_h; temp2 = (temp2 << 16) + temp2_l; if (temp2_zero > temp2) temp2 = temp2_zero - temp2; else temp2 = 0; temp2 = temp2 >> ratio; temp3_h = ReadRegfdc2214(0x06); //讀取第4通道的值 temp3_l = ReadRegfdc2214(0x07); //讀取第4通道的值 temp3 = temp3_h; temp3 = (temp3 << 16) + temp3_l; if (temp3_zero > temp3) temp3 = temp3_zero - temp3; else temp3 = 0; temp3 = temp3 >> ratio; temp_f = temp0 * s1 + temp1 * s2 + temp2 * s3 + temp3 * s4; //求4通道讀數之和 temp = (unsigned int )temp_f; if(temp > temp_pr)Difference = temp - temp_pr;//記錄第二次資料,與延時前資料進行比較 else Difference = temp_pr - temp; if(Difference < Stable) //如果延時前後兩次資料相差小於設定值,則認為已經穩定,可以進行判斷。 { if ((key1_f) || (key3_f == 2)) { if (temp > paper_p)//判定為紙 { Led7_on; Led6_off; Led5_off; numf1 = 3; } else if ((temp > rock_p) && (numf1 < 3))//判定為石頭 { Led5_off; Led6_on; Led7_off; numf1 = 2; } else if (numf1 < 2)//判定為剪刀 { Led5_on; Led6_off; Led7_off; numf1 = 1; } } if ((key2_f) || (key4_f == 2)) { if (temp > num4_5_p)//判定為5 { Display_l(5); numf = 5; } else if ((temp > num3_4_p) && (numf < 5))//判定為4 { Display_l(4); numf = 4; } else if ((temp > num2_3_p) && (numf < 4))//判定為3 { Display_l(3); numf = 3; } else if ((temp > num1_2_p) && (numf < 3))//判定為2 { Display_l(2); numf = 2; } else if (numf < 2)//判定為1 { Display_l(1); numf = 1; } } } } else {//無手勢,清顯示 if ((key1_f) || (key3_f == 2)) { Led5_off; Led6_off; Led7_off; numf1 = 0; } if ((key2_f) || (key4_f == 2)) { Display_l(0); numf = 0; } } } //功能3、4訓練狀態時閃爍 if (delayf && getdelayf() == 0) { delayf = 0; delaytim(300); } if ((delayf == 0) && getdelayf() == 0) { delayf = 1; ms_f = ~ms_f; if (key3_f == 1) { if (ms_f) Led2_on; else Led2_off; } else if (key3_f == 2) Led2_on; else Led2_off; if (key4_f == 1) { if (ms_f) Led3_on; else Led3_off; } else if (key4_f == 2) Led3_on; else Led3_off; } Display_h(temp);//顯示當前測量數值 Key_Event();//檢測按鍵 if (key_Flag == 1)//如果檢測到按鍵,進行按鍵標誌設定。 { key_Flag = 0; buzzer_on; delay_ms(50); buzzer_off; switch (key_val) { case 1: { //鍵1 功能1 key1_f = ~key1_f; if (key1_f) { Led0_on; Led2_off; Led3_off; Led4_off; key3_f = 0; key4_f = 0; key5_f = 0; rock_p = rock; paper_p = paper; } else Led0_off; } break; case 2: { //鍵2 功能2 key2_f = ~key2_f; if (key2_f) { Led1_on; Led2_off; Led3_off; Led4_off; key3_f = 0; key4_f = 0; key5_f = 0; num1_2_p = num1_2; num2_3_p = num2_3; num3_4_p = num3_4; num4_5_p = num4_5; } else Led1_off; } break; case 3: { //鍵3 功能3 Led0_off; Led1_off; Led2_on; Led3_off; Led4_off; key1_f = 0; key2_f = 0; key5_f = 0; if (key3_f < 2) key3_f++; else key3_f = 0; if (key3_f == 1) key3_f_x = 1; } break; case 4: { //鍵4 功能4 Led0_off; Led1_off; Led2_off; Led3_on; Led4_off; key1_f = 0; key2_f = 0; key5_f = 0; if (key4_f < 2) key4_f++; else key4_f = 0; } break; case 5: { //鍵5 功能5 Led0_off; Led1_off; Led2_off; Led3_off; Led4_on; key1_f = 0; key2_f = 0; key3_f = 0; key4_f = 0; key5_f = 1; } break; case 6: { //清零鍵 temp0_h = ReadRegfdc2214(0x00); //讀取第1通道的值 temp0_l = ReadRegfdc2214(0x01); //讀取第1通道的值 temp0 = temp0_h; temp0 = (temp0 << 16) + temp0_l; temp0_zero = temp0; temp1_h = ReadRegfdc2214(0x02); //讀取第2通道的值 temp1_l = ReadRegfdc2214(0x03); //讀取第2通道的值 temp1 = temp1_h; temp1 = (temp1 << 16) + temp1_l; temp1_zero = temp1; temp2_h = ReadRegfdc2214(0x04); //讀取第1通道的值 temp2_l = ReadRegfdc2214(0x05); //讀取第1通道的值 temp2 = temp2_h; temp2 = (temp2 << 16) + temp2_l; temp2_zero = temp2; temp3_h = ReadRegfdc2214(0x06); //讀取第2通道的值 temp3_l = ReadRegfdc2214(0x07); //讀取第2通道的值 temp3 = temp3_h; temp3 = (temp3 << 16) + temp3_l; temp3_zero = temp3; } break; case 7: break; case 8: break; case 9: key9_f = 1; key10_f = 0; key11_f = 0; break; case 10: key9_f = 0; key10_f = 1; key11_f = 0; break; case 11: key9_f = 0; key10_f = 0; key11_f = 1; break; case 12: key12_f = 1; key13_f = 0; key14_f = 0; key15_f = 0; key16_f = 0; break; case 13: key12_f = 0; key13_f = 1; key14_f = 0; key15_f = 0; key16_f = 0; break; case 14: key12_f = 0; key13_f = 0; key14_f = 1; key15_f = 0; key16_f = 0; break; case 15: key12_f = 0; key13_f = 0; key14_f = 0; key15_f = 1; key16_f = 0; break; case 16: key12_f = 0; key13_f = 0; key14_f = 0; key15_f = 0; key16_f = 1; break; default: break; } } } }