Рубрики
Схемы на AVR

Биометрическая система сканирования отпечатков пальцев на микроконтроллере AVR ATmega32

Как показывают многочисленные исследования в современном мире люди более склонны доверять машинам нежели другим людям. Сейчас, когда в мире активно развиваются такие технологии как искусственный интеллект, машинное обучение, чат-боты, синергия (совместная деятельность) между людьми и роботами с каждым годом все больше усиливается. В этой статье мы рассмотрим создание биометрической системы контроля доступа по отпечатку пальцев на основе микроконтроллера ATmega32 (семейство AVR). Эта система будет более надежной и больше защищена от обмана чем контроль посещений (доступа) вручную.

В этом проекте мы будем использовать датчик отпечатков пальцев чтобы с его помощью регистрировать посещения и осуществлять контроль доступа.

Необходимые компоненты

  1. Микроконтроллер ATmega32 (купить на AliExpress).
  2. Программатор AVR-ISP (купить на AliExpress), USBASP (купить на AliExpress) или другой подобный.
  3. Модуль считывания отпечатков пальцев r305 (купить на AliExpress).
  4. Кнопки (или мембранные кнопки) – 4 шт.
  5. Светодиод – 2 шт (купить на AliExpress).
  6. Резистор 1 кОм – 2 шт.
  7. Резистор 2,2 кОм.
  8. Адаптер питания на 12В.
  9. Соединительные провода.
  10. Звонок (зуммер) (купить на AliExpress).
  11. JHD_162ALCD (ЖК дисплей 16×2) (купить на AliExpress).
  12. Макетная плата.
  13. Модуль (часы) реального времени ds1307 или ds3231 (купить на AliExpress).
  14. Регулятор напряжения LM7805 (купить на AliExpress).
  15. Конденсаторы 10 и 1000 мкФ (купить на AliExpress).
  16. Burgstips male female (соединительные колодки).
  17. DC JACK (опционально).
  18. Транзистор BC547 (опционально) (купить на AliExpress).

Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158

Общие принципы работы схемы

В создаваемой нами системе контроля посещения (присутствия) на основе контроля отпечатков пальцев мы будем использовать датчик отпечатков пальцев чтобы идентифицировать конкретного человека. Мы будем использовать 4 кнопки чтобы записывать (вносить в список, регистрировать), удалять, инкрементировать, декрементировать данные отпечатков пальцев. Кнопка 1 будет использоваться для регистрации нового человека в системе. То есть когда будет нужно зарегистрировать новый отпечаток пальцев, то человеку будет необходимо нажать кнопку 1, после этого жидкокристаллический (ЖК) дисплей попросит его поместить палец на датчик отпечатков пальцев два раза, затем он попросит идентификатор (идентификационный) номер данного человека. Кнопка 2 также имеет двойную функцию, когда пользователь регистрирует новый палец, он должен будет выбрать себе идентификатор с помощью кнопок 3 и 4. После этого нажатием кнопки 1 (OK) он регистрирует выбранный идентификатор. Также кнопка 2 используется для сброса или удаления данных из энергонезависимой памяти (EEPROM) микроконтроллера.

Датчик отпечатков пальцев «захватывает» изображение отпечатка пальца, конвертирует его в соответствующий шаблон и сохраняет его в своей памяти в соответствии с идентификатором (ID) человека, который будет храниться в микроконтроллере. Весь процесс происходит под управлением микроконтроллера: получение изображения отпечатка пальца, конвертирование его в шаблон, сохранение в памяти идентификатора и т.д.

Схема устройства

Схема устройства приведена на следующем рисунке.

Микроконтроллер Atmega32 управляет всеми процессами на представленной схеме. Кнопки используются для записи (регистрации) пользователей, удаления, выбора идентификаторов, звонок – для индикации, а ЖК дисплей 16×2 выдает инструкции пользователю что делать в каждый момент времени.

Кнопки напрямую подсоединены к выводам микроконтроллера:

  • ENROL key 1 (кнопка регистрации) – к выводу PA2;
  • DEL key 2 (кнопка удаления) – к выводу PA3;
  • UP key 3 (кнопка инкрементирования) – к выводу PA0;
  • DOWN key 4 (кнопка декрементирования) – к выводу PA4.

Светодиод подсоединен к контакту PC2 и к «земле» через резистор 1 кОм. Контакты передачи (Tx) и приема (Rx) датчика отпечатков пальцев напрямую подсоединены к контактам последовательного порта микроконтроллера (PD0 и PD1). Вся схема запитывается от напряжения 5В, которое получается за счет использования регулятора напряжения LM7805, который запитывается от адаптера питания на 12В. Звонок подсоединен к контакту PC3. ЖК-дисплей используется в 4-битном режиме и его контакты RS, RW, EN, D4, D5, D6, и D7 напрямую подсоединены к контактам PB0, PB1, PB2, PB4, PB5, PB6, PB7 микроконтроллера. Модуль реального времени (RTC module) подсоединен к контактам PC0 и PC1, а контакт PD7 используется как «мягкий» (soft) вывод для получения текущего (реального) времени.

Как работает система доступа на основе отпечатков пальцев

Всегда, когда чей то палец прикладывается к датчику отпечатков пальцев, он захватывает изображение этого пальца и проверяет зарегистрирован ли какой-нибудь идентификатор (ID) с этим отпечатком в системе. Если идентификатор обнаруживается, то на ЖК дисплей выводится надпись что пользователь допущен, а звонок издает звуковой сигнал.

Вместе с датчиком отпечатков пальцев мы используем модуль реального времени для получения времени и даты. Время и дата доступны в системе постоянно, поэтому микроконтроллер может получить их в любое необходимое время – это требуется в тот момент времени, когда пользователь прикладывает свой палец к датчику отпечатков пальцев. Полученные данные микроконтроллер сохраняет в выделенный слот EEPROM.

Пользователь может загрузить данные доступа при помощи нажатия и удержания клавиши 4. Когда вы подадите питание на схему и подождете некоторое время, на экране ЖК дисплея высветится надпись ‘Downloading….’ (загрузка). Пользователь может видеть эти данные доступа на мониторе, в представленном программном коде UART программируется на контакт PD7 – в качестве передающего контакта (Tx) чтобы передавать данные на терминал. Но необходим USB конвертер чтобы можно было посмотреть данные по монитору.

Если пользователю необходимо удалить все данные, то тогда он должен нажать и удерживать кнопку 2. Спустя некоторое время на экране ЖК дисплея высветится надпись ‘Please wait…’ (пожалуйста подождите), а затем ‘Record Deleted successfully’ (запись удалена успешно). Эти два шага не показаны в видео, представленном в конце статьи.

Объяснение кода программы

Полный код программы приведен в конце статьи – он достаточно большой и может показаться немного трудным начинающим микроконтроллерщикам, поэтому в данном разделе статьи будет разъяснено назначение отдельных блоков программы. Вначале нужно подключить необходимые заголовочные файлы и записать необходимые макросы.

#define F_CPU 8000000ul
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

/***MACROS*/

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#define uchar unsigned char
#define uint unsigned int

#define LCDPORTDIR DDRB
#define LCDPORT PORTB
#define rs 0
#define rw 1
#define en 2

#define RSLow (LCDPORT&=~(1<<rs))
#define RSHigh (LCDPORT|=(1<<rs))
#define RWLow (LCDPORT&=~(1<<rw))
#define ENLow (LCDPORT&=~(1<<en))
#define ENHigh (LCDPORT|=(1<<en))

#define KeyPORTdir DDRA
#define key PINA
#define KeyPORT PORTA

После этого мы объявим некоторые переменные и массивы, необходимые для обработки данных об отпечатках пальцев. Также мы добавим некоторые функции для взаимодействия с модулем реального времени.

void RTC_stp()
{ 
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);           //остановить взаимодействие
}

void RTC_read()
{ 
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while((TWCR&0x80)==0x00);
TWDR=0xD0;                                         //RTC write (slave address)
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
TWDR=0x00;                                         //RTC write (word address)
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);              //start RTC  communication again
while ((TWCR&0x80)==0x00);
TWDR=0xD1;                                        // RTC command to read
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));  
}

Далее определим несколько функций, которые будут нам нужны для взаимодействия с ЖК дисплеем. С ЖК дисплеем будем взаимодействовать в 4-битном режиме. Также определим несколько функций, которые будут нам нужны для инициализации последовательного порта (UART) и обмена данными между датчиком отпечатков пальцев и микроконтроллером.

void serialbegin()
{
  UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
  UBRRH = (BAUD_PRESCALE >> 8);
  UBRRL = BAUD_PRESCALE;
  UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
  sei();
}

ISR(USART_RXC_vect)
{
char ch=UDR;
buf[ind++]=ch;
if(ind>0)
flag=1;
//serial1Write(ch);
}

void serialwrite(char ch)
{
while ((UCSRA & (1 << UDRE)) == 0);
UDR = ch;
}

void serialprint(char *str)
{
    while(*str)
    {
        serialwrite(*str++);
    }
}

Теперь определим еще ряд функций для последовательного порта (UART), которые будут использоваться для программного (software) UART. Он будет использоваться для передачи сохраненных данных в компьютер через последовательный терминал. Эти функции основаны на использовании программной задержки (delay-based) и не используют прерывания. Для данного UART (последовательного порта) мы будем использовать только передающий сигнал (tx signal) со скоростью 9600 бод/с.

void SerialSoftWrite(char ch)
{
PORTD&=~(1<<7);
_delay_us(104);
for(int i=0;i<8;i++)
{
if(ch & 1)
PORTD|=(1<<7);
else
PORTD&=~(1<<7);
_delay_us(104);
ch>>=1;
}
PORTD|=(1<<7);
_delay_us(104);
}

void SerialSoftPrint(char *str)
{
while(*str)
{
SerialSoftWrite(*str);
str++;
}
}

Далее определим функции, которые будут отвечать за отображение реального времени на ЖК дисплее. Представленные ниже функции будут использоваться для записи данных доступа в EEPROM и чтения их оттуда.

int eeprom_write(unsigned int add,unsigned char data)
{
while(EECR&(1<<EEWE));
EEAR=add;
EEDR=data;
EECR|=(1<<EEMWE);
EECR|=(1<<EEWE);
return 0;
}
char eeprom_read(unsigned int add)
{
while(EECR & (1<<EEWE));
EEAR=add;
EECR|=(1<<EERE);
return EEDR;
}

Далее идут функции, которые будут отвечать за чтение изображения отпечатка пальца, конвертирования его в соответствующий шаблон, сравнения его с хранящимися изображениями отпечатков пальцев и показе результатов на экране ЖК дисплея.

void matchFinger()
{
    //  lcdwrite(1,CMD);
    //  lcdprint("Place Finger"); 
    //  lcdwrite(192,CMD);
    //  _delay_ms(2000);
     if(!sendcmd2fp((char *)&f_detect[0],sizeof(f_detect)))
     {
         if(!sendcmd2fp((char *)&f_imz2ch1[0],sizeof(f_imz2ch1)))
         {
            if(!sendcmd2fp((char *)&f_search[0],sizeof(f_search)))
            {
LEDHigh;
buzzer(200);
                uint id= data[0];
                     id<<=8;
                     id+=data[1];
                uint score=data[2];
                        score<<=8;
                        score+=data[3];
                (void)sprintf((char *)buf1,"Id: %d",(int)id);
                lcdwrite(1,CMD);
                lcdprint((char *)buf1);
saveData(id);

_delay_ms(1000);
lcdwrite(1,CMD);
lcdprint("Attendance");
lcdwrite(192,CMD);
lcdprint("Registered");
_delay_ms(2000);
LEDLow;
            }

Далее идет функция, используемая для регистрации нового отпечатка пальца и отображения результата (статуса) на ЖК дисплее. Следующая за ней функция используется для удаления хранящегося отпечатка пальца из модуля с помощью его идентификатора (id number) и отображения статуса этой операции на ЖК дисплее. 

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((char *)buf1,"Finger ID %d ",id);
     lcdprint((char *)buf1);
     lcdwrite(192, CMD);
     lcdprint("Deleted Success");
     
  }
   else
   {
       lcdwrite(1,CMD);
       lcdprint("Error");
   }
   _delay_ms(2000);
}

Следующая функция ответственна за передачу данных доступа к последовательному терминалу при помощи программного (soft) UART (контакт PD7) и TTL к USB конвертеру.

/*function to show attendence data on serial monitor using softserial pin PD7*/
void ShowAttendance()
{
char buf[128];
lcdwrite(1,CMD);
lcdprint("Downloding....");
SerialSoftPrintln("Attendance Record");
SerialSoftPrintln(" ");
SerialSoftPrintln("S.No        ID1            ID2            Id3            ID4            ID5    ");
//serialprintln("Attendance Record");
//serialprintln(" ");
//serialprintln("S.No            ID1                     ID2                     Id3                     ID4                     ID5");
for(int cIndex=1;cIndex<=8;cIndex++)
{
sprintf((char *)buf,"%d    "
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    ",
cIndex,
eeprom_read((cIndex*6)),eeprom_read((cIndex*6)+1),eeprom_read((cIndex*6)+2),eeprom_read((cIndex*6)+3),eeprom_read((cIndex*6)+4),eeprom_read((cIndex*6)+5),
eeprom_read((cIndex*6)+48),eeprom_read((cIndex*6)+1+48),eeprom_read((cIndex*6)+2+48),eeprom_read((cIndex*6)+3+48),eeprom_read((cIndex*6)+4+48),eeprom_read((cIndex*6)+5+48),
eeprom_read((cIndex*6)+96),eeprom_read((cIndex*6)+1+96),eeprom_read((cIndex*6)+2+96),eeprom_read((cIndex*6)+3+96),eeprom_read((cIndex*6)+4+96),eeprom_read((cIndex*6)+5+96),
eeprom_read((cIndex*6)+144),eeprom_read((cIndex*6)+1+144),eeprom_read((cIndex*6)+2+144),eeprom_read((cIndex*6)+3+144),eeprom_read((cIndex*6)+4+144),eeprom_read((cIndex*6)+5+144),
eeprom_read((cIndex*6)+192),eeprom_read((cIndex*6)+1+192),eeprom_read((cIndex*6)+2+192),eeprom_read((cIndex*6)+3+192),eeprom_read((cIndex*6)+4+192),eeprom_read((cIndex*6)+5+192));


SerialSoftPrintln(buf);
//serialprintln(buf);
}
lcdwrite(192,CMD);
lcdprint("Done");
_delay_ms(2000);
}

Следующая функция используется для удаления данных доступа из энергонезависимой памяти (EEPROM) микроконтроллера.

void DeleteRecord()
{
lcdwrite(1,CMD);
lcdprint("Please Wait...");
for(int i=0;i<255;i++)
eeprom_write(i,10);
_delay_ms(2000);
lcdwrite(1,CMD);
lcdprint("Record Deleted");
lcdwrite(192,CMD);
lcdprint("Successfully");
_delay_ms(2000); 
} 

В функции main мы инициализируем все используемые модули и контакты ввода/вывода общего назначения. Также в ней будут представлены все контролирующие (управляющие) события.

Полный текст программы на языке С (Си)

В этом разделе статьи представлен полный текст программы. Буду надеяться что эксперименты с этой конструкцией доставят вам немало удовольствия. Если у вас есть вопросы по работе этого проекта можете задать их в комментариях к данной статье. Также, если кому интересно, могу написать адрес оригинала этой статьи (он на английском языке). Буду рад если поможете исправить неточности или опечатки в статье – все таки статья достаточно большая и не очень легкая для понимания, а все мы люди (следовательно, можем делать иногда ошибки).

/*
 * AttandeceSystem.c
 *
 * Created: 1/8/2019 10:10:44 PM
 *  Author: Evan
 */ 
 
#define F_CPU 8000000ul
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
/***MACROS*/
 
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
 
#define uchar unsigned char
#define uint unsigned int
 
#define LCDPORTDIR DDRB
#define LCDPORT PORTB
#define rs 0
#define rw 1
#define en 2
 
#define RSLow (LCDPORT&=~(1<<rs))
#define RSHigh (LCDPORT|=(1<<rs))
#define RWLow (LCDPORT&=~(1<<rw))
#define ENLow (LCDPORT&=~(1<<en))
#define ENHigh (LCDPORT|=(1<<en))
 
#define KeyPORTdir DDRA
#define key PINA
#define KeyPORT PORTA
 
#define OK 3
#define UP 0
#define DOWN 1
#define DEL 3
#define MATCH 1
#define ENROL 2
 
#define enrol (key & (1<<ENROL))   // key 1
#define match (key & (1<<MATCH))   // key 4
#define delet (key & (1<<DEL))   // key 2
#define up (key & (1<<UP))     // key 3
#define down (key & (1<<DOWN)) // key 4
#define ok (key & (1<<OK))      // key 2
 
#define LEDdir DDRC
#define LEDPort PORTC
 
#define LED 3
#define BUZ 2
 
#define LEDHigh (LEDPort += (1<<LED))  
#define LEDLow (LEDPort &= ~(1<<LED))
 
#define BUZHigh (LEDPort += (1<<BUZ))
#define BUZLow (LEDPort &= ~(1<<BUZ))
 
#define HIGH 1
#define LOW 0
 
#define PASS 0
#define ERROR 1
 
#define check(id) id=up<down?++id:down<up?--id:id;
 
#define maxId 5
#define dataLenth 6
#define eepStartAdd 10
 
/*variable*/
 
uchar buf[20];
uchar buf1[20];
volatile uint ind;
volatile uint flag;
uint msCount=0;
uint g_timerflag=1;
volatile uint count=0;
uchar data[10];
uint id=1;
int s,a,b,c;
 
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};
//const char f_readNotepad[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x4,0x19,0x0,0x0,0x1E};
//char f_writeNotepad[]={0xEF,0x1,0xFF,0xFF,0xFF,0xFF,0x1,0x0,0x24};
 
int timeStamp[7],day;
 
enum
{
 CMD=0,
 DATA, 
};
 
void buzzer(uint);
 
void lcdwrite(char ch,char r)
{
     LCDPORT=ch & 0xF0;
RWLow;
     if(r == 1)
RSHigh;
else 
RSLow;
     ENHigh;
     _delay_ms(5);
ENLow;
_delay_ms(10);
  
     LCDPORT=ch<<4 & 0xF0;
RWLow;
if(r == 1)
RSHigh;
else
RSLow;
ENHigh;
_delay_ms(5);
ENLow;
_delay_ms(10); 
}
 
void lcdprint(char *str)
{
    while(*str)
    {
        lcdwrite(*str++,DATA);
        //__delay_ms(20);
    }
}
 
void lcdbegin()
{
    uchar lcdcmd[5]={0x02,0x28,0x0E,0x06,0x01};
    uint i=0;
    for(i=0;i<5;i++)
    lcdwrite(lcdcmd[i], CMD);
}
 
void serialbegin()
{
  UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
  UBRRH = (BAUD_PRESCALE >> 8);
  UBRRL = BAUD_PRESCALE;
  UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
  sei();
}
 
ISR(USART_RXC_vect)
{
char ch=UDR;
buf[ind++]=ch;
if(ind>0)
flag=1;
//serial1Write(ch);
}
 
void serialwrite(char ch)
{
while ((UCSRA & (1 << UDRE)) == 0);
UDR = ch;
}
 
void serialprint(char *str)
{
    while(*str)
    {
        serialwrite(*str++);
    }
}
 
void serialprintln(char *str)
{
serialprint(str);
serialwrite(0x0d);
serialwrite(0x0a);
}
 
void serialFlush()
{
    for(int i=0;i<sizeof(buf);i++)
    {
        buf[i]=0;
    }
}
 
void SerialSoftWrite(char ch)
{
PORTD&=~(1<<7);
_delay_us(104);
for(int i=0;i<8;i++)
{
if(ch & 1)
PORTD|=(1<<7);
else
PORTD&=~(1<<7);
_delay_us(104);
ch>>=1;
}
PORTD|=(1<<7);
_delay_us(104);
}
 
void SerialSoftPrint(char *str)
{
while(*str)
{
SerialSoftWrite(*str);
str++;
}
}
 
void SerialSoftPrintln(char *str)
{
SerialSoftPrint(str);
SerialSoftWrite(0x0D);
SerialSoftWrite(0x0A);
}
 
int bcdtochar(char num)
{
return ((num/16 * 10) + (num % 16));
}
 
void RTC_start()
{
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while((TWCR&0x80)==0x00);
}
 
void RTC_stp()
{ 
TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);           //stop communication
}
 
void RTC_read()
{ 
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while((TWCR&0x80)==0x00);
TWDR=0xD0;                                         //RTC write (slave address)
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
TWDR=0x00;                                         //RTC write (word address)
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);              //start RTC  communication again
while ((TWCR&0x80)==0x00);
TWDR=0xD1;                                        // RTC command to read
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));  
}
 
void sec_init(unsigned char d)
{  
TWDR=d;                                       //second init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));  
}
 
void min_init(unsigned char d)
{  
TWDR=d;                                       //minute init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); 
}
 
void hr_init(unsigned char d)
{ 
TWDR=d;                                        //hour init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); 
}
 
void day_init(unsigned char d)
{ 
TWDR=d;                                          //days init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); 
}
 
void date_init(unsigned char d)
{ 
TWDR=d;                                          //date init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); 
}
 
void month_init(unsigned char d)
{ 
TWDR=d;                                         //month init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); 
}
 
void yr_init(unsigned char d)
{ 
TWDR=d;                                         //year init
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT))); 
}
 
int sec_rw()
{
TWCR|=(1<<TWINT)|(1<<TWEA);                         //RTC second read
while((TWCR & 0x80)==0x00);
return bcdtochar(TWDR);
}
 
int min_rw()
{ 
TWCR|=(1<<TWINT);                                   //RTC minute read
TWCR|=(1<<TWEA);
while((TWCR & 0x80)==0x00);
return bcdtochar(TWDR);
}
 
int hr_rw()
{ 
TWCR|=(1<<TWINT)|(1<<TWEA);                         //RTC hour read
while((TWCR & 0x80)==0x00);
return bcdtochar(TWDR);
}
 
int day_rd()
{ 
TWCR|=(1<<TWINT)|(1<<TWEA);                         //RTC day read
while((TWCR&0x80)==0x00);
return bcdtochar(TWDR);
}
 
int date_rw()
{ 
TWCR|=(1<<TWINT)|(1<<TWEA);                      //RTC date read
while((TWCR & 0x80)==0x00);
return bcdtochar(TWDR);
}
 
int month_rw()
{ 
TWCR|=(1<<TWINT)|(1<<TWEA);                     //RTC month read
while((TWCR & 0x80)==0x00);
return bcdtochar(TWDR);
}
 
int yr_rw()
{ 
TWCR|=(1<<TWINT);                                 //RTC year read
TWCR&=(~(1<<TWEA));
while((TWCR & 0x80)==0x00);
return bcdtochar(TWDR);
}
 
void device()
{
TWDR=0xD0;                                         //RTC write (slave address)
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
 
TWDR=0x00;                                        // word address write
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
}
 
void RTCTimeSet()
{
RTC_start();
device();
sec_init(0);
min_init(0x47);
hr_init(0x22);
day_init(0x03);
date_init(0x23);
month_init(0x08);
yr_init(0x19);
RTC_stp();
}
 
void show()
{
char tem[20];
sprintf(tem,"%d",timeStamp[0]);
lcdwrite(0x80,CMD);
lcdprint("Time:");
lcdprint(tem);
lcdwrite(':',DATA);
sprintf(tem,"%d",timeStamp[1]);
lcdprint(tem);
lcdwrite(':',DATA);
sprintf(tem,"%d",timeStamp[2]);
lcdprint(tem);
lcdprint("  ");
lcdwrite(0xc0,CMD);
lcdprint("Date:");
sprintf(tem,"%d",timeStamp[3]);
lcdprint(tem);
lcdwrite('/',DATA);
sprintf(tem,"%d",timeStamp[4]);
lcdprint(tem);
lcdwrite('/',DATA);
sprintf(tem,"%d",timeStamp[5]);
lcdprint("20");
if(timeStamp[5]<10)
lcdwrite('0',DATA);
lcdprint(tem);
lcdprint("   ");
}
 
void RTC()
{
RTC_read();
timeStamp[2]=sec_rw();
timeStamp[1]=min_rw();
timeStamp[0]=hr_rw();
day=day_rd();
timeStamp[3]=date_rw();
timeStamp[4]=month_rw();
timeStamp[5]=yr_rw();
RTC_stp();
show();
}
 
int eeprom_write(unsigned int add,unsigned char data)
{
while(EECR&(1<<EEWE));
EEAR=add;
EEDR=data;
EECR|=(1<<EEMWE);
EECR|=(1<<EEWE);
return 0;
}
char eeprom_read(unsigned int add)
{
while(EECR & (1<<EEWE));
EEAR=add;
EECR|=(1<<EERE);
return EEDR;
}
 
void saveData(int id)
{
uint cIndex= eeprom_read(id);
if(cIndex == 0)
cIndex=1;
uint cAddress= (cIndex*6) + (id-1)*48;
 
for(int i=0;i<6;i++)
eeprom_write(cAddress+i,timeStamp[i]);
eeprom_write(id,cIndex+1);
}
 
int sendcmd2fp(char *pack, int len)
{
  int res=ERROR;
  serialFlush();
  ind=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;
            //data=(char *)calloc(data_len, sizeof(data));
            for(int i=0;i<data_len-2;i++)
            {
                data[i]=buf[10+i];
            }
            res=PASS;
        }
 
        else
        {
         res=ERROR;
        }
        }
    }
    ind=0;
    flag=0;
    return res;
}
return res;
}
 
uint getId()
{
    uint id=0;
    lcdwrite(1, CMD);
    while(1)
    {
        //check(id);
if(up == LOW)
{
id++;
buzzer(200);
}
else if(down == LOW)
{
id--;
if(id==0)
id=0;
buzzer(200);
}
        else if(ok == LOW)
{
buzzer(200);
            return id;
}
lcdwrite(0x80, CMD);
(void)sprintf((char *)buf1,"Enter Id:%d  ",id);
lcdprint((char *)buf1);
_delay_ms(200);
    }
}
 
void matchFinger()
{
    //  lcdwrite(1,CMD);
    //  lcdprint("Place Finger"); 
    //  lcdwrite(192,CMD);
    //  _delay_ms(2000);
     if(!sendcmd2fp((char *)&f_detect[0],sizeof(f_detect)))
     {
         if(!sendcmd2fp((char *)&f_imz2ch1[0],sizeof(f_imz2ch1)))
         {
            if(!sendcmd2fp((char *)&f_search[0],sizeof(f_search)))
            {
LEDHigh;
buzzer(200);
                uint id= data[0];
                     id<<=8;
                     id+=data[1];
                uint score=data[2];
                        score<<=8;
                        score+=data[3];
                (void)sprintf((char *)buf1,"Id: %d",(int)id);
                lcdwrite(1,CMD);
                lcdprint((char *)buf1);
 
saveData(id);
 
_delay_ms(1000);
lcdwrite(1,CMD);
lcdprint("Attendance");
lcdwrite(192,CMD);
lcdprint("Registered");
_delay_ms(2000);
LEDLow;
            }
            
            else
            {
LEDHigh;
                lcdwrite(1,CMD);
                lcdprint("Not Found");
buzzer(5000);
LEDLow;
            }
         }
else
{
LEDHigh;
lcdwrite(1,CMD);
lcdprint("Not Found");
buzzer(2000);
LEDLow;
}
     }
      
     else
     {
         //lcdprint("No Finger"); 
     }
      //_delay_ms(200);
}
 
void enrolFinger()
{
     lcdwrite(1,CMD);
     lcdprint("Enroll Finger");
     _delay_ms(2000);
     lcdwrite(1,CMD);
     lcdprint("Place Finger"); 
     lcdwrite(192,CMD);
     _delay_ms(1000);
for(int i=0;i<3;i++)
{
     if(!sendcmd2fp((char *)&f_detect[0],sizeof(f_detect)))
     {
         //lcdprint("Finger Detected");
         //__delay_ms(1000);
        if(!sendcmd2fp((char *)&f_imz2ch1[0],sizeof(f_imz2ch1)))
        {
lcdwrite(192,CMD);
            lcdprint("Finger Detected");
            _delay_ms(1000);
          //  lcdwrite(1,CMD);
          //  lcdprint("Tamplate 1");
          //  __delay_ms(1000);
            lcdwrite(1,CMD);
            lcdprint("Place Finger");
            lcdwrite(192,CMD);
            lcdprint("    Again   "); 
            _delay_ms(2000);
            if(!sendcmd2fp((char *)&f_detect[0],sizeof(f_detect)))
            {
                if(!sendcmd2fp((char *)&f_imz2ch2[0],sizeof(f_imz2ch2)))
                {
                    lcdwrite(1,CMD);
                    lcdprint("Finger Detected");
                    _delay_ms(1000);
                    if(!sendcmd2fp((char *)&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((char *)&f_storeModel[0],sizeof(f_storeModel)))
                       {
    buzzer(200);
                            lcdwrite(1,CMD);
                            lcdprint("Finger Stored");
                            (void)sprintf((char *)buf1,"Id:%d",(int)id);
                            lcdwrite(192,CMD);
                            lcdprint((char *)buf1);
                            _delay_ms(1000);
                       }
                       
                       else
                       {
                            lcdwrite(1,CMD);
                            lcdprint("Finger Not Stored");
buzzer(3000);
                       }
                    }
                    else
                        lcdprint("Error");
                }
                else
                   lcdprint("Error");  
}   
else  
i=2;  
        } 
break;
     }
     if(i==2)
     {
lcdwrite(0xc0,CMD);
         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((char *)buf1,"Finger ID %d ",id);
     lcdprint((char *)buf1);
     lcdwrite(192, CMD);
     lcdprint("Deleted Success");
     
  }
   else
   {
       lcdwrite(1,CMD);
       lcdprint("Error");
   }
   _delay_ms(2000);
}
      
void lcdinst()
{
    lcdwrite(0x80, CMD);
    lcdprint("1-Enroll Finger");
    lcdwrite(0xc0, CMD);
    lcdprint("2-delete Finger");
    _delay_ms(10);
}
 
void buzzer(uint t)
{
BUZHigh;
for(int i=0;i<t;i++)
_delay_ms(1);
BUZLow;
}
 
/*function to show attendence data on serial moinitor using softserial pin PD7*/
void ShowAttendance()
{
char buf[128];
lcdwrite(1,CMD);
lcdprint("Downloding....");
SerialSoftPrintln("Attendance Record");
SerialSoftPrintln(" ");
SerialSoftPrintln("S.No        ID1            ID2            Id3            ID4            ID5    ");
//serialprintln("Attendance Record");
//serialprintln(" ");
//serialprintln("S.No            ID1                     ID2                     Id3                     ID4                     ID5");
for(int cIndex=1;cIndex<=8;cIndex++)
{
sprintf((char *)buf,"%d    "
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    "  
"%d:%d:%d  %d/%d/20%d    ",
cIndex,
eeprom_read((cIndex*6)),eeprom_read((cIndex*6)+1),eeprom_read((cIndex*6)+2),eeprom_read((cIndex*6)+3),
eeprom_read((cIndex*6)+4),eeprom_read((cIndex*6)+5),
eeprom_read((cIndex*6)+48),eeprom_read((cIndex*6)+1+48),eeprom_read((cIndex*6)+2+48),
eeprom_read((cIndex*6)+3+48),eeprom_read((cIndex*6)+4+48),eeprom_read((cIndex*6)+5+48),
eeprom_read((cIndex*6)+96),eeprom_read((cIndex*6)+1+96),eeprom_read((cIndex*6)+2+96),
eeprom_read((cIndex*6)+3+96),eeprom_read((cIndex*6)+4+96),eeprom_read((cIndex*6)+5+96),
eeprom_read((cIndex*6)+144),eeprom_read((cIndex*6)+1+144),eeprom_read((cIndex*6)+2+144),
eeprom_read((cIndex*6)+3+144),eeprom_read((cIndex*6)+4+144),eeprom_read((cIndex*6)+5+144),
eeprom_read((cIndex*6)+192),eeprom_read((cIndex*6)+1+192),eeprom_read((cIndex*6)+2+192),
eeprom_read((cIndex*6)+3+192),eeprom_read((cIndex*6)+4+192),eeprom_read((cIndex*6)+5+192));
 
SerialSoftPrintln(buf);
//serialprintln(buf);
}
lcdwrite(192,CMD);
lcdprint("Done");
_delay_ms(2000);
}
 
void DeleteRecord()
{
lcdwrite(1,CMD);
lcdprint("Please Wait...");
for(int i=0;i<255;i++)
eeprom_write(i,10);
_delay_ms(2000);
lcdwrite(1,CMD);
lcdprint("Record Deleted");
lcdwrite(192,CMD);
lcdprint("Successfully");
_delay_ms(2000); 
} 
 
int main()
{             
  LEDdir= 0xFF;
  LEDPort=0x03;
  KeyPORTdir=0xF0;
  KeyPORT=0x0F;  
  LCDPORTDIR=0xFF;
  DDRD+=1<<7;
  PORTD+=1<<7;
  serialbegin();
  SerialSoftPrint("Circuit Digest");
  //serialprint("Saddam Khan");
  buzzer(2000);
  
  lcdbegin();
  lcdprint("Attendance Systm");
  lcdwrite(192,CMD);
  lcdprint("Using AVR and FP");
  _delay_ms(2000);
  
  if(down == LOW)
  ShowAttendance();
  
  else if(delet == LOW)
DeleteRecord();    
 
  ind=0;    
  while(sendcmd2fp((char *)&passPack[0],sizeof(passPack)))
  {
     lcdwrite(1,CMD);
     lcdprint("FP Not Found");
     _delay_ms(2000);
     ind=0;
  }
  lcdwrite(1,CMD);
  lcdprint("FP Found");
  _delay_ms(1000);
  lcdinst();
  _delay_ms(2000);
  lcdwrite(1,CMD);
  //RTCTimeSet();
  while(1)
  { 
    RTC();
 
  //  if(match == LOW)
   // { 
matchFinger();
   // }
    
    if(enrol == LOW)
    {
buzzer(200);
        enrolFinger(); 
        _delay_ms(2000);
       // lcdinst();
    }
    
    else if(delet == LOW)
    {
buzzer(200);
        getId();
        deleteFinger();
        _delay_ms(1000);
    }
  } 
  return 0;
}

Видео, демонстрирующее работу схемы

12 ответов к “Биометрическая система сканирования отпечатков пальцев на микроконтроллере AVR ATmega32”

Где можно найти библиотеки с модулями по типу DS1307/DS3231 и сканера отпечатков пальцев для симуляции в протеусе.

К сожалению, не могу помочь вам в вашей проблеме

Такой вопрос для чего нужен транзистор BC547, и куда его подключать схеме. А так же что будет если убрать данный транзистор из схемы?

На представленной схеме данный транзистор не используется, но при желании с его помощью можно к микроконтроллеру AVR подключить устройства, для управления которыми тока с контактов микроконтроллера недостаточно, например, мощный светодиод вместо светодиода D2 в схеме. Как это сделано, к примеру, в данной статье (только в ней используется другой транзистор, но принцип тот же).

Функции R2 и R1 каковы тут? и что будет если их убрать, ну или изменить величину сопротивления в большую или меньшую сторону?

Резисторы R2 и R1 регулируют параметры отображения изображения на ЖК дисплее. Их номиналы можно изменить и, насколько я понимаю (но 100% гарантии именно для этой схемы дать не могу) их можно убрать совсем потому что большинство других схем на моем сайте, использующие ЖК дисплеи, не содержат этих резисторов

Вопрос: какую функцию тут играют светодиод D2 и еще J1 — это просто выводы для джамперов?
и еще Чертежа печатной платы случайно нету?

Cветодиод D2 — да, действительно, контакт для него в программе инициализируется, но потом не используется. Видимо, разработчики про него забыли. Я думаю он должен сигнализировать о каком-нибудь событии — например, отпечаток пальца правильный или неправильный, просто эту строчку забыли прописать в программе.
J1 — да, это просто выводы. Чертежа печатной платы к этому проекту нет, к сожалению.
Но если вам интересно, на мой взгляд, с датчиком отпечатков пальцев намного проще с помощью Arduino работать (вот статья на эту тему — из нее можно и некоторые идеи почерпнуть для доработки этого проекта), чем с с помощью микроконтроллера AVR

А этот проект устройства на AVR точно рабочий? чтобы повторить

Ну 100% гарантии я дать не могу поскольку я сам этот проект не собирал, а статья переводная с иностранного сайта. Представленное видео доказывает что он рабочий, но, к сожалению, из-за человеческого фактора возможны небольшие опечатки в программе — вероятность этого мала, но все же она ненулевая. Могу дать ссылку на первоисточник статьи, если нужно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *