В данной статье мы рассмотрим создание системы контроля доступа на основе платы Raspberry Pi и радиочастотной идентификации (Radio Frequency Identification and Detection, RFID). Подобные системы получают с каждым годом все большее распространение в современном мире. На нашем сайте ранее мы уже рассматривали следующие проекты с использованием радиочастотной идентификации (RFID):
- cистема радиочастотной идентификации (RFID) на микроконтроллере AVR ATmega32;
- чтение радиочастотных меток с помощью Arduino Uno;
- электронный замок на основе радиочастотных меток (RFID) и Arduino;
- вход в Windows с помощью Arduino и радиочастотной идентификации (RFID);
- подключение модуля чтения RFID меток RDM6300 к Arduino.
Необходимые компоненты
- Плата Raspberry Pi (с установленной SD картой) (купить на AliExpress).
- Модуль чтения RFID меток EM-18 и карты (метки) к нему (купить на AliExpress).
- Кнопка.
- Зуммер (Buzzer) (купить на AliExpress).
- ЖК дисплей 16x2 (купить на AliExpress).
- Потенциометр 10 кОм (купить на AliExpress).
- Резисторы 10 кОм и 1 кОм (купить на AliExpress).
- Светодиод (купить на AliExpress).
- Источник питания с напряжением 5 В.
- Ethernet кабель.
- Макетная плата.
- Соединительные провода.
Модуль чтения RFID меток и метки к нему
Система радиочастотной идентификации (RFID) состоит из двух компонентов - модуля чтения RFID меток и RFID карт/меток. Когда мы помещаем RFID метку рядом с модулем для их считывания, он начинает последовательно считывать информацию с метки (карты). RFID метка содержит вшитый в нее код из 12 символов.
В этом проекте мы будем использовать один из наиболее простых и распространенных сейчас модулей чтения RFID меток - EM-18. На нашем сайте вы можете посмотреть все проекты с его использованием. Модуль EM-18 работает на скорости 9600 бод и использует электромагнит для передачи данных от себя меткам и от меток себе.
Принцип работы проекта
Плата Raspberry Pi управляет всеми процессами в нашем проекте. Модуль чтения RFID меток считывает идентификатор (ID) RFID метки/карты и передает его плате Raspberry Pi через UART (последовательный порт), плата проверяет идентификатор карты на корректность и высвечивает результат проверки на экране ЖК дисплея.
Структурная схема взаимодействия элементов проекта показана на следующем рисунке.
Когда пользователь прикладывает свою RFID карту/метку к модулю EM-18, модуль EM-18 считывает ее идентификатор и передает его плате Raspberry Pi, которая сравнивает его с заранее введенными идентификаторами. Если результат проверки положительный, то плата Raspberry Pi увеличивает счетчик посетителей на 1. Если же карты/метки нет в числе разрешенных, то Raspberry Pi показывает сообщение на экране ЖК дисплея ‘Invalid Card’ (неправильная карта) и включает зуммер. Также в проект добавлена кнопка – при ее нажатии на ЖК дисплее показывается общее количество пользователей, которое успешно прошло через систему. Для тестирования работы схемы мы будем использовать 4 RFID метки, из которых 3 будут корректными (разрешенными), а одна метка будет неразрешенной.
Схема проекта
Схема системы контроля доступа на Raspberry Pi и радиочастотной идентификации (RFID) представлена на следующем рисунке.
Схема содержит плату Raspberry Pi, модуль чтения RFID меток, зуммер, светодиод и ЖК дисплей. Плата Raspberry Pi управляет всеми процессами в схеме: считывание данных с модуля чтения RFID меток, сравнение этих данных с заранее введенными (predefined) данными, управление зуммером и управление отображением информации на ЖК дисплее.
ЖК дисплей подключен к плате Raspberry Pi в 4-битном режиме, его контакты RS, RW и EN непосредственно подключены к контактам GPIO 11, gnd и 10 платы Raspberry Pi. Контакты данных ЖК дисплея подключены к контактам GPIO 6, 5, 4 и 1 платы. Потенциометр 10 кОм используется для установки контрастности ЖК дисплея. Зуммер подключен к контакту GPIO7 платы Raspberry Pi. Три светодиода используются для индикации пользователей с корректными RFID метками, а один светодиод используется для индикации того, что система готова к сканированию RFID метки/карты. Кнопка подключена к контакту GPIO12 платы, при ее нажатии на ЖК дисплее отображается количество прошедших пользователей. Модуль чтения RFID меток подключен к порту последовательной связи платы Raspberry Pi (контакт GPIO16).
Установка библиотеки wiringPi в Raspberry Pi
Если мы пишем программу для Raspberry Pi на Python, то мы используем в ней команду вида "import RPi.GPIO as IO" для того чтобы иметь возможность работы с контактами ввода/вывода (GPIO Pins). Поскольку в этом проекте мы будем писать программу на языке C, то аналогичным образом нам необходимо подключить библиотеку wiringPi чтобы работать с контактами ввода/вывода (GPIO Pins) на языке C. Эту библиотеку можно установить вводя последовательно команды (одну за другой), приведенные ниже. Вы можете вводить эти команды непосредственно в терминале или с помощью SSH клиента, например, Putty.
sudo apt-get install git-core
sudo apt-get update
sudo apt-get upgrade
git clone git://git.drogon.net/wiringPi
cd wiringPi
git pull origin
cd wiringPi
./build
Проверить правильность установки библиотеки wiringPi можно с помощью следующих команд:
gpio -v
gpio readall
Объяснение программы для Raspberry Pi
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Первым делом в программе нам необходимо подключить используемые библиотеки и определить (задать) используемые контакты.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include<wiringPi.h> #include <wiringSerial.h> #include<stdio.h> #include <string.h> #define RS 11 #define EN 10 #define D4 6 #define D5 5 #define D6 4 #define D7 1 #define led1 23 #define led2 24 #define led3 25 #define led5 14 #define buzz 7 |
После этого объявим ряд переменных и массивов, которые нам понадобятся далее в программе.
1 2 3 4 5 6 |
int sp ; int count1=0,count2=0,count3=0; char ch; char rfid[13]; int i=0; char temp[5]; |
Далее запрограммируем ряд функций, которые нам понадобятся в программе. Функция void lcdcmd будет использоваться для передачи команд на ЖК дисплей.
1 2 3 4 5 6 7 8 9 10 11 |
void lcdcmd(unsigned int ch) { int temp=0x80; digitalWrite(D4, temp & ch<<3); digitalWrite(D5, temp & ch<<2); digitalWrite(D6, temp & ch<<1); digitalWrite(D7, temp & ch); digitalWrite(RS, LOW); digitalWrite(EN, HIGH); .... .... .... ..... |
Функция void write будет использоваться для передачи данных ЖК дисплею.
1 2 3 4 5 6 7 8 9 10 11 |
void write(unsigned int ch) { int temp=0x80; digitalWrite(D4, temp & ch<<3); digitalWrite(D5, temp & ch<<2); digitalWrite(D6, temp & ch<<1); digitalWrite(D7, temp & ch); digitalWrite(RS, HIGH); digitalWrite(EN, HIGH); .... .... .... ..... |
Функция void clear() используется для очистки экрана ЖК дисплея, функция setCursor – для установки позиции курсора, а функция void print – для передачи строки на ЖК дисплей.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void clear() { lcdcmd(0x01); } void setCursor(int x, int y) { int set=0; if(y==0) set=128+x; if(y==1) set=192+x; lcdcmd(set); } void print(char *str) { while(*str) { write(*str); str++; } } |
Функция void begin используется для инициализации ЖК дисплея в 4-битном режиме.
1 2 3 4 5 6 7 8 |
void begin(int x, int y) { lcdcmd(0x02); lcdcmd(0x28); lcdcmd(0x06); lcdcmd(0x0e); lcdcmd(0x01); } |
Функция void buzzer() используется для включения зуммера, функция void wait() – для задержки перед считыванием очередной карты/метки, функция serialbegin – для инициализации последовательной связи.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void buzzer() { digitalWrite(buzz, HIGH); delay(1000); digitalWrite(buzz, LOW); } void wait() { digitalWrite(led5, LOW); delay(3000); } void serialbegin(int baud) { if ((sp = serialOpen ("/dev/ttyS0",baud)) < 0) { clear(); print("Unable to open"); setCursor(0,1); print("serial Port"); } } |
В функции void setup() мы инициализируем все используемые контакты ввода/вывода, ЖК дисплей и UART (последовательный порт).
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void setup() { if (wiringPiSetup () == -1) { clear(); print("Unable to start"); setCursor(0,1); print("wiringPi"); } pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); ..... ...... ...... ....... |
Функция void get_card() используется для получения данных с модуля считывания RFID меток. В функции void main() мы высвечиваем необходимые сообщения на экране ЖК дисплея и сравниваем считанные метки с заранее определенными значениями.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
... ...... .... ..... if(strncmp(rfid,"0900711B6003",12)==0) { count1++; clear(); print("Attd. Registered"); setCursor(0,1); print("Studnet 1"); digitalWrite(led1, HIGH); buzzer(); digitalWrite(led1, LOW); wait(); } else if(strncmp(rfid,"090070FE6EE9",12)==0) { count2++; clear(); print("Attd. Registered"); setCursor(0,1); .... ..... .... ..... |
И, наконец, функция void check_button() используется для отображения общего числа посетителей, которые прошли через систему
1 2 3 4 5 6 7 8 9 10 |
void check_button() { if(digitalRead(in1)==0) { digitalWrite(led5, LOW); clear(); setCursor(0,0); print("std1 std2 std3"); .... .... .... ..... |
Исходный код программы на C
Код программы без комментариев, но практически все фрагменты программы достаточно подробно объяснены в предыдущем пункте статьи.
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 |
#include<wiringPi.h> #include <wiringSerial.h> #include<stdio.h> #include <string.h> #define RS 11 #define EN 10 #define D4 6 #define D5 5 #define D6 4 #define D7 1 #define led1 23 #define led2 24 #define led3 25 #define led5 14 #define buzz 7 #define in1 21 int sp ; int count1=0,count2=0,count3=0; char ch; char rfid[13]; int i=0; char temp[5]; void check_button(); void lcdcmd(unsigned int ch) { int temp=0x80; digitalWrite(D4, temp & ch<<3); digitalWrite(D5, temp & ch<<2); digitalWrite(D6, temp & ch<<1); digitalWrite(D7, temp & ch); digitalWrite(RS, LOW); digitalWrite(EN, HIGH); delay(10); digitalWrite(EN, LOW); digitalWrite(D4, temp & ch<<7); digitalWrite(D5, temp & ch<<6); digitalWrite(D6, temp & ch<<5); digitalWrite(D7, temp & ch<<4); digitalWrite(RS, LOW); digitalWrite(EN, HIGH); delay(10); digitalWrite(EN, LOW); } void write(unsigned int ch) { int temp=0x80; digitalWrite(D4, temp & ch<<3); digitalWrite(D5, temp & ch<<2); digitalWrite(D6, temp & ch<<1); digitalWrite(D7, temp & ch); digitalWrite(RS, HIGH); digitalWrite(EN, HIGH); delay(10); digitalWrite(EN, LOW); digitalWrite(D4, temp & ch<<7); digitalWrite(D5, temp & ch<<6); digitalWrite(D6, temp & ch<<5); digitalWrite(D7, temp & ch<<4); digitalWrite(RS, HIGH); digitalWrite(EN, HIGH); delay(10); digitalWrite(EN, LOW); } void clear() { lcdcmd(0x01); } void setCursor(int x, int y) { int set=0; if(y==0) set=128+x; if(y==1) set=192+x; lcdcmd(set); } void print(char *str) { while(*str) { write(*str); str++; } } void begin(int x, int y) { lcdcmd(0x02); lcdcmd(0x28); lcdcmd(0x06); lcdcmd(0x0e); lcdcmd(0x01); } void buzzer() { digitalWrite(buzz, HIGH); delay(1000); digitalWrite(buzz, LOW); } void wait() { digitalWrite(led5, LOW); delay(3000); } void serialbegin(int baud) { if ((sp = serialOpen ("/dev/ttyS0",baud)) < 0) { clear(); print("Unable to open"); setCursor(0,1); print("serial Port"); } } void setup() { if (wiringPiSetup () == -1) { clear(); print("Unable to start"); setCursor(0,1); print("wiringPi"); } pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); pinMode(led5, OUTPUT); pinMode(buzz, OUTPUT); pinMode(RS, OUTPUT); pinMode(EN, OUTPUT); pinMode(D4, OUTPUT); pinMode(D5, OUTPUT); pinMode(D6, OUTPUT); pinMode(D7, OUTPUT); pinMode(in1, INPUT); digitalWrite(in1, HIGH); begin(16,2); serialbegin(9600); } void get_card() { digitalWrite(led5, HIGH); i=0; while(i<12) { check_button(); while(serialDataAvail (sp)) { ch= serialGetchar(sp); rfid[i]=ch; fflush (stdout) ; i++; } } rfid[i]='\0'; buzzer(); return; } void main() { setup(); clear(); print("Attendance Systm"); setCursor(0,1); print("using RPI "); delay(2000); clear(); print("Circuit Digest"); setCursor(0,1); print("Welcomes you"); delay(2000); clear(); print("System Ready"); delay(1000); clear(); while(1) { clear(); print("Place Your Card:"); get_card(); setCursor(0,1); print(rfid); delay(1000); if(strncmp(rfid,"0900711B6003",12)==0) { count1++; clear(); print("Attd. Registered"); setCursor(0,1); print("Student 1"); digitalWrite(led1, HIGH); buzzer(); digitalWrite(led1, LOW); wait(); } else if(strncmp(rfid,"090070FE6EE9",12)==0) { count2++; clear(); print("Attd. Registered"); setCursor(0,1); print("Student 2"); digitalWrite(led2, HIGH); buzzer(); digitalWrite(led2, LOW); wait(); } else if(strncmp(rfid,"3F0072C049C4",12)==0) { count3++; clear(); print("Attd. Registered"); setCursor(0,1); print("Student 3"); digitalWrite(led3, HIGH); buzzer(); digitalWrite(led3, LOW); wait(); } else { clear(); print("Invalid Card"); buzzer(); buzzer(); wait(); } } } void check_button() { if(digitalRead(in1)==0) { digitalWrite(led5, LOW); clear(); setCursor(0,0); print("std1 std2 std3"); setCursor(1,1); sprintf(temp,"%d",count1); print(temp); setCursor(7,1); sprintf(temp,"%d",count2); print(temp); setCursor(13,1); sprintf(temp,"%d",count3); print(temp); delay(5000); digitalWrite(led5, HIGH); clear(); print("Place Your Card:"); } } |