Задержка по прерыванию. Помощь в создании простого реле на Arduino Nano

Тема в разделе "Arduino & Shields", создана пользователем Bortnik27, 23 июн 2019.

  1. Bortnik27

    Bortnik27 Нуб

    Друзья, простая задача и что-то ступор.
    Надо по прерыванию включать мосфет (пока это просто встроенный led), и держать его включенным Нное количество секунд.
    Код (C++):
    #define msft 13
    #define intpin 2
    volatile boolean flag = false;
    unsigned long timer = 2000;
    unsigned long crntt = 0;
    void setup() {
      attachInterrupt(digitalPinToInterrupt(intpin), get_in, FALLING);
    }

    void loop() {
      if (flag)  digitalWrite (msft, HIGH);
      if (millis()- crntt > timer){
      digitalWrite (msft, LOW);
      crntt = millis();
      flag = false;
      }

    }

    void get_in(){
        flag = !flag;
    }
    Идея такая, прерывание дергает флаг в положение вкл. В loop проверяем состояние флага, если вкл, то горит диод, пока таймер не переполнится, если переполняется то выкл.
    Проблема: Сейчас при срабатывании прерывания диод загорается и не гаснет пока ногу привязанную к прерываниям не замкнуть на землю. Но если ее замкнуть сразу же, то таймер отрабатывает и гаснет через заданное кол-во секунд. По идее такого быть не должно, когда таймер сбрасывается, должно сбрасываться и положение флага, а с ним и гаснуть диод, что я делаю не так? Если прерывания поставить на HIGH ситуация такая же. Может я прерывания както не правильно трактую. Arduino nano
     
  2. Asper Daffy

    Asper Daffy Иксперд

    Блин, да чего ж тут номеров строк нет!

    В первом if в loop нужно ещё запомнить время включения (присвоить значение crntt )

    во втором if надо проверять не только истечение времени а ещё и то, что флаг включён.

    Должно заработать.
     
    SergeiL и Daniil нравится это.
  3. Bortnik27

    Bortnik27 Нуб

    Код (C++):
    #define msft 13
    #define intpin 2
    volatile boolean flag = false;
    unsigned long timer = 2000;
    unsigned long crntt = 0;
    void setup() {
      attachInterrupt(digitalPinToInterrupt(intpin), get_in, FALLING);
    }

    void loop() {
      if (flag){
      digitalWrite (msft, HIGH);
      crntt = millis();
    }
      if (((long)millis()- crntt > timer) & flag){
      digitalWrite (msft, LOW);
      crntt = millis();
      flag = false;
      }
    }
    void get_in(){
        flag = !flag;
        }
     
    Если ставить номера строк из редактора форума, он ставит звездочки вместо цифр, а из arduino ide не копируются номера строк. Не получилось. Срабатывает один раз и вечно горит. А если загружать с разомкнутыми ногами то через две секунды загорается, т.е. эффект обратный.
     
    Последнее редактирование: 23 июн 2019
  4. Asper Daffy

    Asper Daffy Иксперд

    1. сконфигурируйте пин мосфета на OUTPUT! Кто за Вас это делать будет?

    2. (некритично, но для порядка) строчку "if(((long)millis()- crntt > timer)& flag)" напишите нормально
    if((millis()- crntt > timer) && flag)
     
    SergeiL нравится это.
  5. parovoZZ

    parovoZZ Гуру

    Что-то вы все мудрите по жесткому. Достаточно пин с мосфетом привязать к компаратору таймера, а таймер запустить в прерывании. И не надо заставлять проц делать ту работу, которую за него прекрасно сделает периферия.
     
  6. Onkel

    Onkel Гуру

    Не к компаратору, к выходу. Компаратор- это вход. Но имхо если ТС забывает сконфигурировать пины, то сконфигурировать таймер....А так конечно Вы правы - я бы так и сделал.
     
  7. Bortnik27

    Bortnik27 Нуб

    Согласен, очевидное забыл, и если честно не совсем понимаю, что дает в данном случае pinMode OUTPUT, так как это не помогло.
    Если подскажете что значит привязать пин мосфета к компаратору или к таймеру, буду крайне признателен. По моему задача совсем тривиальная под attiny13 задумывалась, но что-то оказывается я еще не так хорош в программировании как хотелось бы))
     
  8. Bortnik27

    Bortnik27 Нуб

    Код (C++):
    #define msft 13
    #define intpin 2
    volatile boolean flag = false;
    unsigned long timer = 2000;
    unsigned long crntt = 0;
    void setup() {
      attachInterrupt(digitalPinToInterrupt(intpin), get_in, FALLING);
      pinMode(msft,OUTPUT);
    }

    void loop() {
      if (flag){
      digitalWrite (msft, HIGH);
      crntt = millis();
    }
      if((millis()- crntt > timer) && flag){
      digitalWrite (msft, LOW);
      crntt = millis();
      flag = false;
      }
    }
    void get_in(){
        flag = !flag;
        }
    После срабатывания горит без остановки.
     
  9. Asper Daffy

    Asper Daffy Иксперд

    Ой, мля, ещё одно условие.

    Ты же в первом if всегда заходишь и снова заводишь таймер!

    Поэтому в первом if сбрасывай флаг сразу!

    А во втором if, вместо проверки flag (вместо этого слова) проверяй включён ли мосфет, т.е. пиши digitalRead(msft) == HIGH

    И ещё, у тебя второй пин к питанию подтянут? Если нет, то вставь в сетап pinMode(2, INPUT_PULLUP);
     
  10. Bortnik27

    Bortnik27 Нуб

    Код (C++):
    #define msft 13
    #define intpin 2
    volatile boolean flag = false;
    unsigned long timer = 2000;
    unsigned long crntt = 0;
    void setup() {
      attachInterrupt(digitalPinToInterrupt(intpin), get_in, FALLING);
      pinMode(msft,OUTPUT);
      pinMode(intpin,INPUT_PULLUP);
    }

    void loop() {
      if (flag){
      digitalWrite (msft, HIGH);
      crntt = millis();
      flag = !flag;
    }
      if((millis()- crntt > timer) && (digitalRead(msft) == HIGH)){
      digitalWrite (msft, LOW);
      crntt = millis();
      flag = false;
      }
    }
    void get_in(){
        flag = !flag;
        }
    Все хорошо, но срабатывает не на FALLING а на CHANGE, поставил в interrupt HIGH, та же фигня, при смене состояния пина 2 загорается мосфет.
    Попробовал поставить в прерывание flag = true, все равно на состояние LOW все равно загорается.
     
  11. Bortnik27

    Bortnik27 Нуб

    Код (C++):
    #define msft A2
    #define intpin 2
    volatile boolean flag = false;
    unsigned long timer = 2000;
    unsigned long on = 0;
    unsigned long crntt = 0;
    void setup() {
      attachInterrupt(0, get_in, FALLING);
      pinMode(msft,OUTPUT);
      pinMode(intpin,INPUT_PULLUP);
    }

    void loop() {
      if (flag){
      digitalWrite (msft, HIGH);
      on = millis();
    }
      if((millis()- on > timer)){
      digitalWrite (msft, LOW);
      flag = false;
      }
    }
    void get_in(){
        flag = true;
        }
    Если прошить данный код и запустить аруино, через две секунды зажигается "мосфет", т.е. по факту ничего не взводит флаг, но ардуино как то получает digitalWrite (msft, HIGH); - это же бред
     
  12. Onkel

    Onkel Гуру

    У каждого таймера (всего их 3) есть два выходных пина, которые управляются своими таймерами. По приходу импульса внешнего прерывания вы в функции прерывания запускаете таймер и выставляете ему режим сработки по значению счетчика таймера. Вот тут можно почитать https://habr.com/ru/post/337430/
     
  13. Bortnik27

    Bortnik27 Нуб

    т.е. можно по прерыванию заставить работать функцию подвязанную на прерывание на определенное время? Блин, но это отдельная библиотека на такую простенькую задачу? Просто прерывания хотел использовать чтобы потом загонять в сон и пробуждать, и в последствии думал перенести все на attiny13A
     
  14. b707

    b707 Гуру

    Вам уже на двух форумах обьяснили, как решить вашу простенькую задачу. Чем вы замыкаете пин на массу? Кнопкой? Про антидребез помните?
     
    Последнее редактирование: 24 июн 2019
    SergeiL нравится это.
  15. Bortnik27

    Bortnik27 Нуб

    А чего же про недостаток мозгов удалили?
    Вот "объяснение, как решить мою простенькую задачу"
    Код (C++):
    #define msft 13
    #define intpin 2
    volatile boolean flag = false;
    unsigned long timer = 2000;
    unsigned long crntt = 0;
    void setup() {
      attachInterrupt(digitalPinToInterrupt(intpin), get_in, FALLING);
      pinMode(msft,OUTPUT);
      pinMode(intpin,INPUT_PULLUP);
    }

    void loop() {
      if (flag){
      digitalWrite (msft, HIGH);
      crntt = millis();
      flag = !flag;
    }
      if((millis()- crntt > timer) && (digitalRead(msft) == HIGH)){
      digitalWrite (msft, LOW);
      crntt = millis();
      flag = false;
      }
    }
    void get_in(){
        flag = !flag;
        }
    Проблема не в дребезге, пробле все в том же что и была в моем первом посте, прерывание должно срабатывать на FALLING, а диод загорается каждое изменение состояния контакта. Т.е. и на LOW и на HIGH, дребезг тут не при чем. То что в коде выше, работает лучше чем мой код, но все равно нужно срабатывание только на "открытие двери" т.е. срабатывание геркона, дребезга там нет.
     
  16. parovoZZ

    parovoZZ Гуру

    такое умеют только два пина в МК AVR - INT0 и INT1. Остальные пины тоже умеют прерывание, но не различают фронты, т.к. тупо асинхронные.

    На механических контактах дребезг есть ВСЕГДА. Поэтому не удивительно, что код работает так, как ему сулят законы физики, а не хотелки кодописателя.
     
  17. b707

    b707 Гуру

    ну как же непричем-то? При дребезге именно так и будет - срабатывать при любом изменении, потому что при дребезге при любом изменении есть и FALLING и RISING
    с чего вы взяли, что у геркона нет дребезга?
     
  18. parovoZZ

    parovoZZ Гуру

    можно

    библиотека вместо пары строчек конфигурации? Ну не знаю...
     
  19. parovoZZ

    parovoZZ Гуру

    с этим кодом не получится ровным счетом НИЧЕГО. Его надо уже сейчас писать по-другому в обнимку с книгой Евстифеева. Для плавного старта читай мои темы. Я помешан на микроамперах и батарейном питании. Поэтому тему изучил и вдоль и поперек.
     
  20. b707

    b707 Гуру

    можно, только проблему ребезга это не решит