Удерживайте кнопку/нажмите кнопку/нажмите кнопку

Я хочу управлять серводвигателем таким образом, чтобы

  • Если вы нажмете кнопку, вы сможете управлять ею с помощью потенциометра a.
  • Если вы нажмете двойное время, вы сможете управлять сервоприводом через инфракрасный порт.
  • если удерживать кнопку, шаговый двигатель начнет вращаться из одного положения в другое.

У меня проблема: когда я нажимаю кнопку, происходит бесконечный цикл, и я не могу его остановить. Я пробую другую библиотеку кнопок, но проблема все равно остается. Вот мой код:

// включает библиотеку Servo
#include <Servo.h>
#include <IRremote.h>
#include <OneButton.h>

int state = 0;
int RECV_PIN = 12;
const char type ='W';// W для белого, B для черного. Необходимо сохранять одинарные кавычки, например «B» или «W».
const boolean PCB = 0;// если на плате приемника установлено значение 1, если не установлено значение 0. Подробности смотрите в видео
boolean displayCode = true;// для отображения удаленного кода. если нет, установите значение false

const int SERVO_PIN = 8;  // аналоговый вывод, используемый для подключения потенциометра
int angle =90;    // начальный угол для сервопривода
int angleStep =10;
const int ANGLE_CENTRE =90;// центр/угол сброса вашего сервопривода
//**** Настройка сервоприводов заканчивается

// удаленные настройки
const String RIGHT="CH+";// перемещаем сервопривод вправо с помощью этой клавиши на пульте дистанционного управления
const String LEFT ="CH-";// перемещаем сервопривод влево с помощью этой клавиши на пульте дистанционного управления
const String CENTRE ="CH";// перемещаем сервопривод в центр с помощью этой клавиши на пульте дистанционного управления
// завершение удаленных настроек

IRrecv irrecv(RECV_PIN);
// Определяет контакты Tirg и Echo ультразвукового датчика
const int trigPin = 10;
const int echoPin = 11;
const int potPin = 0;
const int pushButton = 8;
OneButton button(A1, true);  
int value;

// Переменные длительности и расстояния
long duration;
int distance_cm;
Servo myServo; // Создает сервообъект для управления серводвигателем

// это коды хранения массива для White Remote при использовании с версией приемника, отличной от печатной платы
unsigned int whiteRemote[] ={
            0xFFA25D, // СН-
            0xFF629D,   // СН
            0xFFE21D,  // канал+

            0xFF22DD, // |<<
            0xFF02FD, // >>|
            0xFFC23D, // >||

            0xFFE01F, // -
            0xFFA857, // +
            0xFF906F, // эквалайзер

            0xFF6897, // 0
            0xFF9867, // 100+
            0xFFB04F, // 200+

            0xFF30CF, // 1
            0xFF18E7, // 2
            0xFF7A85, // 3

            0xFF10EF, // 4
            0xFF38C7, // 5
            0xFF5AA5,  // 6

            0xFF42BD, // 7
            0xFF4AB5, // 8
            0xFF52AD  // 9
            };
// бирки клавиш белого пульта
 String whiteRemoteKey[] ={
            "CH-",
            "CH",
            "CH+",

            "|<<",
            ">>|",
            ">||",

            "-",
            "+",
            "EQ",

            "0",
            "100+",
            "200+",

            "1",
            "2",
            "3",

            "4",
            "5",
            "6",

            "7",
            "8",
            "9"
            };

// это коды хранения массива для Black Remote при использовании с версией приемника, отличной от печатной платы
 unsigned int blackRemote[] ={
            0xFF629D, // ^
            0x38D3975C,   // <
            0x9334F738,  // ОК
            0x320412D8, // >
            0xFFA857, // v

            0xFF6897, // 1
            0xFF9867, // 2
            0xF0C41643, // 3

            0xFF30CF, // 4
            0xFF18E7, // 5
            0xFF7A85,  // 6

            0xFF10EF, // 7
            0xFF38C7, // 8
            0xFF5AA5,  // 9

            0xFF42BD, // *
            0xFF4AB5, // 0
            0xFF52AD  // #
            };
// Имена черных удаленных клавиш
 String blackRemoteKey[] ={
            "^",
            "<",
            "OK",
            ">",
            "v",

            "1",
            "2",
            "3",

            "4",
            "5",
            "6",

            "7",
            "8",
            "9",

            "*",
            "0",
            "#"
            };

decode_results results;

void setup() {
  pinMode(trigPin, OUTPUT); // Устанавливает trigPin как выход
  pinMode(echoPin, INPUT); // Устанавливает echoPin в качестве входных данных
  Serial. begin(9600);
  irrecv.enableIRIn(); // Запускаем приемник
  myServo.attach(SERVO_PIN); // Определяет, к какому выводу подключен серводвигатель

  button.attachDoubleClick(doubleClick);            // связываем функцию, вызываемую с событием doubleClick.
  button.attachClick(singleClick);                  // связываем функцию, вызываемую с событием SingleClick.
  button.attachLongPressStop(longClick);            // связываем функцию, которая будет вызываться при длительном нажатии.

}
void loop() { 
  button.tick();                                    // проверяем статус кнопки
  delay(10);                                        // небольшое ожидание между проверкой кнопки
}

// Функция расчета расстояния, измеренного Ультразвуковым датчиком
int calculateDistance(){ 
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  // Устанавливает trigPin в состояние HiGH на 10 микросекунд
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH); // Считывает echoPin, возвращает время прохождения звуковой волны в микросекундах
  //Комментарий от меня!
  //расстояние= продолжительность*0.034/2;
  //
  distance_cm = (duration/2) / 29.1;
  return distance_cm;
}
void doubleClick() {                                // что происходит при двойном щелчке по кнопке
  while(1) {
    if (irrecv.decode(&results)) {
      if(displayCode)Serial.println(results.value, HEX);
      validateCode(results.value);// ниже используется "robojaxValidateCode"
      irrecv.resume(); // Получаем следующее значение
    }
    delay(50);// задержка 50 миллисекунд
    break;
  }
}

void singleClick(){                                 // что происходит при нажатии кнопки
  while(1) {
    value = analogRead(potPin);
    value = map(value, 0, 1023, 15, 165);
    myServo.write(value);
    delay(30);
    distance_cm = calculateDistance();

    Serial.print(value); // Отправляет текущую степень в последовательный порт
    Serial.print(","); // Отправляет дополнительный символ рядом с предыдущим значением, который понадобится позже в среде обработки данных для индексации
    Serial.print(distance_cm); // Отправляет значение расстояния в последовательный порт
    Serial.print("."); // Отправляет дополнительный символ рядом с предыдущим значением, который понадобится позже в среде обработки данных для indexin
  }
}

void longClick(){                                   // что происходит при длительном нажатии кнопки
  for(int i=15;i<=165;i++){ 
    myServo.write(i);
    delay(30);
    distance_cm = calculateDistance();// Вызывает функцию расчета расстояния, измеренного Ультразвуковым датчиком для каждого градуса

    Serial.print(i); // Отправляет текущую степень в последовательный порт
    Serial.print(","); // Отправляет дополнительный символ рядом с предыдущим значением, который понадобится позже в среде обработки данных для индексации
    Serial.print(distance_cm); // Отправляет значение расстояния в последовательный порт
    Serial.print("."); // Отправляет дополнительный символ рядом с предыдущим значением, который понадобится позже в среде обработки данных для indexin
  }
  // Повторяет предыдущие строки от 165 до 15 градусов
  for(int i=165;i>15;i--){
    myServo.write(i);
    delay(30);
    distance_cm = calculateDistance();

    Serial.print(i);
    Serial.print(",");
    Serial.print(distance_cm);
    Serial.print("."); 
  }
}
/*
 * function: validateCode
 * validates the remote code and prints correct key name
 * cd is code poassed from the loop
 * Written by A. S. for Robojax
 */
void validateCode(int cd)
{

  // Декодер Robojax IR Remote
  int found=0;

 if(type =='W' && !PCB)
 {
    // Robojax IR White Дистанционный декодер
    // если тип установлен на «W» (белый пульт) и PCB=0, тогда проверьте черный код пульта
      for(int i=0; i< sizeof(whiteRemote)/sizeof(int); i++)
      {
        if(whiteRemote[i] ==cd)
        {

          Serial.print("Key pressed:");
          Serial.println(whiteRemoteKey[i]);
          servoAction(whiteRemoteKey[i]);// выполняем действие
          found=1;
        }// если совпадение
      }// для
 }else{

      // если тип установлен на «B» (черный пульт) и PCB = 0, тогда проверьте код черного пульта
       for(int i=0; i< sizeof(blackRemote)/sizeof(int); i++)
      {
        // Robojax IR черный Дистанционный декодер
        if(blackRemote[i] ==cd)
        {

          Serial.print("Key pressed:");
          Serial.println(blackRemoteKey[i]);
          servoAction(blackRemoteKey[i]);// выполняем действие

          found=1;
        }// если совпадение
      }// для
 }// еще
  if(!found){
    if(cd !=0xFFFFFFFF)
      {
    Serial.println("Key unkown");
      }
  }// найденный
}// конец validateCode

/*
 * 
 * servoAction()
 * receives string "value" as input and based on the settings, 
 * sends translates it to servo value and controls servo
 * either 
 * rotates servo to right
 * rotates servo to left
 * moves the servo to middle
 * 
 */
void servoAction(String value){
  // Демонстрация сервокнопки с ИК-пультом от Robojax.com
  while(value == RIGHT){

    if (angle > 0 && angle <= 180) {
      angle = angle - angleStep;
       if(angle < 0){
        angle = 0;
       }else{
      myServo.write(angle); // перемещаем сервопривод на нужный угол
      Serial.print("Moved to: ");
      Serial.print(angle);   // печатаем угол
      Serial.println(" degree");
       }
    }// если
    value =".";
    delay(100);
  }// пока для ПРАВА
  while(value == LEFT){

    // Демонстрация сервокнопки с ИК-пультом от Robojax.com
    if (angle >= 0 && angle <= 180) {
      angle = angle + angleStep;
      if(angle >180){
        angle =180;
       }else{
      myServo.write(angle); // перемещаем сервопривод на нужный угол
      Serial.print("Moved to: ");
      Serial.print(angle);   // печатаем угол
      Serial.println(" degree");
       }
    }
    value =".";
    delay(100);
  }// пока для LEFT

  if(value == CENTRE)
  {
    angle = ANGLE_CENTRE;
    myServo.write(angle); // перемещаем сервопривод в центр под углом 90 градусов
  }
    // Управление Robojax IR Servo
}//конец действия реле

извините за мой английский. Надеюсь, кто-нибудь мне поможет.

, 👍1


1 ответ


Лучший ответ:

0

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

Используйте функции событий только для установки переменной состояния, а затем в основном цикле используйте переключатель Case Case, чтобы выбрать код, используемый сервоуправлением, следующим образом:

 ....
 unsigned int status = 0;
 ....
 void doubleClick(){
    status = 0;
 }
 void singleClick(){
    status = 1;
 }
 void longClick(){
    status = 2;
 }
 void setup() {
 ....
 }
 void loop {
   button.tick();                                    // проверяем статус кнопки
   //задержка(10); // это не нужно.
   switch (status){
     case 0:{
       //действие по двойному клику
     } 
     case 1:{
       //действие по одиночному клику
     } 
     case 2:{
       //действие при длинном клике
     } 
 }

Внутри каждого случая вставьте соответствующий код, который у вас есть в циклах while(1) функций событий кнопки.

Другой вариант — вставить внутри бесконечных циклов возврат при нажатии кнопки следующим образом:

если (кнопка нажата) возврат;

,

Пожалуйста, используйте Enum вместо «магического числа»., @Filip Franik

Спасибо за ваш ответ. Но мне нужно, чтобы это действие происходило бесконечно, пока статус кнопки не изменится, например, с одного нажатия на двойное нажатие. Когда я использую оператор if, он не работает должным образом., @Amir Hossein Jobeiri

@AmirHosseinJobeiri Цикл while(1) заменяется основным циклом, поэтому он происходит вечно, пока вы не нажмете кнопку и не измените переменную состояния. Или просто используйте кнопку возврата, нажатую внутри цикла while(1), но дальнейшее расширение кода довольно сложно., @Dorian