CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

CraftDuino и RFID-модуль RC522. Обзор, подключение, тестовый скетч. Хардварный "Свой-чужой"

RFID-модуль RC522

Данил Борчевкин
команда lab409.ru


Что нам понадобится в данной статье:
1. CraftDuino или аналог;
2. Модуль RC522;
3. Макетная плата
4. Провода гибкие папа-папа
5. Два светодиода
6. Два резистора 470R или 1K


ОБЗОР



RFID-модуль 13.56 МГц с SPI-интерфейсом. В комплекте к модулю идет 2 RFID-метки — в виде карты и брелока.
Данный модуль может быть использован для различных радиолюбительких и коммерческих применений, в том числе контроля доступа, автоматической идентификации, робототехники, отслеживания вещей, платежных систем и т.д.
Основные характеристики:
• Основан на микросхеме MFRC522;
• Напряжение питания: 3.3V;
• Потребляемый ток :13-26mA
• Рабочая частота: 13.56MHz
• Дальность считывания: 0 ~ 60 мм
• Интерфейс: SPI, максимальная скорость передачи 10МБит/с
• Размер: 40мм х 60мм
• Чтение и запись RFID-меток.


Комплект модуля мне по душе по 3 причинам:
1. Сам модуль;
2. RFID-карта с возможностью перезаписи;
3. RFID-брелок (да, тот же, который используется для открытия домофонной двери) с возможностью перезаписи.

Даже один взгляд на данный комплект рисует в голове множество способов применения RC522:
1. Автоматический замок для открывания двери, ящика, шкафа;
2. Программатор для домофонных ключей;
3. Организация складского учета (но с этим чуть сложней — нужно закупить RFID-метки, такие же, как и на любом товаре в современном магазине);
4. Открытие закрытых ранее для вас дверей копирование и программирование карт для организации доступа к вашим сокровищам.

Важно заметить, что не каждая карта и ключ имеют возможность перезаписи, поэтому при покупке обращайте внимание на описание товара и ищите на буржуйском следующее «Programmable/ Writable», «can be written over and over again» или что-то в этом духе.


ПОДКЛЮЧЕНИЕ
RC522 имеет интерфейс SPI, а это значит, что костылей в этой статье не будет, т.к. CraftDuino имеет его из коробки.

Модуль RC имеет 8 выводов (написаны по порядку расположения на модуле):
VCC — Питание. Необходимо 3.3V;
RST — Reset. Линия сброса. Ни в коем случае не подключать к пину RESET на CraftDuino! Данный пин цепляется на цифровой порт с PWM;
GND — Ground. Земля=));
MISO — Master Input Slave Output — данные от ведомого к ведущему, SPI;
MOSI — Master Output Slave Input — данные от ведущего к ведомому, SPI;
SCK — Serial Clock — тактовый сигнал, SPI;
NSS — Slave Select — выбор ведомого, SPI;
IRQ — линия прерываний;

Для подключения к CraftDuino необходимо воспользоваться следующей распиновкой:
RC522 --> пин CraftDuino
VCC ----> 3.3V
RST ----> 9
GND ----> GND
MISO ---> 12
MOSI ---> 11
SCK ----> 13
NSS ----> 10
IRQ ----> NС — не подключаем [в рамках этого примера. Далее планируется его использовать]

ТЕСТОВЫЙ СКЕТЧ
Для работы с данным модулем есть 2 разных пути:
1. Изучить работу микросхемы, форматы команд и запросов и написать свой софт;
2. Не заморачиваться на первом этапе и воспользоваться готовой библиотекой и примерами.

Первый путь мы отложим до последующих статей, а пока воспользуемся готовой библиотекой, установим ее в Arduino IDE с помощью копирования в папку %путь установки%/libraries/RFID и зальем тестовый скетч cardRead:




/**
* Read a card using a mfrc522 reader on your SPI interface
* Pin layout should be as follows (on Arduino Uno):
* MOSI: Pin 11 / ICSP-4
* MISO: Pin 12 / ICSP-1
* SCK: Pin 13 / ISCP-3
* SS: Pin 10
* RST: Pin 9
*
* Script is based on the script of Miguel Balboa. 
* New cardnumber is printed when card has changed. Only a dot is printed
* if card is the same.
*
* @version 0.1
* @author Henri de Jong
* @since 06-01-2013
*/

#include <SPI.h>
#include <RFID.h>

#define SS_PIN 10
#define RST_PIN 9

RFID rfid(SS_PIN, RST_PIN); 

// Setup variables:
    int serNum0;
    int serNum1;
    int serNum2;
    int serNum3;
    int serNum4;

void setup()
{ 
  Serial.begin(9600);
  SPI.begin(); 
  rfid.init();
  
}

void loop()
{
    
    if (rfid.isCard()) {
        if (rfid.readCardSerial()) {
            if (rfid.serNum[0] != serNum0
                && rfid.serNum[1] != serNum1
                && rfid.serNum[2] != serNum2
                && rfid.serNum[3] != serNum3
                && rfid.serNum[4] != serNum4
            ) {
                /* With a new cardnumber, show it. */
                Serial.println(" ");
                Serial.println("Card found");
                serNum0 = rfid.serNum[0];
                serNum1 = rfid.serNum[1];
                serNum2 = rfid.serNum[2];
                serNum3 = rfid.serNum[3];
                serNum4 = rfid.serNum[4];
               
                //Serial.println(" ");
                Serial.println("Cardnumber:");
                Serial.print("Dec: ");
		Serial.print(rfid.serNum[0],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[1],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[2],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[3],DEC);
                Serial.print(", ");
		Serial.print(rfid.serNum[4],DEC);
                Serial.println(" ");
                        
                Serial.print("Hex: ");
		Serial.print(rfid.serNum[0],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[1],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[2],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[3],HEX);
                Serial.print(", ");
		Serial.print(rfid.serNum[4],HEX);
                Serial.println(" ");
             } else {
               /* If we have the same ID, just write a dot. */
               Serial.print(".");
             }
          }
    }
    
    rfid.halt();
}


Данный скетч выполняет следующие действия:
1. Инициализирует RC522;
2. Если обнаруживает RFID-метку, то выводит ее номер в десятичной и шестнадцатеричной системах исчисления;
3. Ожидает следующей метки. Если предыдущая метка не убрана от модуля и продолжает считываться, то выводит в com-порт точку.

Я не сказал бы, что данный скетч мне нравится, но пример есть пример.

СВОЙ-ЧУЖОЙ
Для интереса, давайте запилим распознавание определенной карты. Чтобы это выполнить, необходимо выполнить следующую логику работы:
1. Создать массив с номером известной карты в качестве разрешенного;
2. Считать серийный номер и записать его в отдельный массив;
3. Произвести поэлементное сравнение разрешенного номера со считанным;
4. В зависимости от результата, выполнить разные действия.

Не только из-за лени переделаем вышеприведенный пример:
serNum0 = rfid.serNum[0];
serNum1 = rfid.serNum[1];
serNum2 = rfid.serNum[2];
serNum3 = rfid.serNum[3];
serNum4 = rfid.serNum[4];

Этот колхоз заменим на трушное считывание в массив unsigned char readnig_card[5] и его вывод через цикл for


Serial.println("Card found");
Serial.println("Cardnumber:"); 
for (i = 0; i < 5; i++)
{     
  Serial.print(rfid.serNum[i]);
  Serial.print(" ");
  reading_card[i] = rfid.serNum[i];
}


На самом деле, отказ от циклов, массивов и структур сложнее if — нормальная практика у китайских программистов. Более подробно можно почитать здесь


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


for (i = 0; i < 5; i++)
{
  if (reading_card[i]!=master[i])
    {
      break;
    }
}
if (i == 5)
{
  allow();
}
else
{
  denied();
}


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


Для индикации возьмем 2 светодиода (в моем случае это синий и желтый), и прицепим их на цифровые порты 6 и 7, как показано на рисунке ниже. Кроме того, не забываем об ограничении тока посредством резистора.



Итого, получаем скетч

/*
www.lab409.ru
Danil Borchevkin
15/12/2013

* MOSI: Pin 11 / ICSP-4
* MISO: Pin 12 / ICSP-1
* SCK: Pin 13 / ISCP-3
* SS: Pin 10
* RST: Pin 9
*/

#include <SPI.h>
#include <RFID.h>

#define SS_PIN 10
#define RST_PIN 9
#define BLUE_LED 6
#define YELLOW_LED 7

RFID rfid(SS_PIN, RST_PIN); 

unsigned char reading_card[5]; //for reading card
unsigned char master[5] = {114,13,207,204,124}; // allowed card
unsigned char i;

void indication(int led);
void allow();
void denied();

void setup()
{ 
  Serial.begin(9600);
  SPI.begin(); 
  rfid.init();
  pinMode(BLUE_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
}

void loop()
{
    if (rfid.isCard()) 
    {
        if (rfid.readCardSerial()) 
        {
                /* Reading card */
                Serial.println(" ");
                Serial.println("Card found");
                Serial.println("Cardnumber:"); 
                for (i = 0; i < 5; i++)
                {     
		  Serial.print(rfid.serNum[i]);
                  Serial.print(" ");
                  reading_card[i] = rfid.serNum[i];
                }
                Serial.println();
                //verification
                for (i = 0; i < 5; i++)
                {
                  if (reading_card[i]!=master[i])
                  {
                    break;
                  }
                }
                if (i == 5)
                {
                  allow();
                }
                else
                {
                  denied();
                }
         } 
    }
    rfid.halt();
}

void allow()
{
  Serial.println("Access accept!");
  indication(BLUE_LED);
}
void denied()
{
  Serial.println("Access denied!");
  indication(YELLOW_LED);
}
void indication(int led)
{
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
}


Теперь у нас все довольно серьезней и интересней. Уже можно организовывать доступ в помещение. Но есть огромное НО — то, что мы выводим как серийный номер, нифига им не является (по крайней мере, в таком виде) — советую покопаться в самой библиотеке и понять, что UID номер карты перевернут, а один из байтов — CRC.

Ссылки
Даташит на микросхему MFRC522
Репозиторий цикла статей с даташитами, примерами, библиотекой и т.д.
Ссылка на скачивание библиотеки

Комментарии (57)

RSS свернуть / развернуть
+
+1
Спасибо за статью, жду продолжения.
Очень интересно :) Особенно хочется узнать о перезаписи меток, об этом вообще нет нигде ни слова…
avatar

zsm

  • 25 декабря 2013, 23:23
+
0
Спасибо за статью.
Попробовал сделать тоже самое, для начала. Соединил uno с моделем rc522 таким образом:
SAD(SS) 10
SCK 13
MOSI 11
MISO 12
GND GND
RST 9
+3.3V 3.3V

Диод d1 горит, но rfid.isCard() всегда возвращает 0. И на карту, ессно, модель не реагирует. Может есть какие-нибудь очевидные ответы?
avatar

pashkash

  • 19 января 2014, 08:44
+
0
модуль*

Ради смеха попробовал вашу распиновку из из статьи, не смотря на подписи на плате (http://www.tinydeal.com/rfid-rc522-rf-ic-card-sensor-module-suite-p-114596.html), благо питание и земля совпали. Результат тот же — не определяется модуль. Попробовал с разными либами — пока нет положительного результата.
avatar

pashkash

  • 19 января 2014, 09:54
+
0
Диод D1 не должен гореть, кроме как в случае, если зарегистрирована карта, которая указана как master.

Очевидный ответ — собрать полностью точно так же, как и в статье, чаще всего — ошибка подключения.
А можно описание того модуля, которым вы пользуетесь? Просто есть такая возможность, что между ними существует какая-то разница
avatar

danil_borchevkin

  • 19 января 2014, 16:36
+
0
Ну неделе попробую на леонарде и меге, как раз должны придти — отпишусь.
Модуль RFID из этого набора www.tinydeal.com/ru/rfid-learning-module-set-for-arduino-p-101545.html
отдельно вот: www.tinydeal.com/ru/rfid-rc522-rf-ic-card-sensor-module-suite-p-114596.html

Я так понимаю, он как у вас в статье. Те же 2 rw ключа в комплекте.

Спасибо, что сказали, что диод гореть не должен. Хотя на видео на ютубе www.youtube.com/watch?v=zi1JqA4CPAk он горит.
avatar

pashkash

  • 19 января 2014, 16:45
+
0
да, модули похожи, но есть одна разница — микросхема модуля, указанного в статье имеет год выпуска 2012, а указанная на сайте tinydeal — 2007 (вторая строчка в маркировке микросхемы)Судя по даташиту на сайте nxp, микросхемы совместимы в возрастающем порядке (т.е пишем под 1.0 — подходит к 2.0), про обратную совместимость ни слова. Может быть еще и в этом проблема, хотя шанс очень низкий.

По поводу зажигания диода — в коде все прозрачно — если детектируем мастер карут, происходит вызов фунции allow(), предназначенной для выполнения действий, связанных с нужной нам картой. из allow() вызывается уже indication(int led), который отвечает за моргание, где led — номер выхода, где висит светодиод

avatar

danil_borchevkin

  • 19 января 2014, 16:57
+
0
Платы только в пятницу пришли, извините за долгий ответ. Ситуация пока без изменений. Попробую заказать ещё несколько rfid шилдов и проверить.
avatar

pashkash

  • 10 февраля 2014, 20:24
+
0
Я бы вам советовал, прежде всего, обратиться к вашему поставщику, выяснить этот вопрос, по возможности попросить схематику, описание используемых решений и компонентов, тогда, я думаю, ситуация быстро прояснится.
avatar

danil_borchevkin

  • 10 февраля 2014, 21:04
+
0
Спасибо за совет. Если под схематикой понимается подписи к ногам — то есть на самом модуле. В соответствии с ними я подсоединяю провода. Но к поставщику обращусь, вы правы.
avatar

pashkash

  • 10 февраля 2014, 21:31
+
0
На карте из Калининграда всё прекрасно работает. Поэтому пока буду считать, что из Китая пришёл брак или что-то уж совсем старое. Спасибо.
avatar

pashkash

  • 7 марта 2014, 13:31
+
0
Спасибо, что сказали, что диод гореть не должен. Хотя на видео на ютубе www.youtube.com/watch?v=zi1JqA4CPAk SaveFrom.net он горит.


Это моё видео, там совсем другой скетч загружен, библиотека RFID в нём не используется, там только SPI.
avatar

DimanRoad

  • 25 января 2014, 10:44
+
0
youtu.be/omB91owk3X8 вот тут работа с красным и зелёным светодиодом, код из этой статьи, чуть подправлена, добавлена серва(имитирует открытие двери при допустимом ключе)
avatar

DimanRoad

  • 25 января 2014, 10:47
+
0
круто! Во что-нибудь более серьезное переросло?
avatar

danil_borchevkin

  • 10 февраля 2014, 21:02
+
0
Заказал другой модуль, на нём всё ок, спасибо.
avatar

pashkash

  • 7 марта 2014, 13:32
+
0
вопрос такой, 125кГц вые метки и карты работают на этом модуле?
avatar

k0der

  • 12 апреля 2014, 05:57
+
0
Нет, данный модуль читает только метки стандарта ISO 14443 A бренда Mifare
avatar

danil_borchevkin

  • 13 апреля 2014, 10:55
+
0
Статья классная, хотелось бы продолжения цикла.
Если не секрет, то когда увидим продолжение?
avatar

ssergo

  • 24 июня 2014, 07:35
+
0
Ребята! Все сайты облазил, как у Вас работает этот код? У меня же компилятор выдает ошибку на этой строчке, почти в самом начале!

RFID rfid(SS_PIN, RST_PIN);

Подскажите что не так??
avatar

Saushin-Eldar

  • 24 января 2015, 09:50
+
0
Скопируйте и запостите в эту ветку ошибку, тогда я вам смогу помочь.
avatar

danil_borchevkin

  • 24 января 2015, 16:37
+
0
sketch_jan25a:7: error: 'RFID' does not name a type
sketch_jan25a.ino: In function 'void setup()':
sketch_jan25a:20: error: 'rfid' was not declared in this scope
sketch_jan25a.ino: In function 'void loop()':
sketch_jan25a:27: error: 'rfid' was not declared in this scope
sketch_jan25a:76: error: 'rfid' was not declared in this scope
это отчет об ошибке… компилятор выделяет ту строчку, которую я прислал ранее…
avatar

Saushin-Eldar

  • 25 января 2015, 09:57
+
0
Скорее всего вы используете другую библиотеку.

Исправил ссылку в статье — загрузите данную библиотеку, представленную в статье и пример будет работать
avatar

danil_borchevkin

  • 3 февраля 2015, 14:31
+
0
При попытке скачать библиотеку — You do not have access to this repository.
avatar

Dr_aleja

  • 8 июня 2015, 23:16
+
0
Можно ли увеличить радиус считывания?
avatar

droncs46

  • 10 февраля 2015, 19:25
+
0
Да, можно, но не с этим модулем. Радиус считывания будет в данном случае напрямую зависеть от антенны. Больше антенна — больше радиус считывания. Для FH 13.56 МГц обычно до 30 см. Дальше начинаются проблемы.

Для считывания на метр и более — используют UHF (860-960 МГц), что дорогое удовольствие — самый дешевый ридер стоит от 200$ для малых дистанций без внешней антенны(до 50 см) и от 300$ для дистанций 5-15 метров с внешней антенной. Метки, соответственно, тоже дороже
avatar

danil_borchevkin

  • 11 февраля 2015, 14:20
+
0
Не подскажите как реализовать хотя бы до 30см?
avatar

droncs46

  • 11 февраля 2015, 14:34
+
0
разработка новой антенны, размер и конфигурация которой будет зависеть от задачи. Например плоская антенна на печатной плате для считывания до 50-60 см, будет иметь размер фактический примерно 800 на 600 мм
avatar

danil_borchevkin

  • 11 февраля 2015, 14:53
+
0
А усилитель нужен будет?
avatar

droncs46

  • 11 февраля 2015, 15:12
+
0
не могу сказать. А вот цепь согласования — точно нужна будет
avatar

danil_borchevkin

  • 11 февраля 2015, 15:20
+
0
немного не понятно подключение… К каким точкам подключить антенну? А какие выключить?
avatar

droncs46

  • 11 февраля 2015, 15:35
+
0
avatar

danil_borchevkin

  • 11 февраля 2015, 15:41
+
0
Рабочая частота: 13.56MHz
Как изменить на 125KHz
avatar

AntonNovikov

  • 21 июня 2015, 10:37
+
0
Так стоп рабочая частота это что? Кило герц или мега герц?

Можно ли с помощью этого модюля считать 125 килогерц?
avatar

AntonNovikov

  • 21 июня 2015, 10:40
+
0
Написано явно — 13.56 МГц

Нет, с помощью этого модуля нельзя считать карты на 125 кГц. Нужен другой считыватель.
avatar

danil_borchevkin

  • 21 июня 2015, 19:09
+
0
Никак. Нужен модуль на 125 кГц
avatar

danil_borchevkin

  • 21 июня 2015, 19:03
+
0
Спасибо. (Я совсем не понимаю эту тему)
А если кварц поменять, не поможет?
avatar

AntonNovikov

  • 21 июня 2015, 21:33
+
0
Нет, не поможет. Физический и канальный уровни отличаются для Mifare (для которого и предназначен данный считыватель) и для EM4100 (самый популярный стандарт на 125 кГц).

Для ознакомления с технологиями RFID можно почитать эту статью или же обратиться к википедии, а вот в этой статье описано как на ATTiny13 собрать свой считыватель на 125 кГц
avatar

danil_borchevkin

  • 21 июня 2015, 21:44
+
0
Спасибо огромное за ссылки, очень нужны. Буду разбираться.
avatar

AntonNovikov

  • 21 июня 2015, 22:02
+
0
Здравствуйте Даниил.
Большое спасибо за Вашу работу.
Отличная программа и у меня сразу все запустилось.
Я решил ее доработать и сделать замок для маленькой мастерской на работе на трех человек.
В программировании я новичок, просто работаю инженером-наладчиком.
Я захотел чтобы при первом касании магнит отпускал дверь, а при повторном притягивал.
Фактически это триггер или переключение светодиода одной кнопкой.
Я использовал флаг состояния и вставил маленький цикл после функции allow()
Но реле переключается всего один раз.
Я бьюсь над этой задачей вторую неделю.
Не могли бы Вы подсказать где у меня ошибка.

[code]
/*
www.lab409.ru
Danil Borchevkin
15/12/2013

* MOSI: Pin 11 / ICSP-4
* MISO: Pin 12 / ICSP-1
* SCK: Pin 13 / ISCP-3
* SS: Pin 10
* RST: Pin 9
*/

#include <SPI.h>
#include <RFID.h>

#define SS_PIN 10
#define RST_PIN 9
#define RED_LED 7
#define GREEN_LED 6
#define RELAY 3
#define BUZZER 5

RFID rfid(SS_PIN, RST_PIN);

unsigned char reading_card[5]; //for reading card
unsigned char Bichurin[5] = {52, 65, 219, 233, 71}; // allowed card
unsigned char Malaxov[5] = {228, 120, 254, 233, 139}; // allowed card
unsigned char Tetradze[5] = {196, 40, 221, 233, 216}; // allowed card
unsigned char i;

void indication(int led);
int flag = 0; // Create a state flag
void allow();
void denied();

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  rfid.init();
  pinMode(RED_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RELAY, OUTPUT);
  pinMode(BUZZER, OUTPUT);
}

void loop()
{
  if (rfid.isCard())
  {
    if (rfid.readCardSerial())
    {
      /* Reading card */
      Serial.println(" ");
      Serial.println(«Card found»);
      Serial.println(«Cardnumber:»);
      for (i = 0; i < 5; i++)
      {
        Serial.print(rfid.serNum[i]);
        Serial.print(" ");
        reading_card[i] = rfid.serNum[i];
      }
      Serial.println();
      //verification
      for (i = 0; i < 5; i++)
      {
        if (reading_card[i] != Bichurin[i])
          if (reading_card[i] != Malaxov[i])
            if (reading_card[i] != Tetradze[i])

            {
              break;
            }
      }
      if (i == 5)
      {
        allow();
      }
      else
      {
        denied();
      }
    }
  }
  rfid.halt();
}

void allow()
{
  Serial.println(«Access accept!»);

  if (flag == 0) // New cycle!
  {
    digitalWrite(RELAY, HIGH); // Turn on the electromagnet
    flag == 1;                          // Flip the flag
  }
  if (flag == 1)
  {
    digitalWrite(RELAY, LOW); // Switch off the electromagnet
    flag == 0;                         // Flip the flag
  }
  indication(GREEN_LED);
  tone(5, 1109, 300); // Play the melody input
  delay(300);
  tone(5, 554, 300);
}
void denied()
{
  Serial.println(«Access denied!»);
  indication(RED_LED);
  tone(5, 554, 2000); // Play ugly ringtone
}
void indication(int led)
{
  digitalWrite(led, HIGH);
  delay(200);
  digitalWrite(led, LOW);
}

[/code]
avatar

Losos

  • 19 ноября 2015, 18:06
+
0
Приветствую!

У вас в коде закралась определенная неясность=))


 if (flag == 0) // New cycle!
  {
    digitalWrite(RELAY, HIGH); // Turn on the electromagnet
    flag == 1;                          // Flip the flag
  }
  if (flag == 1)
  {
    digitalWrite(RELAY, LOW); // Switch off the electromagnet
    flag == 0;                         // Flip the flag
  }


Логика работы кода представлена следующая:
1. Если флаг равен нулю, то отключаем замок
2. Если флаг не равен нулю, то включаем замок.

Но в теле if у вас не происходит изменения значения флага. Т.е. флаг у вас всегда равен нулю

в if все как бы верно, но вот в теле if — у вас не присваивание (flag = 0), а сравнение (flag == 0), которое возвращаяет 0 или 1 в зависимости от условия и ничему не присваивается. Т.е. если запустить отладку и отслеживание переменной, представленный код не меняет значение флага. (кстати для флага int все таки многовато, когда есть char или _Bool, если компилятор С99-совместимый).

Совет — тело второго if делаем телом else первого.

Итого, рабочий код для функции allow():

void allow()
{
  Serial.println(«Access accept!»);

  if (flag == 0) // New cycle!
  {
    digitalWrite(RELAY, HIGH); // Turn on the electromagnet
    flag = 1;                  // Set the flag
  }
  else
  {
    digitalWrite(RELAY, LOW); // Switch off the electromagnet
    flag = 0;                 // Clear the flag
  }
  indication(GREEN_LED);
  tone(5, 1109, 300); // Play the melody input
  delay(300);
  tone(5, 554, 300);
}


P.S. Для того, чтобы лучше узнать С и С++ советую книги Стивена Прата (есть по обеим языкам). Доступно и хорошо написано с сотней примеров и упражений, живой язык
avatar

danil_borchevkin

  • 19 ноября 2015, 21:47
+
0
версия более яснее и короче — используем свойства условия в if:


void allow()
{
  Serial.println(«Access accept!»);

  if (flag) // New cycle!
  {
    digitalWrite(RELAY, HIGH); // Turn on the electromagnet
    flag = 1;                  // Set the flag
  }
  else
  {
    digitalWrite(RELAY, LOW); // Switch off the electromagnet
    flag = 0;                 // Clear the flag
  }
  indication(GREEN_LED);
  tone(5, 1109, 300); // Play the melody input
  delay(300);
  tone(5, 554, 300);
}

avatar

danil_borchevkin

  • 19 ноября 2015, 21:51
+
0
if (!flag)
условие правильное. К сожалению, здесь нельзя редактировать коментарии
avatar

danil_borchevkin

  • 19 ноября 2015, 21:58
+
0
Огромное Вам спасибо.
Сейчас залил Ваш скетч- все работает.
Я перепутал операторы сравнения "==" и присваивания "=". Дурацкая ошибка. Потерял столько времени из-за невнимательности.
В своей работе я использовал учебный пример с сайта.
Включение/отключение светодиода при однократном нажатии за счет переключения «флага» состояния кнопки.
Данная программа в отличии от предыдущих, которые циклично повторяли действие при удержании, выполняет всего одно действие при нажатии и удержании.

Пример 4
int LedPin = 13; // Подключаем светодиод к порту 13
int ButPin = 10; // Подключаем кнопку к выходу 10
int flag = 0; // флаг состояния

void setup()
{
pinMode(LedPin, OUTPUT); // Инициализируем порт «ledPin» как выходной
}

void loop()
{
if(digitalRead(ButPin) == HIGH && flag == 0)
{
digitalWrite(LedPin, !digitalRead(LedPin));
flag = 1;
}
if(digitalRead(ButPin) == LOW && flag == 1)
{
flag = 0;
}
}
Самое обидное что в примере этой ошибки нет.
Когда я изучал в 1992 году программирование на Фортране-77
преподаватель нам сказал: «Ребята заочное образование это тоже самое что заочное питание».
И он был прав. Преподаватель все таки нужен. Я прочел две книги Джереми Блюм «Инструменты технического волшебства» и Улии Соммер «Программирование плат Ардуино». Вторая книга унылого немца просто деньги на ветер. Ни комментариев в примерах ничего вообще.
А Джереми ничего хороший препод. Я еще все его видео уроки пересмотрел, парень он талантливый. Мало кто из хороших инженеров может быть хорошим учителем.
Но его 12 урок по чтению меток меня не вдохновил. Очень сложно. Непонятно зачем он читает столько байтов когда достаточно UID метки.
Ваша программа намного проще и короче. Это хорошо по крайней мере для новичков.
Спасибо еще раз за Вашу работу. В интернете к сожалению информации мало. Много сайтов где сидят копи-пастеры и тупо перепостят.
Буду дальше учить С++.

avatar

Losos

  • 20 ноября 2015, 16:16
+
0
Здравствуйте Даниил!
Я продолжаю делать замок основываясь на Вашей программе.
Но моя идея вмонтировать ридер в середину двери и открывать и закрывать ее с обоих сторон карточками с треском провалилась.
Дверь оказалась слишком толстой 40 мм. и чтение карт идет не уверенно. Точнее говоря карточки читает, а брелки не очень. У синеньких брелков размер антенны меньше чем в белой карточке.
Поэтому я решил добавить в схему кнопку.
Таким образом логика получается следующая:
Подходим к двери и смотрим на светодиоды горит красный-дверь заперта, зеленый-открыта.
Открываем дверь брелком-загорается зеленый идем внутрь. Хотим запираем за собой кнопкой, хотим нет.
Выходим из мастерской смотрим на светодиоды, если дверь заперта отпираем тоже кнопкой, снаружи запираем брелком.
Сервопривод ставить не хочу принципиально при любой аварии ригель запрет дверь намертво.
А электромагнит можно всегда открыть, вырубив автомат в ГРЩ.
Я сделал небольшую платку для кнопки основываясь на схеме Джереми Блюма по аппаратному устранению дребезга с помощью RC цепочки.
Далее я пробовал вставлять стандартный скетч в Вашу программу.
if (digitalRead(BUTTON) == HIGH && but == 0 ) // but переменная в которой храним состояние кнопки
{
digitalWrite(RELAY, !digitalRead(RELAY)); // Выключаем магнит
digitalWrite(GREEN_LED, digitalRead(RELAY)); // Зажигаем зеленый светодиод-дверь открыта
digitalWrite(RED_LED, !digitalRead(GREEN_LED)); // Гасим красный
tone(5, 1109, 300); // Play the melody input
delay(300);
tone(5, 554, 300);
but=1;
}
if (digitalRead(BUTTON) == LOW && but == 1)
{
but=0;
}

Проблема в том что если это вставить после команды void allow ()
То ничего не работает. Поэтому я вставил этот кусок сразу после команды void loop ().
И все заработало. Ридер читает карты, процесс чтения сопровождается веселым попеременным миганием светодиодиков.
Играет маленький гудок. Если карточка не в базе то загорается красный и гудит мерзкая нота.
Но есть одно но! Если я открою дверь картой и запру кнопкой, то следующий товарищ должен будет два раза прикладывать карту.
В команде:
void allow()
{
Serial.println(«Access accept!»);
if ( flag == 0)
{
digitalWrite(RELAY, HIGH);
не сохраняется состояние кнопки переменная but. У меня получились два независимых триггера.
Точнее говоря у кнопки приоритет. Ее никогда не надо два раза нажимать, а вот карточку надо. Кнопка всегда почему-то знает состояние флага после прикладывания карты. А карта перекидывает состояния флага независимо от кнопки.
Я пытался приделать but к flag но не пойму как.
По идее вообще незачем хранить состояние кнопки в but. Я хотел запускать команду void allow()
по условию «ИЛИ» ||. То есть все разрешается либо если карта в массиве либо кнопка изнутри нажата.
Void loop()
If (digitalRead(BUTTON)==LOW) // если кнопка нажата «схема с подтягивающим резистором»
{
but=1;
}
Else
{
but=0;
}
if (i == 5 || but==1 ) // добавочное условие «или». Или карта или кнопка
{
allow();
}
Else
{
denied();
}
Но ничего не получается. Я не могу понять что в Вашей программе является условием запуска void allow().
Если у Вас будет время не подскажете как прикрутить кнопку?
Заранее благодарен.
Андрей Батурин.

avatar

Losos

  • 28 ноября 2015, 15:41
+
0
у вас код нечитаемый — пожалуйста, на будущее — постите, используя форматирование.

Увеличение дальности считывания можно было достичь либо увеличением антенны, либо переносом антенны в другое место путем установки пассивной связанной антенны.

Я вас, на всякий случай, еще раз попрошу прочитать любую книжку по Си или С++ — тогда у вас не будет появляться таких вопросов. Опять же, посоветую книги господина Праты.

allow() — не команда, а функция.

else пишется с маленькой буквы.

if (i == 5 || but==1 )


синтаксически верно, но все же лучше брать отдельные условия в скобки, дабы не напутать с приоритетами

Функция allow() вызывается только в том случае, если все пять байт UID, считанных с карты, совпадают с пятью байтами мастер-карты(i как раз подсчитывает количество совпавших считанных байт с хранящимися в массиве с UID карты). То есть, если нет карты у ридера, либо считанный номер не совпадает — allow() вызываться не будет. Если вы хотите вызывать ее еще из какого-то места — вам ничего не мешает.

У вас уже есть флаг, который хранит состояние двери — зачем вам хранить состояние кнопки?!

в loop() после rfid.halt() вставляете код, который проверяет состояние кнопки и, если она нажата, переключает состояние замка

if (digitalRead(BUTTON))
{
   allow();
}
delay(500);


Теперь функция allow() будет вызываться если поднесена либо карта, либо нажата кнопка. Соответственно, по факту флаг хранит текущее состояние двери (можно его переименовать в более осмысленный). Если дверь была закрыта — она откроется, если открыта — закроется. delay для того, чтобы создать безопасный интервал нажатия.

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

avatar

danil_borchevkin

  • 28 ноября 2015, 21:56
+
0
Еще раз большое спасибо. Программу переделал все заработало как часы.
Аппетит приходит во время еды. Я приписал небольшие кусочки с функцией tone(), чтобы проигрывать гудки или короткие мелодии. Типа вот такие:
tone(0, 1109, 300); // Play the melody input
delay(300);
tone(0, 554, 300);
Хотел создать массив нот и их длительностей как в примерах пишут но я так понимаю внутри функции allow() цикл: for (int i=0; i<10; i++) с перебором элементов не создать. Его наверное надо лепить в основной цикл loop().
У меня сейчас играют три мелодии на вход, на выход и для хулиганов.
Можно я задам последний вопрос? Можно ли по простому выделять людей или хотя бы одного человека из массива и играть им индивидуальную мелодию входа, или зажигать светодиодик? Или для этого надо всю программу менять.
Извиняюсь за назойливость. В свое оправдание скажу что я самый внимательный читатель Вашего блога в мире :)
avatar

Losos

  • 1 декабря 2015, 15:19
+
0
Здравствуйте! Извините, если вопрос не по адресу.
Мне необходимо решить следующую задачу. Нужен совет. Надо идентифицировать фигурки на полях с физическим размером 5х5 см. Полей таких минимум 16. На фигурке наклеена метка. Можно ли использовать для этого чип RC522? Мысль такая. Использовать один чип, и мультиплексно переключать антенны, которые находятся под каждым полем. Антенна, такая-же, как на goo.gl/6qX58R Иначе, конструкция получается очень дорогая, если на каждое поле ставить считыватель. Как думаете, будет работать, если антенны переключать какими-то аналоговыми ключами. Скорость высокая не нужна. Поле можно опрашивать хоть секунду, и переходить на следующее.
avatar

smsirkutsk

  • 24 февраля 2016, 16:11
+
0
Такого опыта не было, точно ответить на вопрос не смогу.

А из чего фигурки?

Скорость переключения — это не главная проблема в данном вопросе.

Возможно, что это будет работать, но нужно во первых систему мультиплексирования подобрать таким образом, чтобы она имела необходимый частотный диапазон, во вторых — согласовать каждый отдельный антенный тракт. Не факт, что такое решение и время на его разработку будет дешевле, чем готовые ридеры (скорее всего, получится дороже)

Попробуйте, и по возможности, отпишитесь
avatar

danil_borchevkin

  • 24 февраля 2016, 16:21
+
0
Фигурки из акрила. Неужели никто не решал подобных задач. Пробовал решить эту проблему контактным способом, но всё получается очень ненадёжно. Нужен бесконтактный способ. Надо идентифицировать минимум 64 различных фигурки. Как ещё можно это решить? Может что-то придёт в голову. Нужно недорогое решение. Стоимость 150 р. (считыватель) х 16 полей = 2560 рублей неприемлема. Это всё нужно для детской развивающей игрушки.
avatar

smsirkutsk

  • 24 февраля 2016, 16:31
+
0
Контактный метод, как раз таки будет самым надежным и дешевым. У вас фигурки различные, Насколько я понял и нужно дектить ее тип.

посмотрите в сторону iButton=)) (таблетки от домофона)

avatar

danil_borchevkin

  • 24 февраля 2016, 17:19
+
0
кроме того, говоря о РФИД, вы забываете о стоимости меток- от 10 руб за 1 шт самого низкого качества на бумажной основе
avatar

danil_borchevkin

  • 24 февраля 2016, 17:21
+
0
могу сразу обозначить круг проблем, с которым вы столкнетесь:
— мультиплексирование нужно осуществлять такими средствами, чтобы ток утечки был минимален, а неактивные антенны отключались
— нужно рассчитывать линии на печатной плате в 50 Ом — получится неплохой челлендж
— нужно изолировать каналы друг от друга
— мультиплексор должен вносить минимальные искажения
— все это приведет к кастомной печатной плате и дорогим микросхемам — pl.mouser.com/ProductDetail/Analog-Devices/ADG904BRUZ/?qs=BpaRKvA4VqEOqmnl0ENwhg%3D%3D — 4 евро за штуку (4 к 1), что уже дороже
avatar

danil_borchevkin

  • 24 февраля 2016, 17:33
+
0
хотя гугл прям на первой странице по запросу «rfid antenna mux» выдает множество решений, но все они дороже, нежели использование отдельных ридеров
https://developer.mbed.org/forum/electronics/topic/4080/

https://e2e.ti.com/support/wireless_connectivity/nfc_rfid/f/667/t/269476

http://www.ti.com/lit/an/sloa167/sloa167.pdf — аппнот как это сделать и рассчитать
http://www.youtube.com/watch?v=16VFU9n8VO4 — видео к предыдущему аппноуту

http://forum.arduino.cc/index.php?topic=244408.0

http://www.electronicspoint.com/threads/switching-between-rfid-antennas-one-reader-100-antennas-how.75634/

Судя по постам, задача нетривиальная, но решена в аппноуте у техасцев, но нужно понимать, что это обойдется вам дороже чем покупка тех же самых 16 ридеров
avatar

danil_borchevkin

  • 24 февраля 2016, 17:29
+
0
Спасибо Вам за ответы. Столько информации, которую я найти не мог. Я эту тему обсуждал на goo.gl/i22WCy Посмотрите, если не трудно. Может будут какие-то идеи. Буду рад почитать Ваши мысли по этому поводу.
avatar

smsirkutsk

  • 24 февраля 2016, 18:46
+
0
Просмотрел. Вам уже предложили все хорошие варианты, в том числе (о чем я не догадался) — DS2411.

ИМХО, вы исходите не из совсем верных посылов — вы берете стоимость в розницу и в России и абсолютно не считаете ни тулинг-косты, ни затраты на разработку/проектирование, ни время, которое будет на это потрачено. Вы слишком рано думаете об оптимизации стоимости, не имея на руках готового прототипа и заранее отметая любые варианты, которые вам предлагают.

Что вам мешает сделать поле 3 х 3 и протестировать свою идею?! Сделать на резистивных делителях, на герконах, на рфидах, на Ibutton, на DS2411, практика и эксперимент покажет, что лучше и что выживет в результате экспериментов. Здесь можно будет уложится в 10-15 тысяч рублей. Затем отдаем это разным ребенкам и смотрим — жива ли вообще идея.

Не совсем также понятна ориентация на ATMEGA 2650 — она стоит от 14 евро за штуку, в то время как STM32 — в два раза меньше (SMT32F4 — Cortex M4), EFM32 — в 3 раза меньше (Wonder Gecko — Cortex M4), а EFM32 — еще и лидер по энергопотреблению, что в разы увеличит автономность вашей игрушки по сравнению с ATMEGA (имеется в виду расход на вычислительную часть).
avatar

danil_borchevkin

  • 24 февраля 2016, 19:30
+
0
Даниил, можно с Вами как-то завтра пообщаться?
avatar

smsirkutsk

  • 24 февраля 2016, 19:42
+
0
пишите на почту danil.borchevkin@lab409.ru
avatar

danil_borchevkin

  • 24 февраля 2016, 19:45
+
0
блин, да даже мои любимые MSp430 дешевле, чем ATMEGA 2560=))
avatar

danil_borchevkin

  • 24 февраля 2016, 19:44

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.