Две кнопки с фиксацией

Тема в разделе "Arduino & Shields", создана пользователем gonzales, 9 авг 2017.

  1. gonzales

    gonzales Нерд

    прошу сильно не пинать, понимаю, что вопрос ламерский)))
    Есть двойной переключатель (каким нормальный люди свет включают). Хочу привязать его к ардуино. Схема в аттаче.
    S1, S2 - кнопки с фиксацией, резисторы по науке, подтяжка на землю.
    Получаю следующую картину. Пока S1 разомкнут, переключаю S2 - все замечательно. Но стоит замкнуть S1 и переключать S2, отрабатывает как бог пошлет. Соответственно наоборот тоже самое, пока S2 разомкнут можно щелкать S1, все работает, стоит S2 замкнуть и абзац.
    Что интересно, эта схема работает при классической обработке кнопки
    Код (C++):
    void CheckSwitch1() {

      State = digitalRead(Pin_D);

      if (sob > 0) {
        if (millis() - CurrentMillis > 100) {
          if (sob == 1 && State == HIGH && PreviosState != State) {
           PreviosState = State;
            //обработка нажатия
          }
          else if (sob == 2 && State == LOW && PreviosState != State) {
            PreviosState = State;
            //обработка нажатия
          }
          sob = 0;
        }

      }
      else {
        if (State == HIGH && PreviosState != State) {
          sob = 1;
          CurrentMillis = millis();
        }
        else if (State == LOW && PreviosState != State) {
          sob = 2;
          CurrentMillis = millis();
        }
      }
    }
    void loop(){
    CheckSwitch1();
    }
     
    Но я переделал скеч на работу по прерываниям, и получаю вот такую неприятность.
    Вот код работы по прерыванию

    Код (C++):
    #include "PinChangeInterrupt.h"
    setup(){
    attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Pin_D), CheckSwitch, CHANGE);
    }

    void CheckSwitch() {
      disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(Pin_D));
      State = digitalRead(Pin_D);

      if (State == HIGH && PreviosState != State) {
        PreviosState = State;
        //обработка нажатия
      }
      else if (State == LOW && PreviosState != State) {
        PreviosState = State;
       //обработка нажатия
      }
      enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(Pin_D));
    }
     

    Что подскажете? Может использовать подтяжку к питанию? Видел схему с резистивным делителем напряжения, конечно вариант, но хотелось бы понять, почему такой вариант не работает.
    Заранее всем спасибо за ответы!
     

    Вложения:

    Последнее редактирование: 9 авг 2017
  2. Vladimir71

    Vladimir71 Нерд

    Наверно программа не правильно обрабатывает.
     
  3. b707

    b707 Гик

    покажите скетч.
    и, по поводу схемы - кнопки лучше к пинам через резистор в несколько сот Ом подключить
     
  4. gonzales

    gonzales Нерд

    о, уже ответы. я дописал топик, не думал, что так быстро ответят. Скетчи там
     
  5. b707

    b707 Гик

    в скетчах только один пин, а где код для второго?
     
  6. gonzales

    gonzales Нерд

    такой же код для второй кнопки. В скетче они обрабатываются разными функциями. Меняется только пин и обработчик нажатия
     
  7. b707

    b707 Гик

    какие точно номера пинов и какая ардуина?
     
  8. gonzales

    gonzales Нерд

    Pro mini. Порты D5 и D6
     
  9. gonzales

    gonzales Нерд

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

    b707 Гик

    на пинах 5 и 6 прерывание общее, выберите один пин из диапазона 0-7, а второй 8-13
     
  11. gonzales

    gonzales Нерд

    я использую библиотеку PinChangeInterrupt.h, она позволяет повесить прерывания на все пины.
    https://github.com/NicoHood/PinChangeInterrupt
    Что характерно, я повесил 2 звонковые кнопки на эти же пины, все отлично работает. Проблема именно с тем, что одна кнопка замкнута, и при замыкании второй срабатывает прерывание на первой, как будто на ней тоже меняется фронт
     
  12. b707

    b707 Гик

    Прерывание на все пины D0-D7 одно и то же, когда оно срабатывает - библиотека определяет, какой из пинов замкнут на ноль. Поскольку одна кнопка у вас нажата всегда. то вторая кнопка вообще не обрабатывается.

    Чтобы эти кнопки работали независимо - подключите их на разные прерывания. И таких прерываний только три, хотя пинов много.
     
    Tomasina нравится это.
  13. b707

    b707 Гик

    И, кстати, есть мнение, что тратить прерывания на кнопки - это расточительство, ибо приемлимая скорость реакции легко достигается и стандартными средствами...
     
  14. gonzales

    gonzales Нерд

    это многое объясняет. спасибо! сейчас попробую.
    у меня высоконагруженный проект, в лупе крутится масса всего, включая обмен данными, хотелось разгрузить его, повесив все добро (кнопки, датчики и тд) на прерывания. Если есть другой вариант, с удовольствием рассмотрю
     
  15. gonzales

    gonzales Нерд

    не помогло(((
    перевесил на D9, эффект тот же самый
     
  16. b707

    b707 Гик

    должно было заработать. Приведите полный код, все-таки
     
  17. gonzales

    gonzales Нерд

    Весь код не получится)))
    примерно вот так
    Код (C++):
    #include "PinChangeInterrupt.h"
    #define BOARD1_D 9        //пин ардуино
    #define BOARD2_D 6        //пин ардуино
    #define BOARD3_D 5        //пин ардуино
    struct TBoard {
      Types Type_ID = TYPE_NO;
      SA SA_ID = SA_NO;
      byte Adress;
      byte Pin_D;
      byte Pin_A;
      struct TLink Link;
      struct TValues Values;
      Func Func_ID = FUNC_NO;
      byte PreviosState = 255;
      byte State = 255;
      byte sob = 0;
      unsigned long CurrentMillis;
    };
    struct TBoard Board[3];

    void setup() {
      Board[0].Pin_D = BOARD1_D;
      Board[1].Pin_D = BOARD2_D;
      Board[2].Pin_D = BOARD3_D;
    SetBoardButton(0);
    SetBoardButton(2);
    }

    void SetBoardButton(byte BoardNum) {
      //кнопка
      Board[BoardNum].SA_ID = SENSOR;
      Board[BoardNum].Adress = BoardNum;
      pinMode(Board[BoardNum].Pin_D, INPUT);
      switch (BoardNum) {
        case 0:
          detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D));
          attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D), detect_button0, CHANGE);
          break;
        case 1:
          detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D));
          attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D), detect_button1, CHANGE);
          break;
        case 2:
          detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D));
          attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D), detect_button2, CHANGE);
          break;
      }
    }
    void detect_switch0() {
      CheckSwitch(0);
    }
    void detect_switch1() {
      CheckSwitch(1);
    }
    void detect_switch2() {
      CheckSwitch(2);
    }

    void CheckSwitch(byte BoardNum) {
      disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D));
      Board[BoardNum].State = byte(digitalRead(Board[BoardNum].Pin_D));

      if (Board[BoardNum].State == HIGH && Board[BoardNum].PreviosState != Board[BoardNum].State) {
        Board[BoardNum].PreviosState = Board[BoardNum].State;
        SendBoardInfo(1, 0, BoardNum);
        if (Board[BoardNum].Link.Link_Type == 1) {
          CheckFunctions(BoardNum);
        }
      }
      else if (Board[BoardNum].State == LOW && Board[BoardNum].PreviosState != Board[BoardNum].State) {
        Board[BoardNum].PreviosState = Board[BoardNum].State;
        SendBoardInfo(1, 0, BoardNum);
        if (Board[BoardNum].Link.Link_Type == 1) {
          CheckFunctions(BoardNum);
        }
      }

      enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(Board[BoardNum].Pin_D));
    }
     
  18. b707

    b707 Гик

    какого-то откровенного криминала в этом куске кода я не нашел. Из соображений - операция digitalRead() довольно медленная и не вполне верно выполнять ее в прерывании, правильно было бы выставлять флаг об изменении и проверять сигнал на пине в основной программе.

    Из замечаний "не по делу"
    - код всех трех меток switch в SetBoardButton абсолютно идентичен, метки вполне можно было бы объединить. Да и сам switch там вообще не нужен,

    - в процедуре CheckSwitch обе ветки - "if" и "else if" содержат один и тот же код, вполне можно было бы обойтись одной. Кстати. то что у вас реакция на включение и на выключение кнопок одна и та же - это не ошибка, так задумано?
     
  19. gonzales

    gonzales Нерд

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

    По существу, так и не ясно почему такая реакция. У меня есть одно объяснение, оно ламерское, но по моему выглядит так: при замкнутой одной кнопки, в момент замыкания второй происходит изменение потенциала на первой кнопке (электронщики сейчас меня бы закидали какахами)))), что в свою очередь отлавливает библиотека.
     
  20. b707

    b707 Гик

    Да, действительно, просмотрел. Кстати, в приведенном коде функций detect_buttonX (x = 0,1,2) - нет, зато есть соответствующие функции detect_switchX - так и надо?


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