Arduino RFID с двигателем и концевыми выключателями

rfid l298n

Спасибо за изучение моего кода Arduino. Я строю автоматизированную раздвижную тягу и пытаюсь активировать двигатель с помощью RFID-сканера. Сканер ожидает жетон, и как только он обнаруживает жетон, двигатель вращается и ожидает обнаружения концевого выключателя и останавливает двигатель, затем он делает то же самое, когда обнаруживает другой жетон RFID, но вместо этого двигатель движется в противоположном направлении. направлении и ожидает нажатия противоположного концевого выключателя. У меня есть 2 набора кода. Одним из них является код сканера RFID, который работает нормально, но он только включает и выключает реле. Другой код предназначен для двигателя с 2 концевыми выключателями с кнопкой активации. Этот код тоже работает, и розыгрыш открывается и закрывается при нажатии кнопки, но он не работает со сканером RFID. Итак, моя цель состоит в том, чтобы внедрить код сканера RFID в код автоматического рисования, чтобы двигатель вращался и реверсировал с помощью жетона RFID и останавливался с помощью концевого выключателя. Я использую плату Arduino UNO, 2 концевых выключателя, драйвер двигателя L298N H Bridge и RFID-сканер MFRC522.

Вот схематичное изображение: Схема платы Arduino

Вот код для автоматического розыгрыша с использованием 3 кнопок (2 концевых выключателя, 1 кнопка активации) и двигателя постоянного тока:

// константы не изменятся. Они используются здесь для установки номеров контактов:
const int buttonPin = 4;     // номер вывода кнопки
const int buttonPin3 = 1;     // номер вывода кнопки
const int buttonPin2 = 2;     // номер вывода кнопки
const int motorPin =  5;      // номер вывода светодиода
const int motorPin2 =  6;      // номер вывода светодиода

// переменные изменятся:
boolean buttonState = 0;         // переменная для чтения статуса кнопки
boolean buttonState2 = 0;         // переменная для чтения статуса кнопки
boolean buttonState3 = 0;   // переменная для чтения статуса кнопки


int drawPosition = 2;  // Сообщаем программе, в какой позиции находится ничья


/**
 *  setup inputs for switches and outs for motor pins
 *  serial begin to read the switches to test for errors
 */
void setup() {
    // инициализируем пин как вход:
    pinMode(motorPin, OUTPUT);
    pinMode(motorPin2, OUTPUT);
    // инициализируем контакт кнопки как вход:
    pinMode(buttonPin, INPUT);
    pinMode(buttonPin2, INPUT);
    pinMode(buttonPin3, INPUT);
    Serial.begin(9600);
}

/**
 * this function turns motor foward 
 */
void drawForward() {
     // повернуть мотор вперед:
     digitalWrite(motorPin, LOW);
     digitalWrite(motorPin2, HIGH);
}

/**
 * this function turns motor backwards
 */
void drawBackward() {
     // повернуть мотор в другую сторону:
     digitalWrite(motorPin, HIGH);
     digitalWrite(motorPin2, LOW);  
}

/**
 * Stop the motor form moving
 */
void stopDrawFromMoving() {
  digitalWrite(motorPin, LOW);
  digitalWrite(motorPin2, LOW);

}


/**
 * 
 */
void loop() {
   // прочитать состояние значения кнопки:
     buttonState = digitalRead(buttonPin);
     buttonState2 = digitalRead(buttonPin2);
   buttonState3 = digitalRead(buttonPin3);



   // проверяем, нажата ли кнопка. Если да, то состояние кнопки ВЫСОКОЕ:
   if (buttonState == HIGH) {
      drawPosition = 2; 
      Serial.println(F("Front button state is high draw is open")); 
      stopDrawFromMoving();
   }else if (buttonState2 == HIGH) {
      drawPosition = 1;        
      stopDrawFromMoving();
  } 

  if (buttonState3 == HIGH) {
    if( drawPosition  == 1 ){
      drawBackward(); 
      delay(100);      
      drawPosition = 2;
      delay(100);  
    }else if (drawPosition == 2 ) {
      delay(100); 
      drawForward();
      delay(100); 
      drawPosition = 1;       
    }

  }
}

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

Вот код, в котором я попытался объединить код RFID и код автоматического розыгрыша:

#include <EEPROM.h>     // Мы будем читать и записывать UID PICC из/в EEPROM
#include <SPI.h>        // Модуль RC522 использует протокол SPI
#include <MFRC522.h>  // Библиотека для устройств Mifare RC522

//настройка входов для концевых выключателей и выходов для драйвера двигателя H Bridge
const int buttonPin = 4;     // номер вывода кнопки
const int buttonPin2 = 2;     // номер вывода кнопки
const int motorPin =  6;      // количество моторов H Bridge (L298N) pin
const int motorPin2 =  5;      // количество моторов H Bridge (L298N) pin


// переменные для состояния концевых выключателей
boolean buttonState = 0;
boolean buttonState2 = 0;
int drawPosition = 2;  // Сообщаем программе, в какой позиции находится ничья

// это функция, которая будет вызываться внутри цикла. это заставляет двигатель поворачиваться вперед
void drawForward() {
  // включаем драйвер двигателя H Bridge в прямой полярности
  digitalWrite(motorPin, LOW);
  digitalWrite(motorPin2, HIGH);
}
// и эта функция поворачивает мотор назад
void drawBackward() {
  // включаем H-мост с ОБРАТНОЙ полярностью
  digitalWrite(motorPin, HIGH);
  digitalWrite(motorPin2, LOW);
}
//Эта функция вызывается, когда двигатель должен ОСТАНОВИТЬСЯ
void stopDrawFromMoving() {
  // выключаем драйвер двигателя моста H, переводя оба контакта в положение LOW
  digitalWrite(motorPin, LOW);
  digitalWrite(motorPin2, LOW);
}

// Просто для работы RFID
boolean match = false;          // инициализируем совпадение карты со значением false
boolean programMode = false;  // инициализируем режим программирования в false
int successRead;    // Целое число переменной, которое нужно сохранить, если у нас есть успешное чтение из считывателя
byte storedCard[4];   // Сохраняет идентификатор, считанный из EEPROM
byte readCard[4];   // Сохраняет отсканированный идентификатор, считанный из модуля RFID
byte masterCard[4];   // Сохраняет идентификатор мастер-карты, считанный из EEPROM
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Создать экземпляр MFRC522.

///////////////////////////////////////// Настраивать //////// ////////////////////////////
void setup() {
  // Настройка цифрового считывания для концевых выключателей
  buttonState = digitalRead(buttonPin);
  buttonState2 = digitalRead(buttonPin2);

  //Конфигурация протокола для сканера RIFD
  Serial.begin(9600);  // Инициализация последовательной связи с ПК
  SPI.begin();           // Аппаратное обеспечение MFRC522 использует протокол SPI
  mfrc522.PCD_Init();    // Инициализировать оборудование MFRC522
  // Это устанавливает максимальный диапазон RFID
  mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
  Serial.println(F("BlueCore Tech Acces Control"));   // В целях отладки

  // Проверяем, определена ли мастер-карта, если нет, позволяем пользователю выбрать мастер-карту
  if (EEPROM.read(1) != 143) {
    Serial.println(F("No Master Card Set"));
    Serial.println(F("Scan A RFID Card to Set as Master Card"));
    do {
      successRead = getID();            // устанавливает для SuccessRead значение 1, когда мы получаем чтение от читателя, в противном случае 0
    }
    while (!successRead);                  // Программа не пойдет дальше, пока вы не получите успешное чтение
    for ( int j = 0; j < 4; j++ ) {        // Цикл 4 раза
      EEPROM.write( 2 + j, readCard[j] );  // Запись UID отсканированного PICC в EEPROM, начиная с адреса 3
    }
    EEPROM.write(1, 143);                  // Запись в EEPROM, которую мы определили для Master Card.
    Serial.println(F("Master Card Set"));
  }
  Serial.println(F("-------------------"));
  Serial.println(F("Master Card's UID = "));
  for ( int i = 0; i < 4; i++ ) {          // Чтение UID Master Card из EEPROM
    masterCard[i] = EEPROM.read(2 + i);    // Записываем на masterCard
    Serial.print(masterCard[i], HEX);
  }
  Serial.println("");
  Serial.println(F("-------------------"));
  Serial.println(F("Everything Ready"));
  Serial.println(F("Waiting for Keys or cards to be scanned"));
  cycleLeds();    // Все готово, давайте дадим пользователю некоторую обратную связь, запустив светодиоды
}
///////////////////////////////////////// Основной цикл /////// /////////////////////////////
void loop () {

// этот первый фрагмент «если» всегда устанавливает переменную из «1» или «2» в зависимости от того, какой концевой выключатель закрыт, это позволяет программе ЗАПОМНИТЬ, какова позиция ничьей.
  if (buttonState == HIGH) {   //если задний концевой выключатель замкнут, тяга находится в закрытом (или обратном) положении
    drawPosition = 2;    //устанавливает переменную в "2", что означает, что розыгрыш находится в закрытом положении
    Serial.println(F("Front button state is high so draw is open"));
    stopDrawFromMoving();  // это также останавливает движение двигательной формы вперед
  } else if (buttonState2 == HIGH) { // здесь применяется тот же принцип, только наоборот:
    drawPosition = 1;
    Serial.println(F("Back button state is high draw is open"));
    stopDrawFromMoving();
  }


// ЗДЕСЬ ОШИБКА, НЕ МОГУ ИСПРАВИТЬ /////////////////////////////////////////// /////////////////////////////////////ЗДЕСЬ ОШИБКА, НЕ МОГУ ИСПРАВИТЬ////// ////////////////////////////////////ЗДЕСЬ ОШИБКА, НЕ МОГУ ИСПРАВИТЬ/////// /////////////////////////////////
// 'getID' не был объявлен в этом статусе выхода области видимости 1 это происходит в любом месте внутри цикла, где упоминается функция 'getID'. Хотя это происходит только в том случае, если вы вызываете функцию, но она не существует, но она явно существует, потому что она внизу
  do {
    successRead = getID();  // устанавливает для SuccessRead значение 1, когда мы получаем чтение от читателя, в противном случае 0
    if (programMode) {
    }
    else {
      normalModeOn();     // Нормальный режим, горит синий индикатор питания, все остальные выключены
    }
  }
  while (!successRead);   // программа не пойдет дальше, пока вы не получите успешное чтение
  if (programMode) {
    if ( isMaster(readCard) ) { //Если мастер-карта снова просканирована, выходим из режима программирования
      Serial.println(F("Master Card Scanned"));
      Serial.println(F("Exiting Programming Mode"));
      Serial.println(F("-----------------------------"));
      programMode = false;
      return;
    }
    else {
      if ( findID(readCard) ) { // Если известна отсканированная карта, удаляем ее
        Serial.println(F("I know this key, removing..."));
        deleteID(readCard);
        Serial.println("-----------------------------");
      }
      else {                    // Если отсканированная карта неизвестна, добавляем ее
        Serial.println(F("I do not know this key, adding..."));
        writeID(readCard);
        Serial.println(F("-----------------------------"));
      }
    }
  }
  else {
    if ( isMaster(readCard) ) {   // Если ID отсканированной карты совпадает с ID мастер-карты, переходим в программный режим
      programMode = true;
      Serial.println(F("Hello Master - Entered Programming Mode"));
      int count = EEPROM.read(0);   // Читаем первый байт EEPROM, который
      Serial.print(F("I have "));     // сохраняет количество идентификаторов в EEPROM
      Serial.print(count);
      Serial.print(F(" record(s) in DATABASE"));
      Serial.println("");
      Serial.println(F("Scan a Card or key to ADD or REMOVE"));
      Serial.println(F("-----------------------------"));
    }
    else {
      if ( findID(readCard) ) {  // Если нет, смотрим, есть ли карта в EEPROM
        Serial.println(F("Welcome, Acces Granted"));
        // это еще одна часть другого кода, который я пытаюсь внедрить в код RFID
        if ( drawPosition  == 1 ) { //если переменная говорит, что ничья в настоящее время находится в позиции FOWARD
          drawBackward();  //затем возвращаем его в НАЗАД
          delay(100);
          drawPosition = 2;  //затем сделайте переменную равной "2", чтобы код помнил, в какой позиции находится рисунок, когда в следующий раз активируется RFID-сканер
          delay(100);
        } else if (drawPosition == 2 ) {  //здесь тот же принцип, но только наоборот, когда ничья находится в противоположной позиции и должна вернуться в противоположную позицию
          delay(100);
          drawForward();
          delay(100);
          drawPosition = 1;
        }
      }
      else {   // Если токен неизвестен, показать, что идентификатор недействителен, и больше ничего не делать
        Serial.println(F("Acces Denied!"));
      }
    }

  }
  ///////////////////////////////////////// Получить UID PICC ////// //////////////////////////////
  int getID() {
    // Подготовка к чтению PICC
    if ( ! mfrc522.PICC_IsNewCardPresent()) { //Если новая PICC помещена в считыватель RFID, продолжить
      return 0;
    }
    if ( ! mfrc522.PICC_ReadCardSerial()) {   //После размещения PICC получаем серийный номер и продолжаем
      return 0;
    }
    // Существуют PICC Mifare, которые имеют 4-байтовый или 7-байтовый UID, если вы используете 7-байтовый PICC.
    // Я думаю, мы должны предположить, что все PICC имеют 4-байтовый UID
    // Пока мы не поддержим 7-байтовые PICC
    Serial.println(F("Scanned KEY's UID:"));
    for (int i = 0; i < 4; i++) {  //
      readCard[i] = mfrc522.uid.uidByte[i];
      Serial.print(readCard[i], HEX);
    }
    Serial.println("");
    mfrc522.PICC_HaltA(); // Остановить чтение
    return 1;
  }
  ///////////////////////////////////////// Показать сведения о считывателе ////// //////////////////////////////
  void ShowReaderDetails() {
    // Получить версию программного обеспечения MFRC522
    byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
    Serial.print(F("MFRC522 Version: 0x"));
    Serial.print(v, HEX);
    if (v == 0x91)
      Serial.print(F(" = v1.0"));
    else if (v == 0x11)
      Serial.print(F(" = BlueCore Tech. RFID Acces v2.0"));
    else
      Serial.print(F(" (unknown)"));
    Serial.println("");
    // Когда возвращается 0x00 или 0xFF, связь, вероятно, не удалась
    if ((v == 0x00) || (v == 0xFF)) {
      Serial.println(F("WARNING: Communication failure, is the RFID-MFRC522 properly connected?"));
      while (true); // дальше не идем
    }
  }
  //////////////////////////////////////// Чтение идентификатора из EEPROM ///// //////////////////////////
  void readID( int number ) {
    int start = (number * 4 ) + 2;    // Определяем начальную позицию
    for ( int i = 0; i < 4; i++ ) {     // Повторить 4 раза, чтобы получить 4 байта
      storedCard[i] = EEPROM.read(start + i);   // Присваиваем значения, считанные из EEPROM, массиву
    }
  }
  ///////////////////////////////////////// Добавить ID в EEPROM ///// ///////////////////////////////
  void writeID( byte a[] ) {
    if ( !findID( a ) ) {     // Перед записью в EEPROM проверяем, не видели ли мы эту карту раньше!
      int num = EEPROM.read(0);     // Получить количество использованных мест, позиция 0 хранит количество удостоверений личности
      int start = ( num * 4 ) + 6;  // Выясняем, где начинается следующий слот
      num++;                // Увеличиваем счетчик на единицу
      EEPROM.write( 0, num );     // Записываем новый счетчик в счетчик
      for ( int j = 0; j < 4; j++ ) {   // Цикл 4 раза
        EEPROM.write( start + j, a[j] );  // Записываем значения массива в EEPROM в правильную позицию
      }
      successWrite();
      Serial.println(F("Succesfully added ID record to DATABASE"));
    }
    else {
      failedWrite();
      Serial.println(F("Failed! There is something wrong with ID or bad DATABASE"));
    }
  }
  ///////////////////////////////////////// Удалить ID из EEPROM ///// ///////////////////////////////
  void deleteID( byte a[] ) {
    if ( !findID( a ) ) {     // Прежде чем удалять из EEPROM, проверяем, есть ли у нас эта карта!
      failedWrite();      // Если не
      Serial.println(F("Failed! There is something wrong with ID or bad DATABASE"));
    }
    else {
      int num = EEPROM.read(0);   // Получить количество использованных мест, позиция 0 хранит количество удостоверений личности
      int slot;       // Определяем номер слота карты
      int start;      // = (число * 4) + 6; // Выясняем, где начинается следующий слот
      int looping;    // Количество повторений цикла
      int j;
      int count = EEPROM.read(0); // Читаем первый байт EEPROM, в котором хранится количество карт
      slot = findIDSLOT( a );   // Определяем номер слота карты для удаления
      start = (slot * 4) + 2;
      looping = ((num - slot) * 4);
      num--;      // Уменьшаем счетчик на единицу
      EEPROM.write( 0, num );   // Записываем новый счетчик в счетчик
      for ( j = 0; j < looping; j++ ) {         // Зацикливаем время сдвига карты
        EEPROM.write( start + j, EEPROM.read(start + 4 + j));   // Сдвигаем значения массива на 4 позиции раньше в EEPROM
      }
      for ( int k = 0; k < 4; k++ ) {         // Цикл сдвига
        EEPROM.write( start + j + k, 0);
      }
      successDelete();
      Serial.println(F("Succesfully removed ID record from DATABASE"));
    }
  }
  ///////////////////////////////////////// Проверка байтов /////// /////////////////////////////
  boolean checkTwo ( byte a[], byte b[] ) {
    if ( a[0] != NULL )       // Сначала убедитесь, что в массиве есть что-то
      match = true;       // Предположим, что сначала они совпадают
    for ( int k = 0; k < 4; k++ ) {   // Цикл 4 раза
      if ( a[k] != b[k] )     // ЕСЛИ a != b, то установить match = false, один сбой, все сбой
        match = false;
    }
    if ( match ) {      // Проверяем, верно ли еще совпадение
      return true;      // Вернуть истину
    }
    else  {
      return false;       // Возвращаем ложь
    }
  }
  ///////////////////////////////////////// Найти слот /////// /////////////////////////////
  int findIDSLOT( byte find[] ) {
    int count = EEPROM.read(0);       // Читаем первый байт EEPROM, который
    for ( int i = 1; i <= count; i++ ) {    // Один цикл для каждой записи EEPROM
      readID(i);                // Читаем ID из EEPROM, он хранится в storeCard[4]
      if ( checkTwo( find, storedCard ) ) {   // Проверяем, читается ли StoreCard из EEPROM
        // то же самое, что и переданная ID-карта find[]
        return i;         // Номер слота карты
        break;          // Хватит искать, мы нашли
      }
    }
  }
  ///////////////////////////////////////// Найти ID из EEPROM ///// ///////////////////////////////
  boolean findID( byte find[] ) {
    int count = EEPROM.read(0);     // Читаем первый байт EEPROM, который
    for ( int i = 1; i <= count; i++ ) {    // Один цикл для каждой записи EEPROM
      readID(i);          // Читаем ID из EEPROM, он хранится в storeCard[4]
      if ( checkTwo( find, storedCard ) ) {   // Проверяем, читается ли StoreCard из EEPROM
        return true;
        break;  // Хватит искать, мы нашли
      }
      else {    // Если нет, возвращаем false
      }
    }
    return false;
  }
  ///////////////////////////////////////// Успех записи в EEPROM ///// ///////////////////////////////
  void successWrite() {
    Serial.println(F("Write to EEPROM is Succsusful"));
  }
  ///////////////////////////////////////// Ошибка записи в EEPROM ///// ///////////////////////////////
  void failedWrite() {
    Serial.println(F("Failed to write to EEPROM"));
  }
  ///////////////////////////////////////// Успех Удалить UID из EEPROM //// /////////////////////////////////
  void successDelete() {
    Serial.println(F("Removed from EEPROM"));
  }
  /////////////////////// Проверить readCard, ЕСЛИ это masterCard /////////////////////// /////////////
  // Проверяем, является ли переданный идентификатор главной картой программирования
  boolean isMaster( byte test[] ) {
    if ( checkTwo( test, masterCard ) )
      return true;
    else
      return false;
  }

Итак, во втором коде есть две основные ошибки (код, реализующий RFID с моей логикой концевого выключателя и функциями двигателя). Первый был совершенно очевиден в коде, когда я сказал «ОШИБКА ЗДЕСЬ», и ошибка была «статус выхода 1, getID не был объявлен в этой области». Не уверен, почему это происходит, я не могу понять это. Как только это будет исправлено, я смогу взглянуть на основную проблему, и это действительно заставит ее работать. Я протестировал код до того, как получил эту ошибку статуса выхода, и логика не работала. Вероятно, есть лучший способ объединить эти фрагменты кода, но я новичок в программировании и не могу понять, как это сделать.

Большое спасибо за помощь ( :

, 👍0

Обсуждение

Проблема с getid была исправлена, я просто переместил все функции в начало кода, чтобы компилятор считывал их до того, как он попадет в код цикла. Но код все еще не работает на практике. Токены вообще не читаются, а мастер-карта есть. Код пытается запустить двигатель и выполнить весь этот код, как только обнаружит известный токен. Любая помощь будет здорово., @Leeham


1 ответ


2

C++ и C считывают объявления функций и глобальные переменные только сверху вниз, он не будет заглядывать вперед, чтобы увидеть, были ли определены какие-либо другие.

Вы можете поместить объявление функций, которые хотите использовать, выше, где вы хотите их использовать.

//...
int getID();
///////////////////////////////////////// Main Loop ///////////////////////////////////
void loop () {
//...
,

Обычно среда разработки Arduino пытается генерировать объявления автоматически., @Craig

спасибо, я постараюсь поставить их все на первое место и дам вам знать, как это происходит, @Leeham