открытие замка сервомотором при последовательном приложении FRID меток.

BlackWizard
Offline
Зарегистрирован: 30.05.2017

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

#include <Servo.h> // библиотека сервомотора 
#include <SPI.h>
#include <MFRC522.h> // библиотека "RFID".
#define SS_PIN 10 
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);
unsigned long uidDec, uidDecTemp;  // для храниения номера метки в десятичном формате
Servo servo;
int counter = 0; // добавляем счётчик
void setup()
{
  Serial.begin(9600);
  Serial.println("Waiting for card...");
  SPI.begin();  //  инициализация SPI / Init SPI bus.
  mfrc522.PCD_Init();     // инициализация MFRC522 / Init MFRC522 card.
  servo.attach(6);
  servo.write(0);  // устанавливаем серву в закрытое сосотояние
 }
void loop()
{
    // Поиск новой метки
  if ( ! mfrc522.PICC_IsNewCardPresent()) 
  {
    return;
  }
  // Выбор метки
  if ( ! mfrc522.PICC_ReadCardSerial()) 
  {
    return;
  }
  uidDec = 0;
  // Выдача серийного номера метки.
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    uidDecTemp = mfrc522.uid.uidByte[i];
    uidDec = uidDec * 256 + uidDecTemp;
  }
  Serial.println("Card UID: ");
  Serial.println(uidDec); // Выводим UID метки в консоль.
  delay(1000);
 if (uidDec == 3491476559) // Сравниваем Uid метки, если он равен заданому то увеличиваем счётчик на 1, если нет, то сбрасываем
  {
    if (counter == 0)
    {
      counter++;
      Serial.println( counter);
    }
    else 
    {
      counter =0;
      Serial.println("couner reset1");
    }
  }
  if (uidDec == 4210874628) // Сравниваем Uid метки, если он равен заданому то увеличиваем счётчик на 1, если нет, то сбрасываем
  {
    if (counter == 1)
    {
      counter++;
      Serial.println( counter);
    }
    else 
    {
      counter =0;
      Serial.println("couner reset2");
    }
  }
 if (counter == 2) // если счётчик равен заданному значению работает мотор
  {
      tone(5, 200, 500); // Делаем звуковой сигнал, Открытие
      servo.write(90); // Поворациваем серву на угол 90 градусов(Отпираем какой либо механизм: задвижку, поворациваем ключ и т.д.)
      delay(3000); // пауза 3 сек 
      tone(5, 500, 500); // Делаем звуковой сигнал,  Закрытие
      servo.write(0); // механизм запирается.
      counter = 0; // сбрасываем счётчик
      Serial.println("couner reset3");
  }
 }
 
 

ещё я хочу добавить таймер, который будет включаться после первого приложения метки и сбрасывать счётчик если в течении 5 секунд не приложить вторую метку, но не смог понять как это сделать. 

Очень прошу вашей помощи в этом вопросе

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

BlackWizard пишет:

решил сделать программу... получился вот такой код:

Давайте уточним, Вы решили найти готовый код и нашли его вот в этой теме. И не спорьте, пожалуйста. Человек, сам написавший этот код не может не понимать как сделать задержку.

BlackWizard пишет:

ещё я хочу добавить ... но не смог понять как это сделать. 

Просто подумайте и сделайте.

Для начала сделайте отдельно (самостоятельной программой) отработку задержки, а потом попробуйте вставить её в этот код. Если будет работать неправильно, публикуйте что получилось, обсудим.

BlackWizard пишет:

Очень прошу вашей помощи в этом вопросе

Помощь обязательно будет, если Вы попытаетесь сделать самостотельно и у Вас не получится.

Тем же, кто скачал чужой код и просит, чтобы его модифицировали, помогают не здесь, а в другом разделе форума.

BlackWizard
Offline
Зарегистрирован: 30.05.2017

я взял код из той темы, и модифицировал его под свои нужды

отработка завдержки используя millis или библиотеку SmartDelay получается но в первом случае счётчик начинает отчёт от начала программы и срабатывает в любом случае через определенный период, что мне не подходит, во втором случае период отчёта начинается от срабатывания первой метки и постоянно повторяется, если не попасть в этот промежуток то мотор не поворачивается

#include <Servo.h>
#include <SPI.h>
#include <MFRC522.h> // библиотека "RFID".
#include <SmartDelay.h>
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);
unsigned long uidDec, uidDecTemp;  // для храниения номера метки в десятичном формате
Servo servo;
int counter = 0;
SmartDelay del(3000000UL);
void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for card...");
  SPI.begin();  //  инициализация SPI / Init SPI bus.
  mfrc522.PCD_Init();     // инициализация MFRC522 / Init MFRC522 card.
  servo.attach(6);
  servo.write(0);  // устанавливаем серву в закрытое сосотояние
   }
void loop() {
   // Поиск новой метки
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }
  // Выбор метки
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }
  uidDec = 0;
  // Выдача серийного номера метки.
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    uidDecTemp = mfrc522.uid.uidByte[i];
    uidDec = uidDec * 256 + uidDecTemp;
  }
  if (del.Now()) {
    counter = 0;
    Serial.println( counter);// Код здесь выполняется каждый интервал в микросекундах, указанный в конструкторе выше.
  }
  Serial.println("Card UID: ");
  Serial.println(uidDec); // Выводим UID метки в консоль.
  delay(1000);
  if (uidDec == 3491476559 and counter == 0) // Сравниваем Uid метки, если он равен заданому то серва открывает.
  {
    counter++;
    Serial.println( counter);
  }
  if (uidDec == 4210874628 and counter == 1)
    {
   counter++;
   Serial.println( counter);
    }
while (counter == 2)
    {
      tone(5, 200, 500); // Делаем звуковой сигнал, Открытие
      servo.write(90); // Поворациваем серву на угол 90 градусов(Отпираем какой либо механизм: задвижку, поворациваем ключ и т.д.)
      delay(3000); // пауза 3 сек и механизм запирается.
      tone(5, 500, 500); // Делаем звуковой сигнал,  Закрытие
      servo.write(0); 
      counter = 0;
    }
}
 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Просто продумайте логику работы задержки, выпишите её на бумаге и внимательно запрограммируйте.

BlackWizard
Offline
Зарегистрирован: 30.05.2017

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Легко. Вот только и не для всех йорурты полезны. Создаешь класс - Серво-замок с двумя методами ON1() и ON2(). Если их вызывать последовательно и заданое время - то замок естественно откроится. А еще создаешь класс  анализатора frid меток с двумя обработчиками: 1 - опозналась метка 1 , а 2 - разумеется вторая. Собираешь в общую кучу и готово. Вот только скетч приведеный выше надо очень сильно переписать.

BlackWizard
Offline
Зарегистрирован: 30.05.2017

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А пусть сам замок решает когда ему надо открывать замок а когда нет. Но если между методами ON1 и ОN2 то ему точно открвать не надо.

И вот вам схема программы.

/*Servo_lock.ino
*/
//--------------------class Cl_Servo_lock------------------------
class Cl_Servo_lock {
  public:
    // указатель на следующий элемент
    Cl_Servo_lock *pnt;
    // конструктор
    Cl_Servo_lock(): pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
    }
    void ON1() {}
    void ON2() {}
};
//--------------------class Cl_frid------------------------frid
class Cl_frid {
    void (*Do1)(), (*Do2)();
    uint32_t com1, com2;
  public:
    // указатель на следующий элемент
    Cl_frid *pnt;
    // конструктор
    Cl_frid(uint32_t _com1, void (*_Do1)(), uint32_t _com2, void (*_Do2)())
      : com1(_com1), Do1(_Do1), com2(_com2), Do2(_Do2), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
    }

};
//-----------------class Cl_sys---------------------------
class Cl_sys {
    Cl_Servo_lock *Start_Servo = NULL;
    Cl_frid *Start_frid = NULL;
  public:
    Cl_sys() {}
    void Plug(Cl_Servo_lock * obj) {
      obj->pnt = Start_Servo;
      Start_Servo = obj;
    }
    void Plug(Cl_frid * obj) {
      obj->pnt = Start_frid;
      Start_frid = obj;
    }
    void setup() {
      Start_Servo->setup();
      Start_frid->setup();
    }
    void loop() {
      Start_Servo->loop();
      Start_frid->loop();
    }
} Sys;
//--------------------------------------------
Cl_Servo_lock Servo;// подключить серву-замок
void Do_frid1() {
  Servo.ON1();
}
void Do_frid2() {
  Servo.ON2();
}
Cl_frid frid (/*метка*/1,/*обработчик*/ Do_frid1,
              /*метка*/2,/*обработчик*/ Do_frid2)      ; // подключить модуль frid_1

void setup() {
  Sys.Plug(&Servo);
  Sys.Plug(&frid);

  Sys.setup();
}
void loop() {
  Sys.loop();
}

 

BlackWizard
Offline
Зарегистрирован: 30.05.2017

благодарю, буду разбираться

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А это на серве и 3 кнопках 

/*Servo_lock_v2.ino
  серва   -> 5
  кнопка1 ->2
  кнопка2 ->3
  кнопка3 ->4
  принцип серва откроется если послед нажать кнопки 1 и 2, кнопка 3 сбрасывает послед
*/
//--------------------class Cl_Servo_lock------------------------
#include <Servo.h> // библиотека сервомотора
const byte angleOFF = 0;// угол закрытой сервы
const byte angleON = 90;// угол открытой сервы
const uint32_t lock_time = 2000; // максим время между 1 и 2  проверками
class Cl_Servo_lock {
    byte pin;// нога
    Servo *myServo;// указатель на серву
    byte stat ; // состояние сервы 0 закрыта /1 первая проверка/ 2 открыта
    uint32_t past = 0;
  public:
    // указатель на следующий элемент
    Cl_Servo_lock *pnt;
    // конструктор
    Cl_Servo_lock(byte _pin): pin(_pin), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      myServo = new Servo;
      myServo->attach(pin);
      myServo->write(angleOFF);
      stat = 0;
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if ((stat == 1) && (millis() - past > lock_time)) stat = 0;
    }
    void ON1() {  // прошла 1 проверка
      past = millis();
      stat = 1;
    }
    void ON2() {
      if ((stat == 1) && (millis() - past <= lock_time)) { // если прошли проверку то открыть
        stat = 2;
        myServo->write(angleON);
      } else     stat = 0;
    }
    void Break() {
      stat = 0;
    }
};
//--------------------class Cl_Btn------------------------
// класс кнопки с 1 обработчиком кнопки
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // указатель на следующую
    Cl_Btn *pnt = NULL;
    // конструктор
    Cl_Btn(byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {};
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//-----------------class Cl_sys---------------------------
class Cl_sys {
    Cl_Servo_lock *Start_Servo = NULL;
    Cl_Btn *Start_Btn = NULL;
  public:
    Cl_sys() {}
    void Plug(Cl_Servo_lock * obj) {
      obj->pnt = Start_Servo;
      Start_Servo = obj;
    }
    void Plug(Cl_Btn * obj) {
      obj->pnt = Start_Btn;
      Start_Btn = obj;
    }
    void setup() {
      Start_Servo->setup();
      Start_Btn->setup();
    }
    void loop() {
      Start_Servo->loop();
      Start_Btn->loop();
    }
} Sys;
//--------------------------------------------
Cl_Servo_lock Servo(/*пин*/5);// подключить серву-замок
void Do_Btn_1() {
  Servo.ON1();
}
void Do_Btn_2() {
  Servo.ON2();
}
void Do_Btn_3() {
  Servo.Break();
}
Cl_Btn Btn_1(/*пин*/2,/*обработчик*/ Do_Btn_1); // подключить кнопку 1
Cl_Btn Btn_2(/*пин*/3,/*обработчик*/ Do_Btn_2); // подключить кнопку 2
Cl_Btn Btn_3(/*пин*/4,/*обработчик*/ Do_Btn_3); // подключить кнопку 3

void setup() {
  Sys.Plug(&Servo);

  Sys.Plug(&Btn_1);
  Sys.Plug(&Btn_2);
  Sys.Plug(&Btn_3);

  Sys.setup();
}
void loop() {
  Sys.loop();
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

BlackWizard пишет:

я не очень хорошо представляю как это должно быть реализовано, знаю только что должно получится,

Беда в том, что Вы и этого не знаете. В смысле не знаете с нужным уровнем детализации.

Я вот предложил Вам сесть и расписать что должно получиться, Вы этот совет проигнорировали. дело Ваше. Если бы Вы ему последовали, расписали бы и показали бы мне, я бы указал что не так распиано, Вы бы поправили. В итоге, Вы бы и сами не заметили как из этой словесной росписи получилась бы программа. Но Вы, видимо посчитали. что я пошутил насчёт "сесть и расписать" - дело Ваше.

Помните у "Наутилуса" Андрей домогался к Христу - "научи по воде ходить", а тот ему - "повиси на кресте и приходи", а Андрей - "типа, хрен с ним с крестом, ты по воде ходить научи". Так и у нас с Вами. Делать то, что нужно для того, чтобы научиться Вы не хотите, и жалуетесь, что не получается.

BlackWizard
Offline
Зарегистрирован: 30.05.2017

логика работы программы видится мне следующим образом: 

ожидание метки-> метка1-> запуск таймера, увеличение счётчика на 1, если нет то счётчик=0-> метка2-> если счётчик =1 и таймер<10сек ->увеличение счётчика на 1, если нет то счётчик=0->метка3-> если счётчик =2 и таймер<10сек ->увеличение счётчика на 1, если нет то счётчик=0->если счётчик=3, открытие мотора-> закрытие мотора, счётчик=0

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

BlackWizard.  Так программировать уже не "модно", я бы сказал отстойно, убого . Сети умные дома Интернет и прочая хрень , которая требует другого подхода к программированию . Вот только "программирование в Ардуине" находится в ЖОПЕ. Никогда не смотри что у вас 1 Ардуина. Рассматривайте что у вас БРИГАДА из классов. У вас FRID датчик . Что он должен делать? Подать сигналы что пришла 1 карточка, пришла 2 карточка, пришла левая карточка и все. У вас Серва . Что она должна делать? Если последовательно пришло по времени 2 сигнала : 1 карточка, 2 карточка . В других случаях на все забить. 

ПС: модернизировал программу с сервой и кнопками , если кому интересно, то можно "покататься"

/*Servo_lock_v2.ino
  серва   -> 5
  кнопка1 ->2
  кнопка2 ->3
  кнопка3 ->4
  принцип серва откроется если послед нажать кнопки 1 и 2, кнопка 3 сбрасывает послед
*/
//--------------------class Cl_Servo_lock------------------------
#include <Servo.h> // библиотека сервомотора
const byte angleOFF = 0;// угол закрытой сервы
const byte angleON = 90;// угол открытой сервы
const uint32_t lock_time = 2000; // максим время между 1 и 2  проверками
const uint32_t ON_time = 3000; //  время в которое серва будет в состоянии ON
class Cl_Servo_lock {
    byte pin;// нога
    Servo *myServo;// указатель на серву
    byte stat ; // состояние сервы 0 закрыта /1 первая проверка/ 2 открыта
    uint32_t past = 0;
  public:
    // указатель на следующий элемент
    Cl_Servo_lock *pnt;
    // конструктор
    Cl_Servo_lock(byte _pin): pin(_pin), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      myServo = new Servo;
      myServo->attach(pin);
      myServo->write(angleOFF);
      stat = 0;
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (stat == 1 && millis() - past > lock_time) stat = 0;
      if (stat == 2 && millis() - past > ON_time) {
        stat = 0;
        myServo->write(angleOFF);
      }
    }
    void ON1() {  // прошла 1 проверка
      past = millis();
      stat = 1;
    }
    void ON2() {
      if ((stat == 1) && (millis() - past <= lock_time)) { // если прошли проверку то открыть
        stat = 2;
        past = millis();
        myServo->write(angleON);
      } else     stat = 0;
    }
    void Break() {
      stat = 0;
    }
};
//--------------------class Cl_Btn------------------------
// класс кнопки с 1 обработчиком кнопки
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // указатель на следующую
    Cl_Btn *pnt = NULL;
    // конструктор
    Cl_Btn(byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {};
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//-----------------class Cl_sys---------------------------
class Cl_sys {
    Cl_Servo_lock *Start_Servo = NULL;
    Cl_Btn *Start_Btn = NULL;
  public:
    Cl_sys() {}
    void Plug(Cl_Servo_lock * obj) {
      obj->pnt = Start_Servo;
      Start_Servo = obj;
    }
    void Plug(Cl_Btn * obj) {
      obj->pnt = Start_Btn;
      Start_Btn = obj;
    }
    void setup() {
      Start_Servo->setup();
      Start_Btn->setup();
    }
    void loop() {
      Start_Servo->loop();
      Start_Btn->loop();
    }
} Sys;
//--------------------------------------------
Cl_Servo_lock Servo(/*пин*/5);// подключить серву-замок
void Do_Btn_1() {
  Servo.ON1();
}
void Do_Btn_2() {
  Servo.ON2();
}
void Do_Btn_3() {
  Servo.Break();
}
Cl_Btn Btn_1(/*пин*/2,/*обработчик*/ Do_Btn_1); // подключить кнопку 1
Cl_Btn Btn_2(/*пин*/3,/*обработчик*/ Do_Btn_2); // подключить кнопку 2
Cl_Btn Btn_3(/*пин*/4,/*обработчик*/ Do_Btn_3); // подключить кнопку 3

void setup() {
  Sys.Plug(&Servo);

  Sys.Plug(&Btn_1);
  Sys.Plug(&Btn_2);
  Sys.Plug(&Btn_3);

  Sys.setup();
}
void loop() {
  Sys.loop();
}

 

BlackWizard
Offline
Зарегистрирован: 30.05.2017

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

О чем вы. Если вы такой дикий , то пользуйтесь каменными орудиями труда. А если вы не хотите диким , то учитесь. Вы наверное пользуетесь смартфонами и компьютерами. А ведь это сложные вещи. Даже если надо просто написать что-то или посмотреть фильм. Не я такой, это жизнь такая. И что бы сделать что-то простое  надо учится .  Здесь и пожилые люди приходят на форум. А ведь у них вроде скоро пенсия, но нифига прогресс догонит их раньше, чем пенсия. 

BlackWizard
Offline
Зарегистрирован: 30.05.2017

не нужно микроскопом гвозди забивать, если что-то можно сделать просто, оно должно быть простым, если будет необходимо, то нужно сделать сложно, вот и всё. Не надо плодить сущности сверх необходимого.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

BlackWizard пишет:

не нужно микроскопом гвозди забивать, если что-то можно сделать просто, оно должно быть простым, если будет необходимо, то нужно сделать сложно, вот и всё. Не надо плодить сущности сверх необходимого.

Вот вы опять несете хрень . УСТРОЙСТВО ДОЛЖНО БЫТЬ ПРОСТЫМ В ИСПОЛЬЗОВАНИИ, но само устройство может быть сложным, тем более все равно процесс копирования дешев, чем разработка. Сейчас эра массового производства, чем штучного. У меня мои программы влегкую работают совместно не мешая друг другу. У меня нет проблем совмещать разные компоненты моих программ. У меня даже на отладку программы уходит меньше времени из-за мнимой "по вашей точке зрения сложности".

/*Servo_lock.ino
  серва  -> 5 (servo_pin)

   RFID_RC522 RST -> 9 (RST_pin)
        SDA(SS)-> 10 (SDA_pin)
        MOSI   -> 11 (MOSI_pin)
        MISO   -> 12 (MISO_pin)
        SCK    -> 13 (SCK_pin)
        3,3В   -> 3,3В
        GND    -> GND
*/
//--------------------class Cl_Servo_lock------------------------
#include <Servo.h> // библиотека сервомотора
const byte angleOFF = 0;// угол закрытой сервы
const byte angleON = 90;// угол открытой сервы
const uint32_t lock_time = 2000; // максим время между 1 и 2  проверками
const uint32_t ON_time = 3000; //  время в которое серва будет в состоянии ON
class Cl_Servo_lock {
    byte pin;// нога
    Servo *myServo;// указатель на серву
    byte stat ; // состояние сервы 0 закрыта /1 первая проверка/ 2 открыта
    uint32_t past = 0;
  public:
    // указатель на следующий элемент
    Cl_Servo_lock *pnt;
    // конструктор
    Cl_Servo_lock(byte _pin): pin(_pin), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      myServo = new Servo;
      myServo->attach(pin);
      myServo->write(angleOFF);
      stat = 0;
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (stat == 1 && millis() - past > lock_time) stat = 0;
      if (stat == 2 && millis() - past > ON_time) {
        stat = 0;
        myServo->write(angleOFF);
      }
    }
    void ON1() {  // прошла 1 проверка
      past = millis();
      stat = 1;
    }
    void ON2() {
      if ((stat == 1) && (millis() - past <= lock_time)) { // если прошли проверку то открыть
        stat = 2;
        past = millis();
        myServo->write(angleON);
      }
    }
    void Break() {
      stat = 0;
    }
};
//--------------------class Cl_rfid------------------------
#include <SPI.h>
#include <MFRC522.h> // библиотека "RFID".
class Cl_rfid {
    byte SS_pin;
    byte RST_pin;
    MFRC522 *Device;// указатель на устройство
    void (*Do1)(), (*Do2)(), (*Do3)();
    uint32_t com1, com2;
    uint32_t past = 0;
  public:
    // указатель на следующий элемент
    Cl_rfid *pnt;
    // конструктор
    Cl_rfid(byte SS, byte RST, uint32_t _com1, void (*_Do1)(), uint32_t _com2, void (*_Do2)(), void (*_Do3)())
      : SS_pin(SS), RST_pin(RST), com1(_com1), Do1(_Do1), com2(_com2), Do2(_Do2), Do3(_Do3), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      SPI.begin();  //  инициализация SPI / Init SPI bus.
      Device = new MFRC522(SS_pin, RST_pin);
      Device->PCD_Init(); // инициализация MFRC522 / Init MFRC522 card.
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (millis() - past >= 100) {
        past = millis();
        if (Device->PICC_IsNewCardPresent() && Device->PICC_ReadCardSerial()) {
          uint32_t uidDec, uidDecTemp;
          for (byte i = 0; i < Device->uid.size; i++) {
            uidDecTemp = Device->uid.uidByte[i];
            uidDec = uidDec * 256 + uidDecTemp;
          }
          Serial.println("Card UID: ");
          Serial.println(uidDec); // Выводим UID метки в консоль.
          if (uidDec ==  com1) Do1();
          else if (uidDec ==  com2) Do2();
          else Do3();
        }
      }
    }
};
//-----------------class Cl_sys---------------------------
class Cl_sys {
    Cl_Servo_lock *Start_Servo = NULL;
    Cl_rfid *Start_rfid = NULL;
  public:
    Cl_sys() {}
    void Plug(Cl_Servo_lock * obj) {
      obj->pnt = Start_Servo;
      Start_Servo = obj;
    }
    void Plug(Cl_rfid * obj) {
      obj->pnt = Start_rfid;
      Start_rfid = obj;
    }
    void setup() {
      Start_Servo->setup();
      Start_rfid->setup();
    }
    void loop() {
      Start_Servo->loop();
      Start_rfid->loop();
    }
} Sys;
//--------------------------------------------
Cl_Servo_lock Servo(/*пин*/5);// подключить серву-замок

void Do_rfid1() {
  Servo.ON1();
}
void Do_rfid2() {
  Servo.ON2();
}
void Do_rfid3() {
  Servo.Break();
}
Cl_rfid rfid(/*SS_pin*/10,/*RST_pin*/9,
                       /*метка*/3491476559,/*обработчик*/ Do_rfid1,   //<-- тут вы впишете свои метки
                       /*метка*/4210874628,/*обработчик*/ Do_rfid2,   //<-- тут вы впишете свои метки
                       /* error_обработчик*/ Do_rfid3);      // подключить модуль
void setup() {
  Serial.begin(9600);
  Sys.Plug(&Servo);
  Sys.Plug(&rfid);

  Sys.setup();
}
void loop() {
  Sys.loop();
}

 

BlackWizard
Offline
Зарегистрирован: 30.05.2017

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Согласен. Но видишь ли, мы окружены вещами, которые простыми только кажутся. На вас обувь, штаны, рубашка,футболка. Что может быть проще. Ну да ,пошел, купил ,одел. Но если вы начнете ее шить. Хрен с ним,с горем попалам, пошили. Так вы это носить не будете. Все одеты с иголочки, только вы ,как пугало.  Еда. Что проще еды. Но если вы за ней пойдете в супермаркет, то вам придется напрягать мозг, что купить. Вдумайтесь . Что проще процесса покупки еды. Разумеется можно набрать всякой дряни, но зачем покупать дрянь и ей питатся, если питаться хочется получше и быть здоровее. Вернемся к нашей теме. В типичных скетчах Ардуины основная проблема. Скетчи работают замечательно, но каждый на свой Ардуине. А вот собираться в кучу и работать совместно у них получается не очень. Или хреново работают ,или человеку надо напрягать мозг ,как их собрать в кучу. Я решил эту проблему. И что в итоге. Компоненты надо писать самому. Да и программа остальным кажется охуительно сложной. Но она эта программа деревянная и с помощью нее легко программировать простые задачи. ПС: В последнем моем коде я могу в легкую прицепить еще 5 RFID устройств и еще 5 серв , и они все будут выполнять такие же задачи на одной Ардуине. При обычном подходе это не выйдет.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

qwone пишет:

А еще создаешь класс

Извините, что прерываю вашу научную беседу, но тема мне настолько интересна .... разрешите мне присесть ...

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

Самое интересное, что с классами код компактнее, чем простыней. Я говорю о коде, а не исходнике. Опять же вы знакомы с терминами: программирование сверху вниз и снизу вверх? 

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

qwone пишет:

Самое интересное, что с классами код компактнее, чем простыней. Я говорю о коде, а не исходнике.

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

Вот еще одна моя программа . Посылание импульса 1 сек по нажатию кнопки . Рабочая я проверял.

/*Cl_Led.ino
  светодиод ->13
  кнопка    ->2
*/

//--------------------class Cl_Led------------------------
// класс светодиода
class Cl_Led {
    byte pin; // нога для подключения светодиода
    bool inv; // 0 светодиод горит при 1/ 1 светодиод горит при 0
    bool stat_ON = 0, led = 0;
    uint32_t time = 500, past = 0;
  public:
    // указатель на следующий элемент
    Cl_Led *pnt;
    // конструктор
    Cl_Led(byte _pin, bool _inv): pin(_pin), inv(_inv), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      pinMode(pin, OUTPUT);// подключить светодиод
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (stat_ON && millis() - past >= time)OFF();
    }
    // включить светодиод
    void ON() {
      stat_ON = 0;
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // включить светодиод на время
    void ON( uint32_t _time) {
      time = _time;
      stat_ON = 1;
      past = millis();
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // выключить светодиод
    void OFF() {
      stat_ON = 0;
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }

};
//--------------------class Cl_Btn------------------------
// класс кнопки с 1 обработчиком кнопки
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // указатель на следующую
    Cl_Btn *pnt = NULL;
    // конструктор
    Cl_Btn(byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {};
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//-----------------class Cl_sys---------------------------
class Cl_sys {
    Cl_Led *Start_Led = NULL;
    Cl_Btn *Start_Btn = NULL;
  public:
    Cl_sys() {}
    void Plug(Cl_Led * obj) {
      obj->pnt = Start_Led;
      Start_Led = obj;
    }
    void Plug(Cl_Btn * obj) {
      obj->pnt = Start_Btn;
      Start_Btn = obj;
    }
    void setup() {
      Start_Led->setup();
      Start_Btn->setup();
    }
    void loop() {
      Start_Led->loop();
      Start_Btn->loop();
    }
} Sys;
//--------------------------------------------
Cl_Led Led(/*пин*/13,/*инверсия*/0);// подключить светодиод на ногу 13 / инверсия отключена
void Do_Btn() {
  const uint32_t time_1s = 1000;
  Led.ON(time_1s);// вкл на 1 секунду
}
Cl_Btn Btn(/*пин*/2,/*обработчик*/Do_Btn);// подключить кнопку на ногу 2

void setup() {
  Sys.Plug(&Led);

  Sys.Plug(&Btn);
  Sys.setup();
}
void loop() {
  Sys.loop();
}

А теперь покажу как обе программы собрать в кучу и они будут работать независимо друг от друга.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

А вот результат объединения. Я уверен что обе программы работают. Чем не облегчение труда программиста.

/*Komby.ino
  ---------------Программа 1---------------
  светодиод ->3
  кнопка    ->2
  --------------Программа 2---------------
    серва  -> 5 (servo_pin)

   RFID_RC522 RST -> 9 (RST_pin)
        SDA(SS)-> 10 (SDA_pin)
        MOSI   -> 11 (MOSI_pin)
        MISO   -> 12 (MISO_pin)
        SCK    -> 13 (SCK_pin)
        3,3В   -> 3,3В
        GND    -> GND
*/

//--------------------class Cl_Led------------------------
// класс светодиода
class Cl_Led {
    byte pin; // нога для подключения светодиода
    bool inv; // 0 светодиод горит при 1/ 1 светодиод горит при 0
    bool stat_ON = 0, led = 0;
    uint32_t time = 500, past = 0;
  public:
    // указатель на следующий элемент
    Cl_Led *pnt;
    // конструктор
    Cl_Led(byte _pin, bool _inv): pin(_pin), inv(_inv), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      pinMode(pin, OUTPUT);// подключить светодиод
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (stat_ON && millis() - past >= time)OFF();
    }
    // включить светодиод
    void ON() {
      stat_ON = 0;
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // включить светодиод на время
    void ON( uint32_t _time) {
      time = _time;
      stat_ON = 1;
      past = millis();
      led = 1;
      digitalWrite(pin, led ^ inv) ; // зажечь светодиод
    }
    // выключить светодиод
    void OFF() {
      stat_ON = 0;
      led = 0;
      digitalWrite(pin, led ^ inv) ; // погасить светодиод
    }

};
//--------------------class Cl_Btn------------------------
// класс кнопки с 1 обработчиком кнопки
class Cl_Btn {
    byte pin; // номер ноги на кнопке
    void (* Do)();// указатель на обработчик
    bool btn, btn_old;
    bool bounce = 0; // антидребезговый флаг
    uint32_t past = 0 ;
  public:
    // указатель на следующую
    Cl_Btn *pnt = NULL;
    // конструктор
    Cl_Btn(byte _pin, void (* _Do)()): pin(_pin), Do(_Do) {};
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      pinMode(pin, INPUT_PULLUP);// подключить кнопку 1 с подтяжкой
      btn = digitalRead(pin); // прочитать реальное значение на выводе};
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (! bounce && btn != digitalRead(pin)) { // если прошел фронт изм на выводн
        bounce = 1;                              // выставить флаг
        past = millis();                         // сделать временую засветку
      }
      else if ( bounce && millis() - past >= 5 ) { // если прошло антидребезговое время
        bounce = 0;                                // то снять флаг
        btn_old = btn ;
        btn = digitalRead(pin) ;                   // прочитать реальное значение на выводе
        if (btn_old && ! btn) Do();
      }
    }
};
//--------------------class Cl_Servo_lock------------------------
#include <Servo.h> // библиотека сервомотора
const byte angleOFF = 0;// угол закрытой сервы
const byte angleON = 90;// угол открытой сервы
const uint32_t lock_time = 2000; // максим время между 1 и 2  проверками
const uint32_t ON_time = 3000; //  время в которое серва будет в состоянии ON
class Cl_Servo_lock {
    byte pin;// нога
    Servo *myServo;// указатель на серву
    byte stat ; // состояние сервы 0 закрыта /1 первая проверка/ 2 открыта
    uint32_t past = 0;
  public:
    // указатель на следующий элемент
    Cl_Servo_lock *pnt;
    // конструктор
    Cl_Servo_lock(byte _pin): pin(_pin), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      myServo = new Servo;
      myServo->attach(pin);
      myServo->write(angleOFF);
      stat = 0;
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (stat == 1 && millis() - past > lock_time) stat = 0;
      if (stat == 2 && millis() - past > ON_time) {
        stat = 0;
        myServo->write(angleOFF);
      }
    }
    void ON1() {  // прошла 1 проверка
      past = millis();
      stat = 1;
    }
    void ON2() {
      if ((stat == 1) && (millis() - past <= lock_time)) { // если прошли проверку то открыть
        stat = 2;
        past = millis();
        myServo->write(angleON);
      }
    }
    void Break() {
      stat = 0;
    }
};
//--------------------class Cl_rfid------------------------
#include <SPI.h>
#include <MFRC522.h> // библиотека "RFID".
class Cl_rfid {
    byte SS_pin;
    byte RST_pin;
    MFRC522 *Device;// указатель на устройство
    void (*Do1)(), (*Do2)(), (*Do3)();
    uint32_t com1, com2;
    uint32_t past = 0;
  public:
    // указатель на следующий элемент
    Cl_rfid *pnt;
    // конструктор
    Cl_rfid(byte SS, byte RST, uint32_t _com1, void (*_Do1)(), uint32_t _com2, void (*_Do2)(), void (*_Do3)())
      : SS_pin(SS), RST_pin(RST), com1(_com1), Do1(_Do1), com2(_com2), Do2(_Do2), Do3(_Do3), pnt(NULL) {}
    // setup()
    void setup() {
      if (this->pnt != NULL) this->pnt->setup();
      SPI.begin();  //  инициализация SPI / Init SPI bus.
      Device = new MFRC522(SS_pin, RST_pin);
      Device->PCD_Init(); // инициализация MFRC522 / Init MFRC522 card.
    }
    // loop()
    void loop() {
      if (this->pnt != NULL) this->pnt->loop();
      if (millis() - past >= 100) {
        past = millis();
        if (Device->PICC_IsNewCardPresent() && Device->PICC_ReadCardSerial()) {
          uint32_t uidDec, uidDecTemp;
          for (byte i = 0; i < Device->uid.size; i++) {
            uidDecTemp = Device->uid.uidByte[i];
            uidDec = uidDec * 256 + uidDecTemp;
          }
          Serial.println("Card UID: ");
          Serial.println(uidDec); // Выводим UID метки в консоль.
          if (uidDec ==  com1) Do1();
          else if (uidDec ==  com2) Do2();
          else Do3();
        }
      }
    }
};
//-----------------class Cl_sys---------------------------
class Cl_sys {
    Cl_Led *Start_Led = NULL;
    Cl_Btn *Start_Btn = NULL;
    Cl_Servo_lock *Start_Servo = NULL;
    Cl_rfid *Start_rfid = NULL;
  public:
    Cl_sys() {}
    void Plug(Cl_Servo_lock * obj) {
      obj->pnt = Start_Servo;
      Start_Servo = obj;
    }
    void Plug(Cl_rfid * obj) {
      obj->pnt = Start_rfid;
      Start_rfid = obj;
    }
    void Plug(Cl_Led * obj) {
      obj->pnt = Start_Led;
      Start_Led = obj;
    }
    void Plug(Cl_Btn * obj) {
      obj->pnt = Start_Btn;
      Start_Btn = obj;
    }
    void setup() {
      Start_Led->setup();
      Start_Btn->setup();
      Start_Servo->setup();
      Start_rfid->setup();
    }
    void loop() {
      Start_Led->loop();
      Start_Btn->loop();
      Start_Servo->loop();
      Start_rfid->loop();
    }
} Sys;
//--------------------------------------------
Cl_Led Led(/*пин*/3,/*инверсия*/0);// подключить светодиод на ногу 13 / инверсия отключена
void Do_Btn() {
  const uint32_t time_1s = 1000;
  Led.ON(time_1s);// вкл на 1 секунду
}
Cl_Btn Btn(/*пин*/2,/*обработчик*/Do_Btn);// подключить кнопку на ногу 2
Cl_Servo_lock Servo(/*пин*/5);// подключить серву-замок

void Do_rfid1() {
  Servo.ON1();
}
void Do_rfid2() {
  Servo.ON2();
}
void Do_rfid3() {
  Servo.Break();
}
Cl_rfid rfid(/*SS_pin*/10,/*RST_pin*/9,
                       /*метка*/3491476559,/*обработчик*/ Do_rfid1,   //<-- тут вы впишете свои метки
                       /*метка*/4210874628,/*обработчик*/ Do_rfid2,   //<-- тут вы впишете свои метки
                       /* error_обработчик*/ Do_rfid3);      // подключить модуль

void setup() {
  Serial.begin(9600);
  Sys.Plug(&Servo);
  Sys.Plug(&rfid);

  Sys.Plug(&Led);

  Sys.Plug(&Btn);
  Sys.setup();
}
void loop() {
  Sys.loop();
}

 

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

qwone пишет:

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

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну извините , за мной нет отработаной школы. Приходится самому разбираться ,что "опасно", что "безопасно", а что "банальные устоявшие заблуждения".

ПС:http://document.saraff.ru/

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

qwone пишет:

http://document.saraff.ru/

Интересно, сей документ во всех ипостасях применим к программированию ардуино или нет?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

ulis пишет:

Интересно, сей документ во всех ипостасях применим к программированию ардуино или нет?

Этот документ применим к Си и к С++. И разумеется к Ардуине. Но разработчики среды Ардуино , немного внесли косяков в Си среды. Да и процессор построен по Гарварской системе, чем по Неймановской, так что надо учитывать и это. По крайней мере конкретно по среде Ардуино аналогов подобного документа нет. Но руководстваться можно этим.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

qwone пишет:

И разумеется к Ардуине. Но разработчики среды Ардуино , немного внесли косяков в Си среды.

Спасибо

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

BlackWizard пишет:

логика работы программы видится мне следующим образом: 

ожидание метки-> метка1-> запуск таймера, увеличение счётчика на 1, если нет то счётчик=0-> метка2-> если счётчик =1 и таймер<10сек ->увеличение счётчика на 1, если нет то счётчик=0->метка3-> если счётчик =2 и таймер<10сек ->увеличение счётчика на 1, если нет то счётчик=0->если счётчик=3, открытие мотора-> закрытие мотора, счётчик=0

Ну, вот что-то подобное я и предполагал. У Вас каша в голове, потому Вы и не можете написать программу, поскольку запрограммировать кашу - это высшая лига в программировании, Вам рано :)

Если хотите, я могу Вас пошагово довести от того, что Вы тут написали до такой записи, которая сама Вам даст собственно и программу, и навык на будущее - как это делается. Но при этом Вы должны делать то, что я скажу шаг за шагом, не считать. что что-то и так понятно - можно пропустить (как Вы сначала поступили с росписью на бумаге). Вы будете так работать? Просто, если не хотите и делать не будете, я не буду время тратить.

BlackWizard
Offline
Зарегистрирован: 30.05.2017

ЕвгенийП пишет:

Ну, вот что-то подобное я и предполагал. У Вас каша в голове, потому Вы и не можете написать программу, поскольку запрограммировать кашу - это высшая лига в программировании, Вам рано :)

Если хотите, я могу Вас пошагово довести от того, что Вы тут написали до такой записи, которая сама Вам даст собственно и программу, и навык на будущее - как это делается. Но при этом Вы должны делать то, что я скажу шаг за шагом, не считать. что что-то и так понятно - можно пропустить (как Вы сначала поступили с росписью на бумаге). Вы будете так работать? Просто, если не хотите и делать не будете, я не буду время тратить.

Давайте попробуем