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
Репозиторий цикла статей с даташитами, примерами, библиотекой и т.д.
Ссылка на скачивание библиотеки


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

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

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

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

    • модуль*

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

    • Диод D1 не должен гореть, кроме как в случае, если зарегистрирована карта, которая указана как master.

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

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

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

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

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

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

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

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

    • Спасибо за совет. Если под схематикой понимается подписи к ногам — то есть на самом модуле. В соответствии с ними я подсоединяю провода. Но к поставщику обращусь, вы правы.

    • На карте из Калининграда всё прекрасно работает. Поэтому пока буду считать, что из Китая пришёл брак или что-то уж совсем старое. Спасибо.

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

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

    • youtu.be/omB91owk3X8 вот тут работа с красным и зелёным светодиодом, код из этой статьи, чуть подправлена, добавлена серва(имитирует открытие двери при допустимом ключе)

    • круто! Во что-нибудь более серьезное переросло?

    • Заказал другой модуль, на нём всё ок, спасибо.

  3. Ребята! Все сайты облазил, как у Вас работает этот код? У меня же компилятор выдает ошибку на этой строчке, почти в самом начале!

    RFID rfid(SS_PIN, RST_PIN);

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

    • Скопируйте и запостите в эту ветку ошибку, тогда я вам смогу помочь.

    • 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
      это отчет об ошибке… компилятор выделяет ту строчку, которую я прислал ранее…

    • При попытке скачать библиотеку — You do not have access to this repository.

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

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

    • Не подскажите как реализовать хотя бы до 30см?

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

    • не могу сказать. А вот цепь согласования — точно нужна будет

    • немного не понятно подключение… К каким точкам подключить антенну? А какие выключить?

    • Так стоп рабочая частота это что? Кило герц или мега герц?

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

    • Написано явно — 13.56 МГц

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

    • Спасибо. (Я совсем не понимаю эту тему)
      А если кварц поменять, не поможет?

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

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

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

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

    [code]
    /*
    http://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]

    • Приветствую!

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

       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. Для того, чтобы лучше узнать С и С++ советую книги Стивена Прата (есть по обеим языкам). Доступно и хорошо написано с сотней примеров и упражений, живой язык

    • версия более яснее и короче — используем свойства условия в 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);
      }
      

    • if (!flag)

      условие правильное. К сожалению, здесь нельзя редактировать коментарии

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

      Пример 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 метки.
      Ваша программа намного проще и короче. Это хорошо по крайней мере для новичков.
      Спасибо еще раз за Вашу работу. В интернете к сожалению информации мало. Много сайтов где сидят копи-пастеры и тупо перепостят.
      Буду дальше учить С++.

  5. Здравствуйте Даниил!
    Я продолжаю делать замок основываясь на Вашей программе.
    Но моя идея вмонтировать ридер в середину двери и открывать и закрывать ее с обоих сторон карточками с треском провалилась.
    Дверь оказалась слишком толстой 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().
    Если у Вас будет время не подскажете как прикрутить кнопку?
    Заранее благодарен.
    Андрей Батурин.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • Такого опыта не было, точно ответить на вопрос не смогу.

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

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

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

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

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

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

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

    • кроме того, говоря о РФИД, вы забываете о стоимости меток- от 10 руб за 1 шт самого низкого качества на бумажной основе

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

    • хотя гугл прям на первой странице по запросу «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 ридеров

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

    • Просмотрел. Вам уже предложили все хорошие варианты, в том числе (о чем я не догадался) — DS2411.

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

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

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

    • Даниил, можно с Вами как-то завтра пообщаться?

    • блин, да даже мои любимые MSp430 дешевле, чем ATMEGA 2560=))

  8. Помогите с кодом, где то что то не так не работает
    #include <SPI.h>
    #include <RFID.h>
    #define RST_PIN 9
    #define SS_PIN 10
    #define DIODE_PIN 2 // PIN- Diode
    #define RELEY_PIN 8 // PIN- RELEY

    RFID rfid(SS_PIN, RST_PIN);

    unsigned char reading_card[5]; //for reading card

    /*unsigned char master[5][5] = { // allowed cards RFID 2
    {179,72,117,246,120},
    {195,116,92,246,29},
    {3,142,90,246,33},
    {0,0,0,0,0},
    {0,0,0,0,0}
    };
    */

    unsigned char master[5][5] = { // allowed cards RFID 1 ����� ������
    {85,177,158,11,113},
    {245,48,185,2,126},
    {85,157,240,7,63},
    {0,0,0,0,0},
    {0,0,0,0,0}
    };

    unsigned char i;
    unsigned char j;

    int counter;
    int MAX_COUNTER = 1;

    bool flag = false;

    void allow();
    void denied();

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

    void loop()
    {
    //flag = false;
    if (rfid.isCard())
    {
    if (rfid.readCardSerial())
    {
    /* Reading card */
    Serial.print(" ");
    Serial.print(«Card found»);
    Serial.print(«Card number:»);
    for (i = 0; i < 5; i++)
    {
    Serial.print(rfid.serNum[i]);
    Serial.print(" ");
    reading_card[i] = rfid.serNum[i];
    }
    Serial.println();
    //verification
    for (j = 0; j < 5; j++)
    {
    for (i = 0; i < 5; i++)
    {
    if (reading_card[i]!=master[j][i])
    {
    break;
    }
    }
    if (i == 5)
    {
    break;
    }
    }
    if (i == 5)
    {
    allow();
    flag = true;
    counter = 0;
    }
    else
    {
    // denied();
    //flag = false;
    }
    }
    }
    rfid.halt();
    if (flag == true)
    {
    counter++;
    digitalWrite(DIODE_PIN, LOW);
    digitalWrite(RELEY_PIN, HIGH);
    Serial.println(«OPEN»);
    }
    if (counter > MAX_COUNTER)
    {
    Serial.println(«CLOSED»);
    digitalWrite(DIODE_PIN, HIGH);
    digitalWrite(RELEY_PIN, LOW);
    flag=false;
    }
    }

    void allow()
    {
    Serial.println(«Access accept!»);
    digitalWrite(DIODE_PIN, HIGH);
    digitalWrite(RELEY_PIN, HIGH);
    }
    void denied()
    {
    Serial.println(«Access denied!»);
    digitalWrite(DIODE_PIN, LOW);
    digitalWrite(RELEY_PIN, LOW);
    }

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

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна конкурс манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение