пауза в цикле

ТокарьКот

✩✩✩✩✩✩✩
29 Мар 2025
6
0
Здраствуйте.
Вопрос: как организовать паузу в цикле ? Например выполняется какой то цикл, при нажатии на кнопку "пауза" он останавливается, при нажатии на кнопку "старт", он продолжает доделывать оставшееся количество циклов. В стандартных циклах этого нельзя добиться, по моему. Поэтому я организовал такой. Но он срабатывает только если кнопка удерживается, причем доделывается цикл, потом делается ещё один и только потом останавливается.



C++:
 #include "GyverButton.h"

#define BTN1 35  //  старт
#define BTN11 36  //  пауза

GButton butt1(BTN1);
GButton butt11(BTN11);

boolean start_flag = false;

// переменные
int8_t Kolihestvo = 1;
 

void loop
butt1.tick();
butt11.tick();

 if (butt1.isPress()) {                              //  Старт
    start_flag = true;
 }

if(!butt11.isPress() && start_flag == true && j < Kolihestvo) {
    funk();
    j++;
  }
  else if(butt11.isPress() || j == Kolihestvo) {
    start_flag = false;
  }
 

poty

★★★★★★✩
19 Фев 2020
3,501
996

@ТокарьКот, приводите правильный пример, который "с флагом". Зачем показывать заведомо неправильный результат?
 

ТокарьКот

✩✩✩✩✩✩✩
29 Мар 2025
6
0
"Правильный" просто не лучше, а даже ещё хуже.

C++:
 #include "GyverButton.h"

#define BTN1 35  //  старт
#define BTN11 36  //  пауза

GButton butt1(BTN1);
GButton butt11(BTN11);

boolean start_flag = false;
boolean pausa_flag = true;

// переменные
int8_t Kolihestvo = 1;
int8_t j;

void loop
butt1.tick();
butt11.tick();

if (butt1.isPress()) {                              //  Старт
    start_flag = true;
    pausa_flag = true;
}
if (butt11.isPress()) {                              //  Пауза
    pausa_flag = false;
}

if( start_flag == true && pausa_flag == true && j < Kolihestvo) {
    funk();
    j++;
  }
  else if(j == Kolihestvo || pausa_flag == false) {
    start_flag = false;
  }
 
Изменено:

Сотнег

★★★★★★★
15 Янв 2020
4,553
1,546
@ТокарьКот,
вы в постановке задачи хотели, чтобы при нажатии кнопки Старт цикл стартовал,
а при нажатии кнопки Пауза приостанавливался.

Тогда зачем в коде при нажатии кнопки Старт поднимается флаг паузы,
а при нажатии кнопки Пауза этот флаг снимается?
Потом он так и проверяется задом наперёд, но задумка непонятна.


В конце кода вы зачем-то снимаете флаг старта, если кто-то нажал кнопку паузы.
Разве, у кнопки паузы должна быть функция отмены старта?
 
Изменено:
  • Лойс +1
Реакции: ТокарьКот

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,460
993
59
Марий-Эл
А куда делись фигурные скобки у функции loop?
И где функция setup?

Метод
butt1.isPress()
срабатывает не с первого раза, он не блокирующий. У вас цикл провернётся несколько раз, пока этот метод сработает.
 

ТокарьКот

✩✩✩✩✩✩✩
29 Мар 2025
6
0
Виноват-с. Вот так лучше работает. Проверил. Но кнопку все равно нужно удерживать и иногда второй круг делает.

C++:
#include "GyverButton.h"

#define BTN1 35  //  старт
#define BTN11 36  //  пауза
#define BTN12 37  //  ресет

GButton butt1(BTN1);
GButton butt11(BTN11);
GButton butt12(BTN12);

boolean start_flag = false;


// переменные
int8_t Kolihestvo = 1;
int8_t j;

void setup {
}

void loop {
butt1.tick();
butt11.tick();
butt12.tick();

if (butt1.isPress()) {                              //  Старт
   start_flag = true;
   
}
if (butt11.isPress()) {                              //  Пауза
    start_flag = false;
}
if (butt12.isPress()) {                              //  Ресет
  j = 0;
}


if ( start_flag == true && j < Kolihestvo) {
     funk();
     j++;
   }
   else if (j == Kolihestvo) {
   start_flag = false;
   }
}

void funk() {
бла бла
}
"А куда делись фигурные скобки у функции loop?
И где функция setup?"


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


"Метод
butt1.isPress()
срабатывает не с первого раза, он не блокирующий. У вас цикл провернётся несколько раз, пока этот метод сработает."


Мне бы хотелось послушать более развернутый ответ С Вашей стороны. Если Вам не трудно.
 
Изменено:

poty

★★★★★★✩
19 Фев 2020
3,501
996
@ТокарьКот, если Вы на первоначальные ошибки будете накладывать ошибки копирования на форум, то переписка будет длиться вечно. Создайте максимально простой код с проблемой, чтобы он у Вас компилировался, скопируйте его полностью сюда на форум, тогда и будут результаты помощи.
Как можно объявить два раза BTN11?
C++:
#define BTN1 35  //  старт
#define BTN11 36  //  пауза
#define BTN11 37  //  ресет
Если предположить, что BTN11 в конце - это BTN12, то где устанавливается первоначальное значение j? Вот Kolihestvo устанавливается явно!
Если предположить, что Вы рассчитываете на j=0 вначале, то при нажатии BTN1 выполнится
C++:
if (butt1.isPress()) {                              //  Старт
   start_flag = true;
}
...
if ( start_flag == true && j < Kolihestvo) {
     funk();
     j++;
   }
j станет равным 1, в следующем цикле выполнится уже
C++:
else if (j == Kolihestvo) {
   start_flag = false;
   }
и флаг сбросится.
Причём j, в этом случае, останется = 1 и снова в
C++:
if ( start_flag == true && j < Kolihestvo) {
     funk();
     j++;
   }
программа никогда не войдёт, сколько бы Вы не жали на BTN1. То есть, программа действует не так, как Вы описываете в целом. Снова ошибки в копировании? Или j изменяется в funk() и мы должны были об этом догадаться? Тогда я - пас, гадальный шар разбился.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,460
993
59
Марий-Эл
Мне бы хотелось послушать более развернутый ответ С Вашей стороны. Если Вам не трудно.
Я могу немного ошибаться, но примерно работает так.
butt11.tick(); проверяет нажата ли кнопка. Если кнопка нажата, поднимается флаг и запоминаются миллисекунды от начала работы МК.
В следующий раз, если флаг установлен, проверяется сколько миллисекунд прошло после того как был установлен флаг и нажата ли кнопка. Если не ошибаюсь, там задано 5 миллисекунд. После этих 5 миллисекунд считается, что дребезг кнопки прошёл и можно считать её нажатой.
А так как это происходит в цикле, а цикл допустим выполняется 0.5 миллисекунд, то Ваш цикл выполнится 10 раз, прежде чем сработает butt1.isPress() и кнопка будет считаться нажатой.
 
  • Лойс +1
Реакции: poty

poty

★★★★★★✩
19 Фев 2020
3,501
996
@Эдуард Анисимов, ТС, по-моему, выдаёт желаемое за действительное.
и остальные - говорит о том, что кнопка инициализировалась со стандартными параметрами: HIGH_PULL, NORM_OPEN, антидребезгом 80 мс и т.п.
- совершенно правы - только опрос, он меняет состояние внутренних флагов в соответствии с установленными временными параметрами, задержками и проч.
из мануала:
возвращает true при нажатии на кнопку. Сбрасывается после вызова
(выделено мной) То есть, сколько не продолжай удерживать кнопку, isPress вернёт true только раз. Каким образом тогда длительность нажатия влияет на выполнение кода - мне непонятно.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,460
993
59
Марий-Эл
@poty, Если удерживать кнопку, isPress не сработает. Там уже буду срабатывать функции удержания. Так что мы можем получить вообще непонятно что.
 

poty

★★★★★★✩
19 Фев 2020
3,501
996
@Эдуард Анисимов, да я-то это понимаю, но вот объяснения ТС:
он срабатывает только если кнопка удерживается, причем доделывается цикл, потом делается ещё один и только потом останавливается
кнопку все равно нужно удерживать и иногда второй круг делает
 

ТокарьКот

✩✩✩✩✩✩✩
29 Мар 2025
6
0
Вновь прошу прощения. Мне не хочется, чтобы кто ни будь думал, что с моей стороны небрежное отношение. Хотя если оно и присутствует, то только из за усталости. А так я не хотел загружать излишней информацией.

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


Вводные данные меняю энкодером. А функция- это движение шаговиков. Скомпилировал. Проверил. Всё работает корректно, кроме кнопки "пауза". Работает при удержании, на второй раз.

C++:
// пины энкодера
#define CLK 4, 
#define DT 5, 
#define SW 6, 


#include "GyverStepper2.h"

#include "GyverEncoder.h"
Encoder enc(4, 5, 6);                  // для работы c кнопкой

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);    // адрес 0x27 или 0x3f

#include "GyverButton.h"

GStepper2<STEPPER2WIRE> stepper1(400, 10, 11);
GStepper2<STEPPER2WIRE> stepper2(400, 12, 13);

#define BTN1 26   // кнопка: (старт)
#define BTN11 36  //  кнопка (пауза)
#define BTN12 37  //  кнопка (ресет)

GButton butt1(BTN1);
GButton butt11(BTN11);
GButton butt12(BTN12);

boolean start_flag = false;

// переменные
int8_t KolPr = 1;            // количество проходов
long Dlina = 0;              // длина обработки
int SjemZa1 = 0;             // съем за один проход
int Podaha = 0;              // подача
int uboost = 7000;           
int uspeed = 4000;           // скорость холостого хода 1-го мотора
int tboost = 7000;
int tspeed = 3000;           // скорость холостого хода 2-го мотора
int tdistance = 400;         // отскок резца
int Raz;
int j;

int8_t arrowPos = 0;  // позиция стрелки

void setup() {
 
  enc.setType(TYPE1);
 

  lcd.init();
  lcd.backlight();
  lcd.setCursor(4, 1);
  lcd.print("TokapjKom");
  delay(2000);
  lcd.clear();
  printGUI();   // выводим интерфейс
}

void loop() {
  enc.tick();
 
  butt1.tick();  // butt1.isClick()  butt1.isSingle() butt1.isDouble() butt1.isTriple()  butt1.isPress()
  butt11.tick();
  butt12.tick();

if (enc.isTurn()) {  // при любом повороте
    lcd.clear();        // очищаем дисплей

    if (enc.isLeftH()) {
      arrowPos++;
      if (arrowPos >= 4) arrowPos = 3;  // ограничиваем позицию курсора

    }
    if (enc.isRightH()) {
      arrowPos--;
      if (arrowPos < 0) arrowPos = 0;  // ограничиваем позицию курсора
    }

    // при повороте меняем переменные ++
    if (enc.isRight()) {
      switch (arrowPos) {
        case 0: KolPr++;
          break;
        case 1: Dlina = Dlina + 400;
          break;
        case 2: SjemZa1 = SjemZa1 + 40;
          break;
        case 3: Podaha = Podaha + 40;
          break;
 
      }
    }

    // при повороте меняем переменные --
    if (enc.isLeft()) {
      switch (arrowPos) {
        case 0: KolPr--;
         if(KolPr <= 1) KolPr = 1;           // значение не меньше одного
          break;
        case 1: Dlina = Dlina - 400;
         if(Dlina <= 0) Dlina = 0;           // только положительные значения
          break;
        case 2: SjemZa1 = SjemZa1 - 40;
         if(SjemZa1<= 0) SjemZa1 = 0;        // только положительные значения
          break;
        case 3: Podaha = Podaha - 40;
         if(Podaha <= 0) Podaha = 0;         // только положительные значения
          break;

      }
    }
    

    printGUI();   // выводим интерфейс
  }


if (butt1.isPress()) {                              //  Старт
    start_flag = true;
  }

  if (butt11.isPress()) {                             //  Пауза
    start_flag = false;
  }


  if (butt12.isPress()) {                             //  Ресет
    Raz = 0;
    j = 0;
    stepper1.reset();
    stepper2.reset();
  }
 if (start_flag == true && j < KolPr) {
     podaha_spravo();
     j++;
   }
   else if (j == KolPr) {
   start_flag = false;
   }
}




void printGUI() {


  lcd.setCursor(0, 0); lcd.print("KolPr "); lcd.print(KolPr);
  lcd.setCursor(0, 1); lcd.print("Dlina "); lcd.print(Dlina);
  lcd.setCursor(0, 2); lcd.print("SjemZa1 "); lcd.print(SjemZa1);
  lcd.setCursor(0, 3); lcd.print("Podaha "); lcd.print(Podaha);


  // выводим стрелку
  switch (arrowPos) {
    case 0: lcd.setCursor(5, 0);
      break;
    case 1: lcd.setCursor(5, 1);
      break;
    case 2: lcd.setCursor(7, 2);
      break;
    case 3: lcd.setCursor(6, 3);
      break;
 
  }     
 
  lcd.write(126);   // вывести стрелку
}

void podaha_spravo() {                                        // Подача
  bool dir = true;
  Raz = tdistance + SjemZa1;

  stepper1.tick();
  stepper1.setAcceleration(uboost);
  stepper1.setMaxSpeed(Podaha);
  stepper1.setTarget(Dlina, RELATIVE);
  while (stepper1.tick())
    ;

  stepper2.tick();
  stepper2.setAcceleration(tboost);
  stepper2.setMaxSpeed(tspeed);
  stepper2.setTarget(tdistance, RELATIVE);
  while (stepper2.tick())
    ;

  stepper1.tick();
  stepper1.setAcceleration(uboost);
  stepper1.setMaxSpeed(uspeed);
  stepper1.setTarget(-Dlina, RELATIVE);
  while (stepper1.tick())
    ;

  stepper2.tick();
  stepper2.setAcceleration(tboost);
  stepper2.setMaxSpeed(tspeed);
  stepper2.setTarget(-Raz, RELATIVE);
  while (stepper2.tick())
    ;
 
    
}
 

asaitov

★✩✩✩✩✩✩
16 Янв 2024
31
13
Проблема в том, что пока выполняется podaha_spravo(), не вызывается butt11.tick(), поэтому состояние кнопки не считывается. Когда же podaha_spravo() заканчивает работу, состояние кнопки наконец считывается. И если кнопка в этот момент не зажата, то просто начаинается следующая итерация podaha_spravo(). Если же кнопка зажата, то начинается проверка на дребезг, т.е. кнопка должна быть нажата также через несколько миллисекунд, но эта проверка сразу не выполняется, так как опять вызывается podaha_spravo(). И когда эта итерация заканчивается, снова вызывается butt11.tick(), проверка на дребезг наконец завершается и только тогда считается, что кнопка нажата.

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

C++:
while (stepper1.tick()) {
  butt1.tick();
  butt11.tick();
  butt12.tick();
}
// то же самое для других вращений
 
  • Лойс +1
Реакции: ТокарьКот

poty

★★★★★★✩
19 Фев 2020
3,501
996
@ТокарьКот, в качестве альтернативы предложению @asaitov (что не означает, что его предложение неверно!) предлагаю ознакомиться с применением GyverButton с прерываниями.
 
  • Лойс +1
Реакции: ТокарьКот

ТокарьКот

✩✩✩✩✩✩✩
29 Мар 2025
6
0
Вот в чем дело. Я чувствовал, что из за этого, но tick() вставлял один раз в функцию.
Спасибо всем за помощь !
Я применю пока самое простое решение, но и другие буду иметь в виду.
Следующий раз буду знать как задавать вопросы ))
Просто, образно говоря, когда берёшь быка за рога. Не замечаешь как сам уже у него на рогах.