Реализация паузы в скетче без delay

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

  1. Megakoteyka

    Megakoteyka Оракул Модератор

    Речь шла о конечном автомате на switch. Он позволяет обойтись без delay и дает возможность одновременно выполнять другие задачи. Но если это не требуется, то не забивайте себе голову и делайте через delay.
     
  2. Vetrinus

    Vetrinus Гик

    Спасибо огромное, все работает замечательно. Пусть я пока не понимаю, как это сделано, но скетч подлежит изучению под микроскопом. Еще раз огромное спасибо)
     
  3. Tomasina

    Tomasina Сушитель лампочек Модератор

    А по сравнению с твоим скетчем ничего изменилось, все то же самое, мною только все повторяющиеся куски обернуты в циклы, массивы и функции. Распечатай оба скетча, положи рядом и сравнивай ;)
     
  4. DrProg

    DrProg Вечный нерд

    И все таки, зачем отказываться от delay(), если он не мешает функционированию? Только потому что он "не очень"? Delay () в данном случае делает заданное время именно то что нужно, то есть ничего. Стоит ли заморачиватьмя подменой его millis() если в итоге будет то же самое, только с большим кол-вом строк в коде?

    Вот с циклами правильное решение, именно это я имел ввиду. Только не понял этот кусок:
    Код (Text):
     while(pinLed[i]) pinMode(pinLed[i++], OUTPUT);
    для остановки цикла pinLed должен равняться 0, это как?
     
    Последнее редактирование: 16 авг 2015
    ИгорьК нравится это.
  5. Tomasina

    Tomasina Сушитель лампочек Модератор

    Для остановки цикла условие должно стать false. Это произойдёт когда закончится последний элемент в массиве pinLed[], так как ячейка pinLed[10] уже не существует.
     
  6. DrProg

    DrProg Вечный нерд

    Я не в курсе тонкостей, разве массивы числовых типов данных тоже отмечаются нулями в конце? Не выскочит ли цикл на мусор за пределами массива?
     
    ИгорьК нравится это.
  7. Tomasina

    Tomasina Сушитель лампочек Модератор

    А откуда там нуль в конце?
    1й проход цикла: i=0, нулевой элемент массива pinLed[0] существует (число 13), значит условие true, поэтому выполняем pinMode(13, OUTPUT); и тут же i++.
    2й проход цикла: i=1, элемент массива pinLed[1] существует, значит условие true, поэтому выполняем pinMode(12, OUTPUT); и тут же i++.
    10й проход цикла: i=9, элемент массива pinLed[9] существует, значит условие true, поэтому выполняем pinMode(3, OUTPUT); и тут же i++.
    11й проход цикла: i=10, элемент массива pinLed[10] не существует, значит условие false, цикл прерывается.
     
  8. DrProg

    DrProg Вечный нерд

    А при чем тут существует или нет, если
    Код (Text):
    pinLed[i]

    возвращает значение этого элемента массива, а не факт его существования.
     
    ИгорьК нравится это.
  9. Tomasina

    Tomasina Сушитель лампочек Модератор

    А если значения нету, значит условие не выполняется, цикл прерывается. В чем противоречие?
     
  10. Unixon

    Unixon Оракул Модератор

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

    То, что у вас массив состоит из 10 элементов еще не означает, что вы не можете прочитать несуществующие 11-й, 12-й и т.д. элементы. Компилятор ничего за вас додумывать не будет, никакой проверки индекса массива, это вам не Паскаль или Ада. Массив в Си - это просто указатель на первый элемент. За доступом к памяти следите сами.
     
    Последнее редактирование: 16 авг 2015
    DrProg нравится это.
  11. Tomasina

    Tomasina Сушитель лампочек Модератор

    Ладно, убедили. Пишем так:
    Код (Text):
    for(byte i =0; i < 10; i++) {pinMode (pinLed[i], OUTPUT);}
     
  12. issida

    issida Нерд

    как в таком коде уйти от delay
    Код (C++):


    // запуск ручного режиам сервы1
    else if (m==10){ // если нажата кнопка и экран10
         servo1_current_vol = servo1_current_vol + servo1_set_vol; // вычисление текущего угла сервы 1
          myservo1.attach(3); //включение сервы 1
          while (servo1_current_vol >= 180) {  //пока текуший угол сервы 1 больше 180
            servo1_current_vol = servo1_current_vol - 180 ;  // высчитываем оставшийся нужный угол с начала
             myservo1.write(180) ;
             delay(1000);
              myservo1.write(0);
              delay(1000);
            }
           myservo1.write(servo1_current_vol);   //поворот сервы 1  на высчитанный угол
           delay(1000);
            myservo1.detach();         //отключение сервы , чтоб не жужжала
       } // конец ручного режима сервы 1  
       
    библиотека на обработку кнопок OneButton.h
    Пробовал с millis, но while не обрабатывается тогда.
     
  13. Unixon

    Unixon Оракул Модератор

    Переписывайте весь код в один большой автомат. У вас не будет ни while ни delay, будут только всякие if-ы, куча меток времени, сравнения их с millis и смена состояния. Любой кусок кода, для входа в который или для выхода из которого нужны дополнительные условия или ожидание должен выделяться в отдельное состояние.
     
    ostrov нравится это.
  14. ostrov

    ostrov Гуру

    Даже и не куча времени для сравнения, задержка везде одинакова - 1 сек. То есть задача всего лишь после подачи команды серве выждать эту самую секунду не дергая ее раньше. Ничего особо сложного не вижу. Другой вопрос: надо ли? Уход от delay() нужен только в том случае, если программа в это время занята чем то другим. Если же приведенный код таков весь, то с delay() проще и правильнее.
     
  15. issida

    issida Нерд

    секунда для того, чтоб серва успела встать в нужное положение. Если поступит команда повернуть серву на 500 , то должна будет повернуться от текущего положения ( к примеру 0 ) до 180, вернуться в 0 , повернуться на 180, вернуться в 0 и стать на оставшийся угол (140). С if не угадать сколько их понадобится . В устройстве всего 4 такие сервы с аналогичным управлением, и может случится такое, что включение второй будет на момент работы первой, когда та делает свои delay.
     
  16. Unixon

    Unixon Оракул Модератор

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

    Onkel Гуру

    умеете Вы напугать терминологией, умеете, и ведь без единого матерного слова! Но Вы конечно правы.
    Про работу 8 серв на одном мк я тут писал как-то в "смотрите что я сделал", но уже уплыло, вот есть пример кода на С Сode Vision, но легко портировать на arduino ide, посмотрите тут, немного есть вот тут, как делать сами импульсы средствами самого мк атmega328
    http://onkelz.livejournal.com/2243.html
     
  18. issida

    issida Нерд

    Код (C++):
    //-------------------Ручной режим СЕРВЫ1------------------
    switch (s1) {
        case 1:  
    if(utime-prev_mixer_time>=30){
    s1t=utime;
    analogWrite(mixer, mixer_speed);
    s1=2;
    break;
    }
    else if(utime-prev_mixer_time<30){
    s1=3;
    break;
    }
        case 2:
    if(utime-s1t>=mixer_time){
      analogWrite(mixer, 0);
      prev_mixer_time = utime;
    }
    if(utime-s1t>=mixer_time+5){
      s1=3;
    }
        break;
       
        case 3:
    servo1_current_vol = servo1_current_vol + servo1_set_vol; // вычисление текущего угла сервы 1
    s1=4;
        break;

       
        case 4:
    if(servo1_current_vol>=180){
      s1=5;
      s1t=utime;
      }
      else if(servo1_current_vol<180){
      s1=8;
      }
        break;

        case 5:
    if(utime-s1t>=1){
      servo1_current_vol=servo1_current_vol-180;
      myservo1.attach(3);
      myservo1.write(180);
      s1=6;
       }
        break;

        case 6:
    if(utime-s1t>=3){
    myservo1.write(0);
    s1=7;
    }
        break;

        case 7:
    if(utime-s1t>=5){
    s1=4;
    }
        break;

        case 8:
    myservo1.attach(3);
    myservo1.write(servo1_current_vol);
    s1t=utime;
    s1=9;
        break;
        case 9:
    if(utime-s1t>=2){
    myservo1.detach();
    s1=0;
        break;
    }
    }

    //-------------------Ручной режим СЕРВЫ2------------------
    switch (s2) {
        case 1:  
    if(utime-prev_mixer_time>=30){
    s2t=utime;
    analogWrite(mixer, mixer_speed);
    s2=2;
    break;
    }
    else if(utime-prev_mixer_time<30){
     
    s2=3;
    break;
    }
        case 2:
    if(utime-s2t>=mixer_time){
      analogWrite(mixer, 0);
      prev_mixer_time = utime;
    }
    if(utime-s2t>=mixer_time+5){
      s2=3;
    }
        break;
       
        case 3:
    servo2_current_vol = servo2_current_vol + servo2_set_vol; // вычисление текущего угла сервы 1
    s2=4;
        break;

       
        case 4:
    if(servo2_current_vol>=180){
      s2=5;
      s2t=utime;
      }
      else if(servo2_current_vol<180){
      s2=8;
      }
        break;

        case 5:
    if(utime-s2t>=1){
      servo2_current_vol=servo2_current_vol-180;
      myservo2.attach(6);
      myservo2.write(180);
      s2=6;
       }
        break;

        case 6:
    if(utime-s2t>=3){
    myservo2.write(0);
    s2=7;
    }
        break;

        case 7:
    if(utime-s2t>=5){
    s2=4;
    }
        break;

        case 8:
    myservo2.attach(6);
    myservo2.write(servo2_current_vol);
    s2t=utime;
    s2=9;
        break;
        case 9:
    if(utime-s2t>=2){
    myservo2.detach();
    s2=0;
        break;
    }
    }
    Про автоматы я со switch case нашел. Так заработало
     
    Tomasina нравится это.