Проблемы в управление массивом кнопок

Тема в разделе "Arduino & Shields", создана пользователем dangear, 26 апр 2015.

  1. dangear

    dangear Нуб

    Всем привет! Столкнулся с проблемой: создал массив из 5 кнопок и 5 лампочек, отслеживаю их нажатие и нужно сделать так, чтобы сценарий при нажатии отыгрывался только один раз. Всю ночь вчера просидел и так не разобрался. Как организовать отслеживание нажатия одной кнопки я разобрался, но как это сделать с массивом - пока не понял. Подскажите кто что сможет:
    PHP:
    #include <MIDI.h>

    // Simple tutorial on how to receive and send MIDI messages.
    // Here, when receiving any message on channel 4, the Arduino
    // will blink a led and play back a note for 1 second.

    MIDI_CREATE_DEFAULT_INSTANCE();

    const int ledPin =  13;  // Pin для встроенного диода

    const int myPins[] = {2, 3, 4, 5, 6}; //Массив пинов кнопок
    const int myNote[] = {76, 77, 78, 79, 80}; //Массив передаваемых данных
    const int myLed[] = {8, 9, 10, 11, 12}; // Массив светодиодов для реакции на нажатие

    int buttonState = 0;        //  Переменная состояния нажатия

    void setup()
    {
        pinMode(ledPin, OUTPUT);
        MIDI.begin(10);          // Запускаем библиотеку MIDI  на 10 канале
        Serial.begin(115200);
        for(int i=0;i<5;i++) { // Определяем пины кнопок как входящие данные
          pinMode(myPins[i], INPUT_PULLUP);
        }
        for(int i=0;i<5;i++) { // определяем пины светодиодов на исходящие данные
          pinMode(myLed[i], OUTPUT);
        }
    }

    void loop()
    {

    for(int i=0;i<5;i++) { // бегам по кнопкам
        buttonState = digitalRead(myPins[i]);  // проверяем их состояние
     
        if (buttonState == LOW) { // если нажата, то выполняем сценарий
                MIDI.sendNoteOn(myNote[i],127,1); //отправляем ноту из массива myNote[], соответствующую кнопке
                digitalWrite(ledPin, HIGH); //Мигаем 13м пином
                digitalWrite(myLed[i], HIGH); // Включаем светодиот из массива myLed[], соответствующий нажатой кнопке
        }
    }
    }
    Сейчас код отправляет выполняет сценарий до тех пор, пока зажата кнопка, а хотелось бы сделать следующий алгоритм: нажимаем и держим кнопку, загорается соответствующая ей лампочка, выполняется сценарий один раз, лампочка продолжает гореть до тех пор, пока не отпустим кнопку. И так со всем массивом кнопок! Жду любых предложений!
     
  2. geher

    geher Гуру

    Надо просто сохранять состояние кнопки, и запускать сценарий только по изменению этого состояния в сторону нажатия.
    Получается римерно так (код не проверялся, работа после копипаста не гарантируется):
    Код (Text):

    //В начале
    int buttonStates[5]={HIGH,HIGH,HIGH,HIGH,HIGH};
    int pin13Time=0;
    ...

    void loop()
    {
        for(int i=0;i<5;i++) { // бегам по кнопкам
           buttonState = digitalRead(myPins[i]);  // проверяем их состояние
           if (buttonState!=buttonStates[i]) // если состояние изменилось
              if (buttonState == LOW) { // если нажата, то выполняем сценарий
                  MIDI.sendNoteOn(myNote[i],127,1); //отправляем ноту из массива myNote[], соответствующую кнопке
                  digitalWrite(ledPin, HIGH); //Мигаем 13м пином
                  pin13Time=millis(); // запоминаем, когда мигнули
                  digitalWrite(myLed[i], HIGH); // Включаем светодиод из массива myLed[], соответствующий нажатой кнопке
              }
              else // кнопка отпущена
              {
                  digitalWrite(myLed[i], LOW); // Выключаем светодиод из массива myLed[], соответствующий нажатой кнопке
               }
               buttonState=buttonStates[i]; // Сохраняем изменившееся значение
           }
        }
       if (millis()-pin13Time>500) // если 13-м мигнули больше полусекунды назад, то пора и загасить
       {
              digitalWrite(ledPin, HIGH); //Гасим 13-й
       }
    }
     
     
  3. dangear

    dangear Нуб

    Благодарю, но, к сожалению, не работает. Лампочка загарается и залипает в таком состоянии и после отжатия кнопки, а данные MIDI.sendNoteOn(myNote,127,1); так же сыпятся в порт многочисленно. Скрипт, который я привел в топике, рабочий, но там проблема в том, что при зажатой клавише он сыпет MIDI.sendNoteOn(myNote,127,1); без остановки, а хотелось бы, чтобы это происходило один раз. Вот именно над этой проблемой и борюсь. Думаю ввести переменную именно для отслеживания отправки MIDI.sendNoteOn(myNote,127,1); и если отправка происходит один раз, то потом мы эту строку игнорируем и продолжаем светит лампочкой до того момента, когда отпустится кнопка. Могли бы Вы подсказать свое видение ситуации, иначе мое уже иссякает) В любом случае благодарен Вам за отзыв.
     
  4. dangear

    dangear Нуб

    Мне кажется, что проблема в цикле:
    PHP:
    for(int i=0;i<5;i++) {

    }
    Т.к. код для одной кнопки отрабатывается как нужно:
    PHP:
    #include <MIDI.h>

    // Simple tutorial on how to receive and send MIDI messages.
    // Here, when receiving any message on channel 4, the Arduino
    // will blink a led and play back a note for 1 second.

    MIDI_CREATE_DEFAULT_INSTANCE();

    const int ledPin =  13;  // Pin для встроенного диода
    const int buttonPin = 2; // Pin кнопки
    const int myLed = 8; // Pin контрольной лампы
    const int myNote = 76; // Pin кнопки

    int buttonState = 0; //Переменная состояния нажатия
    int lastButtonState = 0;    //Последнее состояние нажатия

    void setup()
    {
        MIDI.begin(10); //Запускаем библиотеку MIDI  на 10 канале
        Serial.begin(115200);
        pinMode(ledPin, OUTPUT); //13 Pin на выход
        pinMode(buttonPin, INPUT_PULLUP); //Копка с подтягивающим резистором на вход
        pinMode(myLed, OUTPUT); //Контрольная лампа на выход
    }

    void loop()
    {
      buttonState = digitalRead(buttonPin); //Определяем состояние
      if (buttonState != lastButtonState) {
        if (buttonState == LOW) { //если нажата
          digitalWrite(ledPin, HIGH); //Включаем светодиод на 13 Pin
          digitalWrite(myLed, HIGH); //Включаем контрольную лампу
          MIDI.sendNoteOn(myNote,127,1); //Отправляем данные
        }
        else {  // кнопка отпущена
          digitalWrite(myLed, LOW); //Выключаем контрольный светодиод
          digitalWrite(ledPin, LOW); //Выключаем светодиод на 13 Pin
        }
      }
      lastButtonState = buttonState; //Запоминаем последнее состояние
    }
    Но стоит загнать это все в перебор массива кнопок for(int i=0;i<5;i++) {} как тут же все сыпется.
    Может есть альтернатива отслеживания нажатия кнопок из массива?
     
  5. 9xA59kK

    9xA59kK Гик

    Попробуй библиотеку(описание),ссылка на саму библиотеку,в ней есть три примера использования , тебе надо change .
    Поиграйся со всеми, увидишь разницу. Спрашивай, если что будет не понятно- что смогу объясню.

    Из примера:
    Код (Text):
    #include <Bounce.h>

    #define BUTTON 2      // пин на которой кнопка

    #define LED 13




    int ledValue = LOW;




    // This example changes the state of the LED everytime the button is pushed

    // Build the circuit indicated here: http://arduino.cc/en/Tutorial/Button







    Bounce bouncer = Bounce( BUTTON, 5 );   // антидребезг




    void setup() {

      pinMode(BUTTON,INPUT);

      pinMode(LED,OUTPUT);

    }




    void loop() {




      if ( bouncer.update() ) {

      if ( bouncer.read() == HIGH) {  // если кнопка нажата

      if ( ledValue == LOW ) {    // то, если было выключено

      ledValue = HIGH;              // включаем

      } else {                              

      ledValue = LOW;                // иначе выключаем

      }

      digitalWrite(LED,ledValue);

      }

      }

    }
     
    Последнее редактирование: 26 апр 2015
  6. DrProg

    DrProg Вечный нерд

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

    Код (Text):
    delay(10);
    while (digitalRead(myPins[i]) {};

    в ветке if после выполнения сценария. Задержка нужна для пропуска дребезга. Следующая строка подвешивает плату до тех пор пока нажатая кнопка не будет отпущена. После этого скетч продолжит опрашивать кнопки как обычно.
     
    Последнее редактирование: 27 апр 2015
  7. dangear

    dangear Нуб

    Всем спасибо! Рашил задачу! Привожу рабочий код ниже:
    PHP:
    #include <MIDI.h> // Добавляем библиотеку MIDI

    MIDI_CREATE_DEFAULT_INSTANCE();

    /* Импортируем библиотеки nRF24l01*/
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    /* Обозначаем пины nRF24l01*/
    #define CE_PIN  9
    #define CSN_PIN 10

    int myPins[] = {2, 3, 4, 5, 6}; //Массив пинов кнопок
    int myNote[] = {76, 77, 78, 79, 80}; //Массив передаваемых данных
    int myLed[] = {A1, A2, A3, A4, A5}; //Массив светодиодов для реакции на нажатие
    int sendOn[] = {false,false,false,false,false}; //Массив состояния нажатой кнопки
    int sendOff[] = {false,false,false,false,false}; //Массив состояния отжатой кнопки
    int midChannel = 2; //Канал Midi

    int buttonState = 0; //Переменная состояния нажатия

    const uint64_t pipe = 0xE8E8F0F0E1LL; // определяем канал связи беспроводных модулей

    /* Создаем радио канал*/
    RF24 radio(CE_PIN, CSN_PIN);
    /* Создаем массив, который отправлем по радио*/
    int MidOUT[3]={0,0,0};

    void setup()
    {
        radio.begin();
        radio.openWritingPipe(pipe);

        Serial.begin(115200);
        for(int i=0;i<5;i++) {
          pinMode(myPins[i], INPUT_PULLUP); //Определяем пины кнопок как входящие данные
        }
        for(int i=0;i<5;i++) {
          pinMode(myLed[i], OUTPUT); //определяем пины светодиодов на исходящие данные
        }
    }

    void loop()
    {
    for(int i=0;i<5;i++) {
      buttonState = digitalRead(myPins[i]);

      if (buttonState == LOW && sendOn[i] == false)  // Нажатие клавиши
      {
        MIDI.sendNoteOn(myNote[i],127,midChannel); // Отправляем Миди сигнал в сериал
        digitalWrite(myLed[i], HIGH); // загорается контрольная лампочка
        sendOn[i] = true;    // Команда Note On послана
        sendOff[i] = false;  // Команда Note Off не послана
        MidOUT[0]=myNote[i]; // Забиваем массив для радиосигнала
        MidOUT[1]=127;
        MidOUT[2]=midChannel;
        radio.write(MidOUT, sizeof(MidOUT)); // Отправляем Миди сигнал по радио
      }
      else if (buttonState == LOW && sendOn[i] == true)  // Если клавиша удерживается
      {
        digitalWrite(myLed[i], HIGH); // Лампа продолжает гореть
        sendOn[i] = true;
        sendOff[i] = false;
      }
      else if (buttonState == HIGH && sendOff[i] == false)  // Если клавишу отпустили
      {
        MIDI.sendNoteOn(myNote[i],0,midChannel); // Отправляем Миди сигнал в сериал
        digitalWrite(myLed[i], LOW); // Гасим лампу
        sendOn[i] = false;
        sendOff[i] = true;
        MidOUT[0]=myNote[i]; // Забиваем массив для отправки по радио
        MidOUT[1]=0;
        MidOUT[2]=midChannel;
        radio.write(MidOUT, sizeof(MidOUT)); // Отправляем миди сигнал по радио каналу
      }
    }
    }
    Но вот есть проблема: при отправке сигнала по радиоканалу есть сильное запоздание. Т.е. для того, чтобы сигнал отправился нужно удерживать кнопку. И он не всегда отправляется. Пробовал устанавливать radio.write(MidOUT, sizeof(MidOUT)); перед закрытием цикла loop, скрипт работает как надо, но постоянно сыпет в радиосигнал значения, что не есть хорошо. Хочется отправлять в радио лишь только то, что нужно. Как побороть эту задержу в отправке?
     
    Последнее редактирование: 29 апр 2015
  8. dangear

    dangear Нуб

    Решил проблему заменой библиотеки для nrf24l01