Arduino RFID с двигателем и концевыми выключателями
Спасибо за изучение моего кода Arduino. Я строю автоматизированную раздвижную тягу и пытаюсь активировать двигатель с помощью RFID-сканера. Сканер ожидает жетон, и как только он обнаруживает жетон, двигатель вращается и ожидает обнаружения концевого выключателя и останавливает двигатель, затем он делает то же самое, когда обнаруживает другой жетон RFID, но вместо этого двигатель движется в противоположном направлении. направлении и ожидает нажатия противоположного концевого выключателя. У меня есть 2 набора кода. Одним из них является код сканера RFID, который работает нормально, но он только включает и выключает реле. Другой код предназначен для двигателя с 2 концевыми выключателями с кнопкой активации. Этот код тоже работает, и розыгрыш открывается и закрывается при нажатии кнопки, но он не работает со сканером RFID. Итак, моя цель состоит в том, чтобы внедрить код сканера RFID в код автоматического рисования, чтобы двигатель вращался и реверсировал с помощью жетона RFID и останавливался с помощью концевого выключателя. Я использую плату Arduino UNO, 2 концевых выключателя, драйвер двигателя L298N H Bridge и RFID-сканер MFRC522.
Вот схематичное изображение:
Вот код для автоматического розыгрыша с использованием 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 не был объявлен в этой области». Не уверен, почему это происходит, я не могу понять это. Как только это будет исправлено, я смогу взглянуть на основную проблему, и это действительно заставит ее работать. Я протестировал код до того, как получил эту ошибку статуса выхода, и логика не работала. Вероятно, есть лучший способ объединить эти фрагменты кода, но я новичок в программировании и не могу понять, как это сделать.
Большое спасибо за помощь ( :
@Leeham, 👍0
Обсуждение1 ответ
C++ и C считывают объявления функций и глобальные переменные только сверху вниз, он не будет заглядывать вперед, чтобы увидеть, были ли определены какие-либо другие.
Вы можете поместить объявление функций, которые хотите использовать, выше, где вы хотите их использовать.
//...
int getID();
///////////////////////////////////////// Main Loop ///////////////////////////////////
void loop () {
//...
Обычно среда разработки Arduino пытается генерировать объявления автоматически., @Craig
спасибо, я постараюсь поставить их все на первое место и дам вам знать, как это происходит, @Leeham
- Как использовать RFID-RC522 с Arduino?
- Как остановить SoftwareSerial от получения данных и повторно включить его в какой-то другой момент?
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
- Использование прерываний с RC522
- Проблема совместного использования MISO с несколькими RFID-считывателями RC522
- rfid_default_keys проверить с помощью RC522
- MFRC522: прошивка неизвестна
- MFRC522 не сканируется карта
Проблема с getid была исправлена, я просто переместил все функции в начало кода, чтобы компилятор считывал их до того, как он попадет в код цикла. Но код все еще не работает на практике. Токены вообще не читаются, а мастер-карта есть. Код пытается запустить двигатель и выполнить весь этот код, как только обнаружит известный токен. Любая помощь будет здорово., @Leeham