Цикл чтения RFID-карты кажется остановленным

Мне удалось запрограммировать считыватель RFID-карт на включение и выключение света при предъявлении любой RFID-карты. Я протестировал это, и оно работает, при этом индикаторы постоянно включаются и выключаются, если представлена какая-либо карта с поддержкой RFID.

Я попытался добавить команду, согласно которой при считывании двух определенных карт (идентифицируемых по их номерам UID) только эти карты будут сбрасывать индикаторы на "выключено" независимо от того, в каком состоянии они были в данный момент — как кнопка сброса.

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

Я новичок в программировании Arduino, а также в технологии RFID, но мне кажется, что цикл не сбрасывается в начало должным образом, или мой оператор IF каким-то образом оставляет систему в состоянии, когда начальный код не может запустить.

Мой код ниже. Будем признательны за любые мысли.

`

#define r1 A0
int relay1 = LOW;

#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Создать экземпляр MFRC522.


void setup()
{
  pinMode(r1, OUTPUT);

  Serial.begin(9600);   // Инициируем последовательную связь
  SPI.begin();      // Инициируем шину SPI
  mfrc522.PCD_Init();   // Инициировать MFRC522
  Serial.println("Approximate your card to the reader...");
  Serial.println();
}

void loop()
{
  // Ищем новые карты
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }
  
// Выбираем одну из карт
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }

  // Показать UID на последовательном мониторе
  Serial.print("UID tag :");
  String content = "";
  byte letter;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");  
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));  
    content.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  Serial.println();
  Serial.print("Message : ");
  content.toUpperCase();


  if ((content.substring(1) == "23 49 1F BE") || (content.substring(1) == "CB CB 2C E3")) // меняем здесь UID карты/карт которым вы хотите предоставить доступ
  {
   Serial.println("Staff access");
    Serial.println();
    relay1 = HIGH;
    digitalWrite(r1, relay1);
    delay(500);
  }
  else
  {

    Serial.println("Authorized access");
    Serial.println();
    relay1 = ~ relay1;
    digitalWrite(r1, relay1);
    delay(500);
  }
}

`

, 👍1

Обсуждение

Вы смотрите на последовательный вывод, когда это происходит? Вы видите сообщение «Доступ персонала»? а затем есть ли какие-либо другие признаки того, что он делает? Я бы добавил операторы печати в два места, куда вы возвращаетесь, таким образом вы сможете отслеживать состояние цикла и/или видеть, перестанет ли он работать и где последнее место, откуда он печатался., @Chad G

если первая карта, которую я представляю, является универсальной картой, последовательный монитор возвращает «авторизованный доступ» при каждом нажатии и продолжает включать и выключать свет. Если затем я представлю карту персонала, последовательный монитор вернет «доступ персонала», но индикаторы ничего не сделают, и после этого, если я снова коснусь общей карты, последовательный монитор вернет «разрешить доступ снова, но индикаторы больше не реагируют., @Christine

Эта операция с int нуждается в некотором объяснении: relay1 = ~ relay1;. Есть ли другой способ достичь своей цели здесь?, @6v6gt

Да, relay1 должен быть логическим, а затем используйте relay1=!relay1; для переключения состояний., @Chad G

relay1 = ~relay1 работал нормально, когда я использовал только один критерий для карт (это означает, что все были авторизованы). только когда я добавил критерий «Доступ персонала», он перестал работать. Есть ли особая причина, по которой !relay1 будет работать лучше, чем ~relay1 ?, @Christine

Оператор C++ тильда (~) является побитовым оператором NOT. То есть он изменяет каждый 0 на 1 и каждую 1 на 0. Он почти никогда не подходит для использования с числами со знаком, такими как int, где бит старшего разряда является битом знака. Обычно он используется для управления отдельными битами переменной, а не для логических операций., @6v6gt

Спасибо, и совет принят, но не думаете ли вы, что это проблема, из-за которой цикл не работает? Как я уже сказал, раньше он работал, меняя состояние от низкого к высокому, когда его активировала любая карта. Почему код больше не запускает событие освещения теперь, когда есть два набора карт доступа для оценки? Я чувствую, что может быть что-то не так с оператором if или с тем, как он заканчивается., @Christine


1 ответ


1

Проблема заключается в неправильном использовании тильды (~) , которая является побитовым оператором НЕ, по отношению к переменной int relay1. Кажется, что он работает правильно, когда реле 1 запускается с НИЗКИМ значением, которое имеет значение 0. То есть реле 1 имеет внутреннее значение 0b00000000000000000. Если теперь выполняется оператор relay1 = ~relay1, внутреннее значение relay1 будет 0b1111111111111111. Это обрабатывается как HIGH в выражении digitalWrite(r1, relay1);, поэтому кажется, что он работает правильно. Если снова выполняется оператор relay1 = ~relay1, внутреннее значение relay1 будет равно 0b00000000000000000. Это рассматривается как LOW в выражении digitalWrite(r1, relay1); Так что это также будет работать непрерывно, включая и выключая реле.

Проблема возникает, когда вы явно устанавливаете relay1 в HIGH здесь: relay1 = HIGH;. HIGH имеет значение 1, то есть реле1 теперь имеет внутреннее значение 0b00000000000000001, и снова это работает, однако следующее выполнение инструкции relay1 = ~relay1 дает реле1 внутреннее значение 0b1111111111111110, который также считается ВЫСОКИМ. Итак, с этого момента оператор relay1 = ~relay1 всегда будет приводить к тому, что relay1 будет иметь значение, которое интерпретируется как ВЫСОКОЕ. Таким образом, реле, похоже, застряло.

Решение, которое уже фигурирует в комментарии, состоит в том, чтобы изменить оператор int relay1 = LOW; на bool relay1 = LOW; и изменить этот оператор реле1 = ~ реле1; в реле1 = ! реле1;

,

Большое спасибо за объяснение. Я не понимал, что будет внутреннее значение, отличное от нуля, и единица, связанная с НИЗКИМ и ВЫСОКИМ, поэтому не мог понять, как решение изменения оператора реле может помочь. Похоже, это решит проблему, и теперь у меня есть еще одна концепция, которую нужно изучить и понять больше :), @Christine

@Кристина, протокол заключается в том, чтобы отметить правильный ответ. :-), @Rohit Gupta