Добрый! Ну что ж, прошла неделя с покупки набора ардуино и пробы "пера", а вот теперь появились вопросы. Прошу помощи у сообщества, если вопросы глупые - дайте хоть вектор куда копать, какой код глянуть Суть - пишу простую GMS сигнализацию (коих достаточно, но интересен сам процесс набивания шишек). Прикладываем ключ, система ставится под охрану. Второй раз прикладываем - снимается с охраны. Пока в режиме охраны должен идти опрос геркона. Датчик пока один - геркон на двери, потом планирую добавить. Итого надо в цикле опрашивать все датчики + считывать данные с RFID Дано: ардуино мега, RFID считыватель (RC522), простой геркон, пара LED (красный и зеленый). Сразу столкнулся с тем, что поиск карты останавливает loop(). Использовал за основу стандартный код. Код (Text): if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } В итоге, пока решил использовать прерывание (для одного датчика, хотя для 3-4-5 это имхо не выход). Но вот тут столкнулся с тем, что при срабатывании геркона всегда получаю "единицу" на пин 2. Приложил магнит, убрал магнит - всегда считывается 1. (Аппаратного или программного "анитдребезга" нет) Сам код полностью (он страшноват, вижу часть моментов, которые надо переделать) Код (C++): #include <SPI.h> #include <MFRC522.h> #define SS_PIN 53 #define RST_PIN 9 // объект MFRC522 MFRC522 mfrc522(SS_PIN, RST_PIN); // для отображения номера карточки в десятичном формате unsigned long idKey, idKeyTemp; byte bCounter, readBit; unsigned long ticketNumber; /* Переменные Pin */ int pinRed = 6; int pinGreen = 7; int pinDoor = 0; /* Массив ключей */ char* myKeys[] = {"1111111111", "2222222222"}; String txtKey = ""; /**********************************************************/ void printInfo(String txt) { Serial.println(txt); } boolean checkKey(String txt) { boolean validKey = false; for (int i = 0; i < 2; i++) { if ((txtKey == myKeys[i]) && (!validKey)) { validKey = true; } } if (validKey) { return true; //ключ найден в массиве } else { return false; //ключ не найден в массиве } } void setup() { Serial.begin(9600); // инициализация SPI SPI.begin(); // инициализация MFRC522 mfrc522.PCD_Init(); pinMode(pinRed, OUTPUT); pinMode(pinGreen, OUTPUT); pinMode(pinDoor, INPUT); attachInterrupt(pinDoor, swap, CHANGE ); } void swap() { /* if (digitalRead(pinDoor) == LOW) { Serial.println("Door open"); } else { Serial.println("Door close"); } */ Serial.println(digitalRead(pinDoor)); //тут всегда единица } void loop() { // Поиск новой карточки if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Выбор карточки if ( ! mfrc522.PICC_ReadCardSerial()) { return; } idKey = 0; // Выдача серийного номера карточки printInfo("Card UID:"); for (byte i = 0; i < mfrc522.uid.size; i++) { idKeyTemp = mfrc522.uid.uidByte[i]; idKey = idKey*256+idKeyTemp; } txtKey = String(idKey); printInfo(txtKey); if (checkKey(txtKey)) { digitalWrite(pinGreen, HIGH); digitalWrite(pinRed, LOW); } else { digitalWrite(pinRed, HIGH); digitalWrite(pinGreen, LOW); } // Halt PICC mfrc522.PICC_HaltA(); } В перывании менял режим обработки. Все равно при срабатывании на выходе единица, а хотелось бы считывания состояние геркона, чтобы понимать открыта дверь или нет (как вариант можно менять переменную логическую при срабатывании геркона). Второй вариант - сделать наоборот, в основном цикле идет проверка состояния датчиков, а вот считывание ключа вынести. Но пока ненагуглил хоть примерный код, как это реализовать
Для начала рекомендую библиотеку MFRC522.h заменить на RFID.h она менее глючная и код получается короче, что иногда критично.
Странный вы - pinDoor у вас описан как 0, читаете вы, соответственно, с пина аппаратного UART. Вы чего там хотите увидеть-то? Если хотите юзать прерывания, то это пины 2 и 3, соответственно код будет: Код (C++): #define pinDoor 2 void swap() { Serial.println(digitalRead(pinDoor)); } void setup() { attachInterrupt(digitalPinToInterrupt(pinDoor),swap,CHANGE); } Разницу видите?
Физически геркон у меня висит на втором пине, а ноль указан в соответствии с этим видео тем более с "нулевого" пина я получаю событие о срабатывании, но именно событие, а не состояние. попробую упростить вопрос - как параллельно считывать ключи и опрашивать N датчиков. Библиотеку гляну после обеда, спасибо, может там будет проще
Ещё раз: вы читаете состояние не второго пина, а нулевого. Вы вообще разницу понимаете между номером прерывания и номером пина? Я вам привёл полный пример, как номер пина в рамках Arduino IDE переводится в номер прерывания. Хотите делать по своему - пожалуйста, но тогда не удивляйтесь, почему не работает. Повторюсь: прерывания на Uno доступны на пинах 2 и 3, прерывание на пине 2 имеет номер 0, прерывание на пине 3 - номер 1. Для переносимости кода под другие дуины есть функция digitalPinToInterrupt, строго рекомендуется юзать именно её, а не писать какашечный код, руководствуясь какашечными видео. А если хотите читать из пина, на который повешен обработчик прерывания - то надо указывать в digitalRead не номер прерывания, как вы делаете сейчас, а номер пина.
Да, у меня были вчера такие мысли, но не успел попробовать на практике, уже сморило. Конечно, скорее всего вы правы ) Тем не менее в моем случае получится, что я смогу задействовать столько датчиков, сколько есть прерываний. имхо логичнее в loop() пробегать по всем датчикам, проверяя их состояние, но как тогда считывать карту...
Юзайте таймеры, они работают по прерываниям. Возьмите, например, библиотеку Timer One, она лежит на офсайте ардуино - и всё будет. Настройте интервал между опросами датчиков, взведите таймер - и по каждому прерыванию с таймера читайте с очередного датчика. что при этом происходит в loop - уже никого не волнует
Ага, были тоже такие мысли уйти на таймер. Значит хоть вектор у меня правильный Я правильно понимаю, что вынести rfid в принципе из loop не возможно (без дополнительных кнопок, датчиков...)? Либо городить отдельный контроллер на ардуино со считывателем?
все возможно Вынеси в отдельные функции чтение RFID, опрос датчиков, работу с LED и пр. А в loop просто вызывай их с нужной периодичностью.
да, сейчас попробую резюмировать 1) если использовать MFRC522.h и стандартный пример dumpinfo, то там loop выглядит следующим образом Код (C++): void loop() { // Look for new cards if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select one of the cards if ( ! mfrc522.PICC_ReadCardSerial()) { return; } // Dump debug info about the card; PICC_HaltA() is automatically called mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); } т.е. код не выполнится, пока не будет приложена карта/ключ. Значит надо либо проверку ключа выносить из loop(), либо проверку датчиков. Как варианты выше - отдельный датчик вешать на прерывание, либо использовать прерывание по таймеру. 2) если использовать RFID.h, то код будет уже выглядеть так Код (C++): if (rfid.isCard()) { if (rfid.readCardSerial()) { Serial.print(rfid.serNum[0]); Serial.print(","); Serial.print(rfid.serNum[1]); Serial.print(","); Serial.print(rfid.serNum[2]); Serial.print(","); Serial.print(rfid.serNum[3]); Serial.print(","); Serial.print(rfid.serNum[4]); Serial.println(""); for (int x = 0; x < sizeof(cards); x++) { for (int i = 0; i < sizeof(rfid.serNum); i++ ) { if (rfid.serNum[i] != cards[x][i]) { access = false; break; } else { access = true; } } if (access) break; } } if (access) { Serial.println("Key accept!"); } else { Serial.println("Key not found!"); } } rfid.halt(); этот код не останавливает выполнение любого другого Но в первом случае есть некий плюс - карту поднесли и можно держать, она считывается один раз, во втором случае - карта читается "много" раз, пока не уберешь
Домашнее задание, перепишите вот это: Код (C++): Serial.print(rfid.serNum[0]); Serial.print(","); Serial.print(rfid.serNum[1]); Serial.print(","); Serial.print(rfid.serNum[2]); Serial.print(","); Serial.print(rfid.serNum[3]); Serial.print(","); Serial.print(rfid.serNum[4]); Serial.println(""); одной строкой. Не помню чтобы MFRC522.h тормозил всю программу. Он работает аналогично с Serial.available, то есть опрашивает рфид на предмет приложена ли метка, если нет то проскакивает дальше, если да, то считывает данные в массив и опять таки проскакивает дальше. Ваше дело отследить получены ли данные и что то с ними делать. Библиотека RFID.h хороша тем, что чувствует когда метку убрали.
Вот например так хреначит без задержек, перед последней фигурной скобкой ставьте что угодно и вперед. Ну и, само собой, в этом случае заменить delay() на работу с millis(): Код (C++): void loop() { if ( ! mfrc522.PICC_IsNewCardPresent()) // cardUID[0] = 0; return; if ( ! mfrc522.PICC_ReadCardSerial()) // cardUID[0] = 0; return; dump_byte_array(mfrc522.uid.uidByte, 4); // mfrc522.uid.size); compareUID(); mfrc522.PICC_IsNewCardPresent(); mfrc522.PICC_ReadCardSerial(); delay(500); } Вот эти две строки: Код (C++): mfrc522.PICC_IsNewCardPresent(); mfrc522.PICC_ReadCardSerial(); нужны потому, что второй раз подряд эти функции возвращают ерунду.
Но я все же настоятельно рекомендую RFID.h Тогда можно записать такую функцию: Код (C++): bool readUID () { // читаем UID если карта поднесена if (!rfid.isCard()) return false; if (!rfid.readCardSerial()) return false; for (int i = 0; i < 5; i++) { cardUID[i] = rfid.serNum[i]; } rfid.isCard(); return true; } Которую следует вызывать в loop(), она возвращает 0 если карты нет и 1 если есть. Во втором случае в массиве cardUID[] чудесным образом появляется номер поднесенной метки. При этом в loop можно делать что угодно еще, например опрашивать геркон, а то и два!
Вот вам до кучи функция сверки массива считанной метки с массивом эталонной метки: Код (C++): bool validCard (byte * cardMassiv) { // сверка cardUID с заданным массивом 1 - совпало, 0 - не совпало byte valNum = 0; for (byte i = 0; i < 5; i++) { if (*(cardMassiv + i) == cardUID[i]) valNum++; } if (valNum == 5) { return 1; } else { return 0; } }
Значит ставьте вопрос правильно, мол дайте код но с ошибками чтобы я их нашел и сделал лучше чем было!