Выполнить функцию цикла из основного цикла()

У меня проблемы с частью кода.

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

У меня есть функция sensorActivated(), которая выполняется в основном цикле.

, 👍-1

Обсуждение

Это работает, только если я вызываю fadingLED() ... что это значит? ... как это терпит неудачу?, @jsotola

пожалуйста, не говорите "когда даны определенные условия"... вместо этого перечислите условия, @jsotola

Печатаются ли сообщения «статус DFplayer:» и т. д.?, @Nick Gammon

Я отредактирую вопрос, чтобы быть более ясным, спасибо., @Lahey Corey

Возможно, вам следует опубликовать соответствующий код., @Rohit Gupta


2 ответа


1

Вот возможное решение, доказательство концепции того, как это можно сделать. Одна из проблем, с которой вы столкнулись, заключается в том, что вы используете delay() таким образом, что код останавливается, не позволяя произойти другим вещам. Проверьте Arduino «BlinkWithoutDelay». Обратите внимание, что если вы начнете с интенсивности менее 20, с шагом 4, вы добавите 4, но затем вернетесь к исходному числу. Возможно, вы захотите взглянуть на это и убедиться, что вы не можете попасть в эту ситуацию.

Вам всегда нужно вызывать функцию в цикле, но делать это нужно только тогда, когда вы хотите, чтобы она была выполнена. Эту программу можно было бы улучшить (избавиться от глобальных переменных, использовать статические переменные), но это можно легко исправить.

Этот код добавил немного последовательного вывода, так что вы можете использовать "последовательный плоттер" в IDE, чтобы увидеть, как включается и выключается бит "свечения", а также видеть различную яркость вашего светодиода.

// Создаем эффект свечения, но только когда бит свечения равен true
// тайм-аут

#define LED 13

unsigned long currenttime;
unsigned long currenttimeold;
unsigned long lastledtime;
unsigned long printold;
bool glow = false;
int brightness = 60;
int counter;
int fadeAmount = 4;

void setup() {
  // поместите сюда код установки для однократного запуска:
  Serial.begin(9600);
}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:

  currenttime=millis();
  
  // Каждые 100 мс прибавляем к счетчику
  // Когда оно достигает 50, инвертируем бит свечения
  if ((currenttime - currenttimeold) > 100)
  {
    currenttimeold = currenttime;
    counter = counter + 1;
    if (counter > 50)
    {
      glow = !glow;
      counter = 0;
    }
  }

  // Если бит свечения включен, гасим светодиод
  // иначе выключаем
  if (glow)
  {
    fadingLED();
  }
  else
  {
    analogWrite(LED, 0);
  }

  if ((currenttime - printold) > 50)
  {
    printold=currenttime;
    // Serial.print(millis());
    // Serial.print(",");
    Serial.print(glow * 100);
    Serial.print(",");
    Serial.print(brightness);
    Serial.print("\n");
  }

}


void fadingLED() {
  //Ло дель светодиод
  analogWrite(LED, brightness);

  if ((millis() - lastledtime) > 60)
  {
    lastledtime = millis();
    // изменить яркость в следующий раз через цикл:
    brightness = brightness + fadeAmount;

    // изменить направление затухания на концах затухания:
    if (brightness <= 20 || brightness >= 100) {
      fadeAmount = -fadeAmount;
    }
  }

}
,

1

Я видел ваши новые комментарии и поэкспериментировал с этим сегодня, используя UNO и этот PIR. Приведенный ниже код, несмотря на отсутствие какого-либо подобия элегантности, работает. При запуске устанавливает громкость и ждет срабатывания детектора движения. Затем он воспроизводит "случайный" трек во время пульсации светодиода. Светодиод мигает только во время воспроизведения трека и гаснет, когда трек не воспроизводится. Обратите внимание, как я использую ".isPlaying()".

Надеюсь, это поможет.

#include <DFPlayerMini_Fast.h>
#include <SoftwareSerial.h>

SoftwareSerial MySerial(10, 11); // прием, передача
DFPlayerMini_Fast MyMP3;

    #define PIR 8        // входной контакт PIR
    #define LED 9        // вывод светодиода
    #define pulseDelay 5 // миллисекунды между изменениями светодиода
    
    int brightness = 0;  // Уровень ШИМ для светодиода
    int fadeAmount = 5;  // на сколько точек затухать светодиод
    int volume = 25;     // Начальная громкость плеера
    int nFiles = 15;     // количество mp3 файлов на SD карте
    
    void setup() {
      analogWrite(LED, brightness);
      randomSeed(analogRead(5));
      Serial.begin(9600);
      MySerial.begin(9600);
      MyMP3.begin(MySerial, false);
      MyMP3.stop();
      Serial.print("Setting volume to ");
      Serial.println(volume);
      MyMP3.volume(volume);
    }
    
    void loop() {
      sensorActivated();
      fadingLED();
    }
    
    void fadingLED() {
      static unsigned long timer = millis();
    
      if (MyMP3.isPlaying()) {
        if (millis() - timer > pulseDelay) {
          timer = millis();
          analogWrite(LED, brightness);
          brightness = brightness + fadeAmount;
          if (brightness == 0 || brightness >= 255) {
            fadeAmount = -fadeAmount;
          }
        }
      }
    }
    
    void sensorActivated() {
      if ( (digitalRead(PIR) == HIGH) && (!MyMP3.isPlaying()) )
      {
        Serial.println("Sensor Activated");
        Serial.print("Random track being played: ");
        int randomInt = random(1, nFiles + 1);
        Serial.println(randomInt);
        MyMP3.play(randomInt);
      }
      else {
        if (!MyMP3.isPlaying())
        {
          if (brightness) {
            brightness = 0;
            analogWrite(LED, brightness);
          }
        }
      }
    }

===================

Вы можете сделать это немного проще, если четко скажете, какой эффект вы хотите получить. Например, когда DFP НЕ воспроизводится (дорожка закончена), мигайте светодиодом ДО тех пор, пока не появится движение, вызывающее воспроизведение другой дорожки.

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

То, что вы написали, это: *Я хочу выполнить функцию fadingLED(); только с условием:

if(pirSensor == HIGH && myDFPlayer.isPlaying()!=1) Я знаю, что мой код неверен. Как лучше всего выполнить функцию fadingLED() с условием (pirSensor == HIGH && myDFPlayer.isPlaying()!=1) ???*

Проблема, которую я вижу, заключается в том, что когда условие, если (pirSensor == HIGH && myDFPlayer.isPlaying()!=1) истинно, вы выполняете код для случайного выбора другой дорожки и запускаете воспроизведение снова. Это произойдет очень быстро, поэтому myDFPlayer.isPlaying() изменится, и вы никогда не сможете увидеть пульсирующий светодиод.

Мне кажется, вы неправильно написали.

Я ПРЕДПОЛАГАЮ, что когда датчик PIR имеет НИЗКИЙ уровень, это указывает на движение, а когда myDFP.isPlaying()!=1 указывает, что он НЕ воспроизводится. Когда вы обнаруживаете движение И DFP не воспроизводится, вы хотите начать воспроизведение другой дорожки.

Итак, измените строку в sensorActivated() на if(pirSensor == LOW && myDFPlayer.isPlaying()!=1)

Примечание: если у меня неправильный выходной сигнал ИК-датчика, оставьте его как if(pirSensor == HIGH && myDFPlayer.isPlaying()!=1) но прочитайте остальное, так что вы увидите, к чему я клоню, потому что вы не можете использовать ту же условную проверку в функциях fadingLED().

Теперь, когда он не воспроизводится и вы обнаруживаете движение, начнется воспроизведение другого трека.

Заменить "fadingLED();" в датчике Активировано для:

яркость=20; AnalogWrite(светодиод, яркость);

Это становится:

    void sensorActivated() {

  // DFPlayerMini_Fast.h имеет встроенную функцию "player.isPlaying()", которая возвращает логическое значение в зависимости от того, воспроизводит ли модуль песню в данный момент или нет.
  int pirSensor = digitalRead(SENSORPIN);

  if (pirSensor == HIGH && myDFPlayer.isPlaying() != 1)
  {
    Serial.println("DFplayer status: ");
    Serial.println(myDFPlayer.isPlaying());
    Serial.println("Sensor Activated");
    Serial.println("DFPlayer Working...");
    Serial.println("Random track being played: ");
    randomInt = random(3, 8);
    Serial.println(randomInt);
    myDFPlayer.play(randomInt);
    brightness = 20;
    analogWrite(LED, brightness);
    // здесь вам может понадобиться подождать, пока myDFPlayer.isPlaying() не изменит значения

  }
}

Теперь во время воспроизведения светодиод горит тусклым светом (позже его можно отключить);

Измените fadingLED на это:

void fadingLED() {

  static unsigned long timer = millis();

  if (myDFPlayer.isPlaying() != 1)) {
    if (millis() - timer > pulseDelay) {
      timer = millis();
      analogWrite(LED, brightness);
      // изменить яркость в следующий раз через цикл:
      brightness = brightness + fadeAmount;
      // изменить направление затухания на концах затухания:
      if (brightness == 20 || brightness >= 100) {
        fadeAmount = -fadeAmount;
      }
    }
  }
}

Эта функция не требует блокирующего вызова (например, delay(), который находится там, пока не истечет время). Теперь, когда DFP НЕ воспроизводится, светодиод будет мигать.

В начале кода используйте:

#define LED 9     // светодиод на контакте 9
#define pulseDelay 60    // миллисекунд
int brightness = 20;  // насколько яркий светодиод
int fadeAmount = 5;  // на сколько точек затухать светодиод

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

Наконец, используйте:

void loop() {
  sensorActivated();
  fadingLED();
}

Кроме того, вы используете значения аналоговой записи от 20 до 100. Помните, это не процент. Диапазон 0-255. Вы можете легко изменить это.

Даже если вы хотите, чтобы он мигал во время игры, надеюсь, в ответе достаточно информации, которая может оказаться вам полезной

,

Привет. Я отредактировал свой вопрос, пытаясь быть ясным. Я проверил ваше решение и вызвал fadingLED(); от основного контура, светодиод постоянно мигает. Я хочу, чтобы светодиод имел эффект затухания, но только во время воспроизведения, и оставался выключенным, пока dfp не воспроизводится. По какой-то причине, и я не знаю почему (выглядит странно, если честно), во время игры я должен использовать myDFPlayer.isPlaying() != 1) вместо myDFPlayer.isPlaying() == 1), а когда это не так играет, myDFPlayer.isPlaying() == 0), @Lahey Corey

Последний код (полная программа), который я выложил 22 числа, у меня хорошо работает. Мигает только при воспроизведении трека. Выключается, когда не играет. PIR активирует случайную дорожку и начинает воспроизведение. Прослушал кучу мелодий за несколько часов. Извините, но я не знаю, почему у вас все еще возникают проблемы., @DrG

Есть кое-что, что я не уверен, что полностью понимаю, возможно, вы можете помочь мне с этим. О статусе myDFPlayer.isPlaying(): Разве это не будет myDFPlayer.isPlaying() != 1 ииграет()==0 тоже самое? Если статус равен 0, статус отличается от 1, поэтому он даст тот же результат, верно? Большое спасибо!, @Lahey Corey