[Решено] Как подружить 2 RFID-сканера RC522 и Arduino Nano

Тема в разделе "Arduino & Shields", создана пользователем onmironov, 11 сен 2015.

  1. onmironov

    onmironov Нерд

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

    Я взял пример для одного сканера и сдублировал код для второго (да, я программист от бога ;) ). Как и ожидалось, ничего не сработало.

    К ардуино сканеры подключаю так: mosi, miso и sck общие для обоих сканеров, все остальное в отдельные пины.

    Вот код этого безобразия (комменты не мои, в основном еще из первого примера, который взят за начало, решил не удалять, вдруг пригодятся):

    Код (Text):
    #include <Servo.h>
    #include <SPI.h>
    #include <MFRC522.h> // библиотека "RFID"

    #define SERVO_PIN 6
    #define LCard_SS_PIN 10
    #define LCard_RST_PIN 9
    #define RCard_SS_PIN 3
    #define RCard_RST_PIN 2

    MFRC522 mfrc522_LEFT(LCard_SS_PIN, LCard_RST_PIN);
    MFRC522 mfrc522_RIGHT(RCard_SS_PIN, RCard_RST_PIN);

    unsigned long LC_uidDec, LC_uidDecTemp; // для хранения номера метки в десятичном формате
    unsigned long RC_uidDec, RC_uidDecTemp; // для хранения номера метки в десятичном формате

    Servo servo;

    void setup() {
      Serial.begin(9600);
      SPI.begin(); // инициализация SPI / Init SPI bus
      mfrc522_LEFT.PCD_Init(); // инициализация MFRC522 / Init MFRC522 card
      mfrc522_RIGHT.PCD_Init(); // инициализация MFRC522 / Init MFRC522 card
      servo.attach(SERVO_PIN);
      servo.write(0); // устанавливаем серву в закрытое состояние
    }

    void loop() {
      if (mfrc522_LEFT.PICC_IsNewCardPresent() && mfrc522_RIGHT.PICC_IsNewCardPresent()) {
        // Выбор метки
        if ( ! mfrc522_LEFT.PICC_ReadCardSerial() || ! mfrc522_RIGHT.PICC_ReadCardSerial()) {
          Serial.println("Can't read serial");
        }
        LC_uidDec = 0;
        RC_uidDec = 0;
        // Выдача серийного номера метки
        for (byte i = 0; i < mfrc522_LEFT.uid.size; i++ )
        {
          LC_uidDecTemp = mfrc522_LEFT.uid.uidByte[i];
          LC_uidDec = LC_uidDec * 256 + LC_uidDecTemp;
        }
        for (byte i = 0; i < mfrc522_RIGHT.uid.size; i++ )
        {
          RC_uidDecTemp = mfrc522_RIGHT.uid.uidByte[i];
          RC_uidDec = RC_uidDec * 256 + RC_uidDecTemp;
        }
        Serial.println("Left card UID: ");
        Serial.println(LC_uidDec); // Выводим UID метки в консоль
        Serial.println("Right card UID: ");
        Serial.println(RC_uidDec); // Выводим UID метки в консоль
        if (LC_uidDec == 1494988646 && RC_uidDec == 3024868508) // Сравниваем Uid метки, если он равен заданному то серва открывает
        {
          servo.write(180); // Поворачивавшем серву на угол 90 градусов(Отпираем какой либо механизм: задвижку, поворачивавшем ключ и т.д.)
          delay(3000);
        }
      } else {
        servo.write(0);
      }
    }
    Если кто-то может помочь или подскажет, в какую сторону копать — буду очень благодарен.

    п.с. по профессии очень далек от мира Ардуино, но интересно, поэтому заранее прошу простить за тупые вопросы или логику чайника =)
     
    zserg нравится это.
  2. DrProg

    DrProg Вечный нерд

    Так совпало, что на днях буду срочно разбираться с RFID, задача похожая, только не 2 сканера, а 9. И срабатывать должно когда к каждому поднесена своя правильная метка. Пока что не вижу трудностей в теории, буду держать в курсе исследований.
     
    ИгорьК нравится это.
  3. onmironov

    onmironov Нерд

    Буду очень благодарен, даже если просто покажете свой код и расскажете, как подключили сканеры. Заранее огромное спасибо
     
  4. DrProg

    DrProg Вечный нерд

    В общем, немного повозившись, задачку с двумя ридерами решил. Пока что у меня два в наличии, но развить идею до любого количества можно по аналогии. Если коротко, то идея такая - ноги всех ридеров подключаются к соответствующим пинам параллельно кроме ноги MISO. Эти ноги мы подключаем к своему пину 50 (в моем случае, потому что Mega) через биполярные транзисторы, которыми управляем любыми свободными пинами (в моем случае 2 и 3).
    [​IMG]
    Включая их по очереди мы можем опрашивать по очереди порты ридеров. В моем примере на терминал выводится код метки поднесенной к каждому порту или к обоим, далее делайте с этой информацией что угодно. Код:
    Код (Text):
    #include <SPI.h>
    #include <MFRC522.h>

    #define RST_PIN        9          // пин RST
    #define SS_PIN          53          // пин SS (на Меге)
    #define R1_PIN          2          // включение ридера 1
    #define R2_PIN          3          // включение ридера 2

    MFRC522 mfrc522(SS_PIN, RST_PIN);  

    int cardUID[3];
    unsigned long timerReader;  // таймер опроса
    byte activeReader = 1;      // опрашиваемый ридер
    int timeSwitch = 100;      // время смены опроса ридеров

    void setup() {
      // put your setup code here, to run once:
      pinMode(R1_PIN, OUTPUT);
      pinMode(R1_PIN, OUTPUT);
      Serial.begin(9600);
      while (!Serial);
      SPI.begin();
      digitalWrite(R1_PIN, HIGH);
      digitalWrite(R2_PIN, LOW);
      mfrc522.PCD_Init();
      Serial.println(F("Card please:"));
      timerReader = millis() + timeSwitch;
    }

    void loop() {
      if (timerReader <= millis()) {          // переключение опроса ридеров
        activeReader = !activeReader;        // для двух сгодится так, для большего кол-ва алгоритм другой
        digitalWrite(R1_PIN, activeReader);
        digitalWrite(R2_PIN, !activeReader);
        timerReader = millis() + timeSwitch;
      }

      if ( ! mfrc522.PICC_IsNewCardPresent())
        return;
      if ( ! mfrc522.PICC_ReadCardSerial())
        return;

      Serial.print(F("Card UID "));
      Serial.print(activeReader, DEC);
      Serial.print(": ");
      dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
      for (int i = 0; i < 4; i++) { // печатаем UID
        Serial.print(cardUID[i], HEX);
        Serial.print(" ");
      }
      Serial.println("");

    }

    void dump_byte_array(byte * buffer, byte bufferSize) { // считываем UID в массив
      for (byte i = 0; i < bufferSize; i++) {
        cardUID[i] = buffer[i];
      }
    }
     
    ИгорьК нравится это.
  5. Unixon

    Unixon Оракул Модератор

    Достаточно просто 1k резистор на каждую линию MISOx последовательно повесить.
     
  6. DrProg

    DrProg Вечный нерд

    Я не понял, поясните как это и что даст.
     
    ИгорьК нравится это.
  7. onmironov

    onmironov Нерд

    Большое спасибо, буду пробовать. Но фраза «для двух сгодится так, для большего кол-ва алгоритм другой» пугает, конечно =)
     
  8. DrProg

    DrProg Вечный нерд

    Мне нужно на 9 штук сделать. Я буду писать функцию которая единовременно опрашивает все 9 рфид (или другое колво) и закидывает результат в двумерный массив.
     
    ИгорьК нравится это.
  9. geher

    geher Гуру

    Ничего страшного. Просто когда ридера два, можно перебирать их просто инвертируя номер активного ридера и используя его же для установки уровней на управляющих пинах.
    Код (Text):

      if (timerReader <= millis()) {          // переключение опроса ридеров
        activeReader = !activeReader;        // для двух сгодится так, для большего кол-ва алгоритм другой
        digitalWrite(R1_PIN, activeReader);
        digitalWrite(R2_PIN, !activeReader);
        timerReader = millis() + timeSwitch;
      }
     
    Если же ридеров больше, таким финтом ушами не отделаешься.
    Придется отдельно перебирать ридеры и отдельно их подключать/отключать.
    Например так:
    Код (Text):

      if (timerReader <= millis()) {          // переключение опроса ридеров
        activeReader ++;  
        if (activeReader>MAXREADERNUM) activeReader=1;
        digitalWrite(R1_PIN, activeReader==1);
        digitalWrite(R2_PIN, activeReader==2);
        digitalWrite(R2_PIN, activeReader==3);
        .....
        timerReader = millis() + timeSwitch;
      }
     
    Можно завести массив для номеров управляющих пинов. Тогда это будет выглядеть примерно так:
    Код (Text):

      byte readerPins[]={R1_PIN,R2_PIN,R1_PIN...};
      if (timerReader <= millis()) {          // переключение опроса ридеров
        activeReader ++;  
        if (activeReader>MAXREADERNUM) activeReader=1;
        for (byte i=0;i<MAXREADERNUM;++i){
            digitalWrite(readerPins[i], activeReader==i+1);
        }
        timerReader = millis() + timeSwitch;
      }
     
     
  10. onmironov

    onmironov Нерд

    Если отпишите сюда, как сделали, буду каждое утро посылать вам в карму много плюсов =)

    Я понимаю, ну, чисто в теории, что не страшно, но ваше сообщение пришлось перечитать раза четыре. Но спасибо, попробую
     
  11. DrProg

    DrProg Вечный нерд

    Я думаю сделать массив с пинами, благо на Меге их хватает, так проще опрашивать и обрабатывать в цикле и более универсально, при изменении кол-ва рфидов достаточно будет нескольких простых движений. Еще думал использовать мой любимый 595 регистр, но для 9 штук ни то ни сё, одного мало, двух много.
     
    ИгорьК нравится это.
  12. Unixon

    Unixon Оракул Модератор

    А транзисторы вам зачем?
     
  13. DrProg

    DrProg Вечный нерд

    Чтобы считывать с одного выбранного рфида отключая на время сигнал с других.
     
    ИгорьК нравится это.
  14. DrProg

    DrProg Вечный нерд

    Вот примерно так получилось. Единственное пока не пойму почему без первой метки остальные не читает, когда первая есть, все отлично, пока ее нет не видит и остальных. Причем, в первом примере, метки видит независимо друг от друга. Вероятно, дело в функциях библиотеки, логику надо осилить.
    Код (Text):
    #include <SPI.h>
    #include <MFRC522.h>

    #define RST_PIN        9          // пин RST
    #define SS_PIN          53          // пин SS (на Меге)

    MFRC522 mfrc522(SS_PIN, RST_PIN);

    byte maxRF = 1;                // всего рфидов (включая нулевой)
    byte RFpin[2] = {2, 3};        // пины включения рфидов
    byte actRF = 0;                // опрашиваемый рфид

    byte massRFuid[2][4];          // массив UID меток (первый - номер ридера, второй - 4 числа UID)

    void setup() {
      for (byte i = 0; i <= maxRF; i++) { // выставляем пины
        pinMode(RFpin[i], OUTPUT);
      }
      RFpinsLOW();                      // сброс всех пинов в LOW

      Serial.begin(9600);
      while (!Serial);
      SPI.begin();
      digitalWrite(RFpin[0], HIGH);    // включение одного рфид (первого) для инициализации
      mfrc522.PCD_Init();
      Serial.println("Card please:");
    }


    void loop() {
      for (int i = 0; i <= maxRF; i++) { // заполняем массив меток
        readRF(i);
        delay (100);                        // не знаю надо ли
      }
      SerialRFprint();                        // печатаем содержимое массива меток на экран
      delay(2000);
    }



    void readRF (byte RF) {
      RFpinsLOW();
      digitalWrite(RFpin[RF], HIGH);          // включаем нужный рфид
      delay(100);
      if ( ! mfrc522.PICC_IsNewCardPresent()) { // если метки нет
        massRFuid[RF][0] = 0;        // метим отсуствие метки в первом числе UID
        return;
      }
      if ( ! mfrc522.PICC_ReadCardSerial()) {
        massRFuid[RF][0] = 0;
        return;
      }

      dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size, RF);
    }

    void RFpinsLOW () {                // сброс всех пинов в LOW
      for (byte i = 0; i <= maxRF; i++) {
        digitalWrite(RFpin[i], LOW);
      }
    }

    void dump_byte_array(byte * buffer, byte bufferSize, byte RF) { // считываем UID в массив
      for (byte i = 0; i < bufferSize; i++) {
        massRFuid[RF][i] = buffer[i];
      }
    }

    void SerialRFprint () {            // печать массива меток на экран
      for (int i = 0; i <= maxRF; i++) {
        Serial.print("Card ");
        Serial.print(i, DEC);
        Serial.print(": ");
        if (massRFuid[i][0] == 0) {
          Serial.println("NO card");
        } else {
          for (int j = 0; j < 4; j++) { // печатаем UID
            Serial.print(massRFuid[i][j], HEX);
            Serial.print(" ");
          }
          Serial.println("");
        }
      }
    }
     
    В принципе, для моей задачи этого достаточно, должны лежать все 9 меток на своих местах, считает без проблем, но хотелось бы большей универсальности и независимости одного считывателя от другого.
     
    Последнее редактирование: 13 сен 2015
    ИгорьК нравится это.
  15. Unixon

    Unixon Оракул Модератор

    Для этого есть сигналы выборки SSx, а все MISOx можно просто скрутить вместе через резисторы. Коммутировать через ключи это правильный вариант, но можно и проще делать.
     
  16. DrProg

    DrProg Вечный нерд

    Можно в этом месте поподробнее? Каким образом пользоваться сигналом выборки?
     
    ИгорьК нравится это.
  17. Unixon

    Unixon Оракул Модератор

    У каждого n-го устройства SPI есть 4 сигнала: SCK, MOSI, MISO, SSn; Когда сигнал выборки SSn данного устройства не активен, все остальные сигналы SCK, MOSI, MISO общие для всех устройств им игнорируются. По идее, каждое ведомое устройство при получении неактивного уровня на SSn должно переводить свой MISOn в третье состояние. Но если это не реализовано в ведомых устройствах, то, чтобы защитить выходы других устройств на шине, все MISOn можно объединить в общий MISO через резисторы либо транзисторные ключи.
     
  18. DrProg

    DrProg Вечный нерд

    В теории понятно, на практике как это выглядит? Нужно заинитить несколько рфид-ридеров вот так:
    Код (Text):
    MFRC522 mfrc522_1(SS_PIN_1, RST_PIN);
    MFRC522 mfrc522_2(SS_PIN_2, RST_PIN);
    MFRC522 mfrc522_3(SS_PIN_3, RST_PIN);
    Даже если так, как к ним обращаться из цикла?
     
    ИгорьК нравится это.
  19. Unixon

    Unixon Оракул Модератор

    Кстати, вам общий MISO стоит притянуть к земле, чтобы он не плавал, когда на коллекторе "0" или оба канала закрыты.
     
  20. Unixon

    Unixon Оракул Модератор

    Что именно непонятно как делать?

    А кто вам мешает сделать массив объектов MFRC522 ?