Всего каких то лет 10 тому назад датчики отпечатков пальцев были своеобразной диковинкой, доступной только в дорогих устройствах. Сейчас же они стали значительно более доступными и их сфера применения значительно расширилась. Основное применение они находят в различных системах контроля доступа и безопасности для идентификации людей, которым разрешен доступ в охраняемую зону.
Ранее нашем сайте мы уже рассматривали подключение датчика отпечатков пальцев к микроконтроллеру AVR, платам Arduino и Raspberry Pi, в этой же статье мы рассмотрим его подключение к микроконтроллеру PIC16f877A. В нашем проекте мы сможем записывать новые отпечатки пальцев в систему, а также удалять уже имеющиеся в системе отпечатки пальцев.
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- Модуль датчика отпечатков пальцев (купить на AliExpress).
- Кнопки или клавиатура с 4 кнопками (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Потенциометр 10 кОм (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- Кварцевый генератор 18.432000 МГц.
- Конденсаторы 22 пФ (2шт.) (купить на AliExpress).
- Резисторы 150 Ом – 1 кОм (опционально) (купить на AliExpress).
- Светодиод (опционально) (купить на AliExpress).
- Источник напряжения питания 5v.
- Макетная или перфорированная плата, соединительные провода.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Схема проекта
Для управления нашим проектом мы будем использовать 4 кнопки. Кнопка 1 будет использоваться для проверки соответствия отпечатков пальцев и инкрементирования идентификатора (ID) отпечатка пальца при его сохранении или удаления из системы. Кнопка 2 будет использоваться для записи нового отпечатка пальцев и для декрементирования идентификатора (ID) отпечатка пальца при его сохранении или удаления из системы. Кнопка 3 будет использоваться для удаления сохраненного отпечатка пальца из системы, а кнопка 4 будет играть роль кнопки OK. Светодиод будет использоваться для индикации того, обнаружен ли отпечаток пальца или он соответствует заданному отпечатку.
В нашем проекте мы будем использовать модуль датчика отпечатков пальцев, который работает через последовательный порт связи (UART). С нашим микроконтроллером PIC он будет работать на скорости 57600 бод.
Схема подключения датчика отпечатков пальцев к микроконтроллеру PIC представлена на следующем рисунке.
Как видите, схема достаточно проста. Модуль датчика отпечатков пальцев подключен к последовательному порту (UART) микроконтроллера PIC. Для отображения информации системы используется ЖК дисплей 16x2. Его контакты данных d4, d5, d6 и d7 подключены к контактам RA0, RA1, RA2 и RA3 микроконтроллера соответственно. Потенциометр 10 кОм используется для регулировки контрастности ЖК дисплея.
Четыре кнопки (или четырехкнопочная клавиатура) подключены к контактам RD1, RD2 и RD порта PORTD RD0. Светодиод подключен к контакту RC3 порта PORTC. Для задания тактовой частоты микроконтроллера мы используем кварцевый генератор на 18.432000 MHz.
Общие принципы работы проекта
Для начала работы с проектом загрузите hex файл программы с помощью программатора (PIckit2, Pickit3 или другого подобного) в микроконтроллер PIC. После этого вы увидите приветственное сообщение на экране ЖК дисплея и затем на экране дисплея появится сообщение о выборе желаемой операции. Чтобы проверить отпечаток пальца нажмите кнопку 1, после чего на экране ЖК дисплея появится сообщение о том, что нужно поместить палец на датчик отпечатков пальцев. После того как вы поместите свой палец на модуль вы можете узнать сохранен ли уже ваш отпечаток пальца в системе или нет. Если сохранен, то на экране ЖК дисплея высветится идентификатор, под которым он сохранен, например, ‘ID:2’. Если не сохранен, на экране дисплея появится сообщение ‘Not Found’ (не найден).
Чтобы сохранить отпечаток пальца в систему необходимо нажать кнопку 2 и следовать инструкциям на экране ЖК дисплея.
Чтобы удалить отпечаток пальца из системы необходимо нажать кнопку 3. После этого на экране ЖК дисплея появится запрос о том, отпечаток пальца с каким идентификатором (ID) необходимо удалить. Затем используя кнопку инкрементирования (кнопка 1) или кнопку декрементирования (кнопка 2) необходимо выбрать нужный ID и нажать кнопку OK чтобы удалить его из системы. Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В нашей программе мы используем формат кадра чтобы обмениваться данными с модулем отпечатков пальцев. Когда мы передаем на модуль кадр запроса данных он отвечает нам используя тот же самый формат кадра. Все доступные команды (форматы кадров) можно посмотреть в даташите или руководстве пользователя на модуль датчика отпечатков пальцев R305.
В программе мы используем формат кадра, приведенный на следующем рисунке.
Первым делом в программе мы настроим биты конфигурации и макросы для используемых контактов для подключения ЖК дисплея, кнопок и светодиода. Затем мы объявим ряд используемых переменных и массивов и сконструируем формат кадра, который мы будем использовать для обмена данными с датчиком отпечатков пальцев.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
uchar buf[20]; uchar buf1[20]; volatile uint index=0; volatile int flag=0; uint msCount=0; uint g_timerflag=1; volatile uint count=0; uchar data[10]; uint id=1; enum { CMD, DATA, SBIT_CREN=4, SBIT_TXEN, SBIT_SPEN, }; const char passPack[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x7, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1B}; const char f_detect[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x3, 0x1, 0x0, 0x5}; const char f_imz2ch1[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x4, 0x2, 0x1, 0x0, 0x8}; const char f_imz2ch2[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x4, 0x2, 0x2, 0x0, 0x9}; const char f_createModel[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x3,0x5,0x0,0x9}; char f_storeModel[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x6,0x6,0x1,0x0,0x1,0x0,0xE}; const char f_search[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x8, 0x1B, 0x1, 0x0, 0x0, 0x0, 0xA3, 0x0, 0xC8}; char f_delete[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x7,0xC,0x0,0x0,0x0,0x1,0x0,0x15}; |
После этого запрограммируем ряд функций для работы с ЖК дисплеем.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
void lcdwrite(uchar ch,uchar rw) { LCDPORT= ch>>4 & 0x0F; RS=rw; EN=1; __delay_ms(5); EN=0; LCDPORT= ch & 0x0F; EN=1; __delay_ms(5); EN=0; } lcdprint(char *str) { while(*str) { lcdwrite(*str++,DATA); //__delay_ms(20); } } lcdbegin() { uchar lcdcmd[5]={0x02,0x28,0x0E,0x06,0x01}; uint i=0; for(i=0;i<5;i++) lcdwrite(lcdcmd[i], CMD); } |
Также запрограммируем функцию для инициализации последовательного порта связи (UART).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void serialbegin(uint baudrate) { SPBRG = (18432000UL/(long)(64UL*baudrate))-1; // baud rate @18.432000Mhz Clock TXSTAbits.SYNC = 0; //Setting Asynchronous Mode, ie UART RCSTAbits.SPEN = 1; //Enables Serial Port TRISC7 = 1; //As Prescribed in Datasheet TRISC6 = 0; //As Prescribed in Datasheet RCSTAbits.CREN = 1; //Enables Continuous Reception TXSTAbits.TXEN = 1; //Enables Transmission GIE = 1; // ENABLE interrupts INTCONbits.PEIE = 1; // ENable peripheral interrupts. PIE1bits.RCIE = 1; // ENABLE USART receive interrupt PIE1bits.TXIE = 0; // disable USART TX interrupt PIR1bits.RCIF = 0; } |
Затем запрограммируем функции для передачи команд модулю отпечатков пальцев и приема информации от него.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
void serialwrite(char ch) { while(TXIF==0); // Wait till the transmitter register becomes empty TXIF=0; // Clear transmitter flag TXREG=ch; // load the char to be transmitted into transmit reg } serialprint(char *str) { while(*str) { serialwrite(*str++); } } void interrupt SerialRxPinInterrupt(void) { if((PIR1bits.RCIF == 1) && (PIE1bits.RCIE == 1)) { uchar ch=RCREG; buf[index++]=ch; if(index>0) flag=1; RCIF = 0; // clear rx flag } } void serialFlush() { for(int i=0;i<sizeof(buf);i++) { buf[i]=0; } } |
Также запрограммируем функции, которые подготавливают данные для передачи модулю датчика отпечатков пальцев и декодируют данные, поступающие от модуля.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
int sendcmd2fp(char *pack, int len) { uint res=ERROR; serialFlush(); index=0; __delay_ms(100); for(int i=0;i<len;i++) { serialwrite(*(pack+i)); } __delay_ms(1000); if(flag == 1) { if(buf[0] == 0xEF && buf[1] == 0x01) { if(buf[6] == 0x07) // ack { if(buf[9] == 0) { uint data_len= buf[7]; data_len<<=8; data_len|=buf[8]; for(int i=0;i<data_len;i++) data[i]=0; for(int i=0;i<data_len-2;i++) { data[i]=buf[10+i]; } res=PASS; } else { res=ERROR; } } } |
После этого запрограммируем 4 функции для реализации основных функций нашей системы безопасности:
- unit getId() – функция для ввода идентификатора (ID) отпечатка пальца;
- void matchFinger() – функция для проверки отпечатка пальца;
- void enrolFinger() – функция для записи нового отпечатка пальца в систему;
- void deleteFinger() – функция для удаления отпечатка пальца из системы.
В основной функции программы main мы будем инициализировать контакты ввода/вывода (GPIOs), ЖК дисплей, последовательный порт связи (UART) и проверять подключен ли датчик отпечатков пальцев к микроконтроллеру PIC или нет. Затем в цикле while мы будем проверять нажатия кнопок и в зависимости от их состояния выполнять необходимые действия.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
int main() { void (*FP)(); ADCON1=0b00000110; LEDdir= 0; SWPORTdir=0xF0; SWPORT=0x0F; serialbegin(57600); LCDPORTDIR=0x00; TRISE=0; lcdbegin(); lcdprint("Fingerprint"); lcdwrite(192,CMD); lcdprint("Interfacing"); __delay_ms(2000); lcdwrite(1,CMD); lcdprint("Using PIC16F877A"); lcdwrite(192,CMD); lcdprint("Circuit Digest"); __delay_ms(2000); index=0; while(sendcmd2fp(&passPack[0],sizeof(passPack))) { lcdwrite(1,CMD); lcdprint("FP Not Found"); __delay_ms(2000); index=0; } lcdwrite(1,CMD); lcdprint("FP Found"); __delay_ms(1000); lcdinst(); while(1) { FP=match<enrol?matchFinger:enrol<delet?enrolFinger:delet<enrol?deleteFinger:lcdinst; FP(); } return 0; } |
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
#define _XTAL_FREQ 18432000 #include <xc.h> #include<pic.h> #include <stdio.h> #include <stdlib.h> // BEGIN CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) //END CONFIG #define uchar unsigned char #define uint unsigned int #define LCDPORTDIR TRISA #define LCDPORT PORTA #define RS RE1 #define EN RE0 #define SWPORTdir TRISD #define SWPORT PORTD #define enrol RD4 #define match RD5 #define delet RD7 #define ok RD6 #define up RD5 #define down RD4 #define LEDdir TRISC3 #define LED RC3 #define HIGH 1 #define LOW 0 #define PASS 0 #define ERROR 1 #define checkKey(id) id=up<down?++id:down<up?--id:id; uchar buf[20]; uchar buf1[20]; volatile uint index=0; volatile int flag=0; uint msCount=0; uint g_timerflag=1; volatile uint count=0; uchar data[10]; uint id=1; enum { CMD, DATA, SBIT_CREN=4, SBIT_TXEN, SBIT_SPEN, }; const char passPack[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x7, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1B}; const char f_detect[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x3, 0x1, 0x0, 0x5}; const char f_imz2ch1[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x4, 0x2, 0x1, 0x0, 0x8}; const char f_imz2ch2[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x4, 0x2, 0x2, 0x0, 0x9}; const char f_createModel[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x3,0x5,0x0,0x9}; char f_storeModel[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x6,0x6,0x1,0x0,0x1,0x0,0xE}; const char f_search[]={0xEF, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x8, 0x1B, 0x1, 0x0, 0x0, 0x0, 0xA3, 0x0, 0xC8}; char f_delete[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x7,0xC,0x0,0x0,0x0,0x1,0x0,0x15}; void lcdwrite(uchar ch,uchar rw) { LCDPORT= ch>>4 & 0x0F; RS=rw; EN=1; __delay_ms(5); EN=0; LCDPORT= ch & 0x0F; EN=1; __delay_ms(5); EN=0; } lcdprint(char *str) { while(*str) { lcdwrite(*str++,DATA); //__delay_ms(20); } } lcdbegin() { uchar lcdcmd[5]={0x02,0x28,0x0E,0x06,0x01}; uint i=0; for(i=0;i<5;i++) lcdwrite(lcdcmd[i], CMD); } void lcdinst() { lcdwrite(0x80, CMD); lcdprint("1-Match 2-Enroll"); lcdwrite(0xc0, CMD); lcdprint("3-delete Finger"); __delay_ms(10); } void serialbegin(uint baudrate) { SPBRG = (18432000UL/(long)(64UL*baudrate))-1; // baud rate @18.432000Mhz Clock TXSTAbits.SYNC = 0; //Setting Asynchronous Mode, ie UART RCSTAbits.SPEN = 1; //Enables Serial Port TRISC7 = 1; //As Prescribed in Datasheet TRISC6 = 0; //As Prescribed in Datasheet RCSTAbits.CREN = 1; //Enables Continuous Reception TXSTAbits.TXEN = 1; //Enables Transmission GIE = 1; // ENABLE interrupts INTCONbits.PEIE = 1; // ENable peripheral interrupts. PIE1bits.RCIE = 1; // ENABLE USART receive interrupt PIE1bits.TXIE = 0; // disable USART TX interrupt PIR1bits.RCIF = 0; } void serialwrite(char ch) { while(TXIF==0); // Wait till the transmitter register becomes empty TXIF=0; // Clear transmitter flag TXREG=ch; // load the char to be transmitted into transmit reg } serialprint(char *str) { while(*str) { serialwrite(*str++); } } void interrupt SerialRxPinInterrupt(void) { if((PIR1bits.RCIF == 1) && (PIE1bits.RCIE == 1)) { uchar ch=RCREG; buf[index++]=ch; if(index>0) flag=1; RCIF = 0; // очищаем флаг rx } } void serialFlush() { for(int i=0;i<sizeof(buf);i++) { buf[i]=0; } } int sendcmd2fp(char *pack, int len) { uint res=ERROR; serialFlush(); index=0; __delay_ms(100); for(int i=0;i<len;i++) { serialwrite(*(pack+i)); } __delay_ms(1000); if(flag == 1) { if(buf[0] == 0xEF && buf[1] == 0x01) { if(buf[6] == 0x07) // ack { if(buf[9] == 0) { uint data_len= buf[7]; data_len<<=8; data_len|=buf[8]; for(int i=0;i<data_len;i++) data[i]=0; for(int i=0;i<data_len-2;i++) { data[i]=buf[10+i]; } res=PASS; } else { res=ERROR; } } } index=0; flag=0; return res; } } uint getId() { uint id=0; lcdwrite(1, CMD); while(1) { lcdwrite(0x80, CMD); checkKey(id); sprintf(buf1,"Enter Id:%d ",id); lcdprint(buf1); __delay_ms(200); if(ok == LOW) return id; } } void matchFinger() { lcdwrite(1,CMD); lcdprint("Place Finger"); lcdwrite(192,CMD); __delay_ms(2000); if(!sendcmd2fp(&f_detect[0],sizeof(f_detect))) { if(!sendcmd2fp(&f_imz2ch1[0],sizeof(f_imz2ch1))) { if(!sendcmd2fp(&f_search[0],sizeof(f_search))) { lcdwrite(1,CMD); lcdprint("Finger Found"); uint id= data[0]; id<<=8; id+=data[1]; uint score=data[2]; score<<=8; score+=data[3]; sprintf(buf1,"Id:%d Score:%d",id,score); lcdwrite(192,CMD); lcdprint(buf1); LED=1; __delay_ms(1000); LED=0; } else { lcdwrite(1,CMD); lcdprint("Not Found"); } } } else { lcdprint("No Finger"); } __delay_ms(2000); } void enrolFinger() { lcdwrite(1,CMD); lcdprint("Enroll Finger"); __delay_ms(2000); lcdwrite(1,CMD); lcdprint("Place Finger"); lcdwrite(192,CMD); __delay_ms(1000); if(!sendcmd2fp(&f_detect[0],sizeof(f_detect))) { if(!sendcmd2fp(&f_imz2ch1[0],sizeof(f_imz2ch1))) { lcdprint("Finger Detected"); __delay_ms(1000); lcdwrite(1,CMD); lcdprint("Place Finger"); lcdwrite(192,CMD); lcdprint(" Again "); __delay_ms(2000); if(!sendcmd2fp(&f_detect[0],sizeof(f_detect))) { if(!sendcmd2fp(&f_imz2ch2[0],sizeof(f_imz2ch2))) { lcdwrite(1,CMD); lcdprint("Finger Detected"); __delay_ms(1000); if(!sendcmd2fp(&f_createModel[0],sizeof(f_createModel))) { id=getId(); f_storeModel[11]= (id>>8) & 0xff; f_storeModel[12]= id & 0xff; f_storeModel[14]= 14+id; if(!sendcmd2fp(&f_storeModel[0],sizeof(f_storeModel))) { lcdwrite(1,CMD); lcdprint("Finger Stored"); sprintf(buf1,"Id:%d",id); lcdwrite(192,CMD); lcdprint(buf1); __delay_ms(1000); } else { lcdwrite(1,CMD); lcdprint("Finger Not Stored"); } } else lcdprint("Error"); } else lcdprint("Error"); } else lcdprint("No Finger"); } } else { lcdprint("No Finger"); } __delay_ms(2000); } void deleteFinger() { id=getId(); f_delete[10]=id>>8 & 0xff; f_delete[11]=id & 0xff; f_delete[14]=(21+id)>>8 & 0xff; f_delete[15]=(21+id) & 0xff; if(!sendcmd2fp(&f_delete[0],sizeof(f_delete))) { lcdwrite(1,CMD); sprintf(buf1,"Finger ID %d ",id); lcdprint(buf1); lcdwrite(192, CMD); lcdprint("Deleted Success"); } else { lcdwrite(1,CMD); lcdprint("Error"); } __delay_ms(2000); } int main() { void (*FP)(); ADCON1=0b00000110; LEDdir= 0; SWPORTdir=0xF0; SWPORT=0x0F; serialbegin(57600); LCDPORTDIR=0x00; TRISE=0; lcdbegin(); lcdprint("Fingerprint"); lcdwrite(192,CMD); lcdprint("Interfacing"); __delay_ms(2000); lcdwrite(1,CMD); lcdprint("Using PIC16F877A"); lcdwrite(192,CMD); lcdprint("Circuit Digest"); __delay_ms(2000); index=0; while(sendcmd2fp(&passPack[0],sizeof(passPack))) { lcdwrite(1,CMD); lcdprint("FP Not Found"); __delay_ms(2000); index=0; } lcdwrite(1,CMD); lcdprint("FP Found"); __delay_ms(1000); lcdinst(); while(1) { FP=match<enrol?matchFinger:enrol<delet?enrolFinger:delet<enrol?deleteFinger:lcdinst; FP(); } return 0; } |