Использование millis() для создания временной последовательности событий

millis programming-sequence

Я надеялся, что кто-нибудь сможет помочь мне с моей проблемой.

Я пытаюсь воспроизвести последовательность тонов без задержки. Поэтому я полагаюсь на millis(). Однако я еще не добился успеха, и после прочтения нескольких руководств по использованию millis() я не смог найти ни одного, охватывающего последовательности событий. Я пытаюсь сделать следующее:

  • Воспроизвести мелодию 1 в течение 1 сек.
  • Через 1 секунду (время, в течение которого воспроизводится тон 1) воспроизводится тон 2.
  • Через 1 секунду (время, в течение которого воспроизводится тон 2) воспроизводится тон 3.
  • Через 1 секунду (время, в течение которого воспроизводится тон 3) воспроизводится тон 4.

С текущим кодом, который у меня есть, кажется, что все воспроизводится одновременно и на самом деле не учитывает мои операторы IF.

Код:

#include "pitches.h"

int notes[]={
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2, 
NOTE_C3, 
NOTE_CS3,
NOTE_D3, 
NOTE_DS3,
NOTE_E3, 
NOTE_F3,
NOTE_FS3,
NOTE_G3, 
NOTE_GS3, 
NOTE_A3,  
NOTE_AS3, 
NOTE_B3,  
NOTE_C4,  
NOTE_CS4, 
NOTE_D4,  
NOTE_DS4, 
NOTE_E4,  
NOTE_F4,  
NOTE_FS4, 
NOTE_G4,  
NOTE_GS4, 
NOTE_A4,  
NOTE_AS4, 
NOTE_B4,  
NOTE_C5,  
NOTE_CS5, 
NOTE_D5,  
NOTE_DS5, 
NOTE_E5,  
NOTE_F5,  
NOTE_FS5, 
NOTE_G5,  
NOTE_GS5, 
NOTE_A5,  
NOTE_AS5, 
NOTE_B5,  
NOTE_C6,  
NOTE_CS6, 
NOTE_D6,  
NOTE_DS6, 
NOTE_E6,  
NOTE_F6,  
NOTE_FS6, 
NOTE_G6,  
NOTE_GS6, 
NOTE_A6,  
NOTE_AS6, 
NOTE_B6,  
NOTE_C7,  
NOTE_CS7, 
NOTE_D7,  
NOTE_DS7, 
NOTE_E7,  
NOTE_F7,  
NOTE_FS7, 
NOTE_G7,  
NOTE_GS7, 
NOTE_A7,  
NOTE_AS7, 
NOTE_B7,  
NOTE_C8, 
NOTE_CS8,
NOTE_D8,  
NOTE_DS8
};

int speakerPin = 3;

 #define N_BUTTONS 8


int button_pins[N_BUTTONS] = {6, 7, 8, 9, 10, 11, 12, 13}; // Putting button_pins into an array

int Pitches[N_BUTTONS] = {0}; // Define array to hold the pitch. Setting it to 0.

long Durations[N_BUTTONS]; // Define array to hold the duration of the note. Setting it to 500.

unsigned long startMillis;
unsigned long startMillis_2;
unsigned long startMillis_3;
unsigned long startMillis_4;
unsigned long currentMillis;
unsigned long period = 1000;



void setup() {

Serial.begin(9600);

for(int pin : button_pins) pinMode(pin, INPUT); // Define the input pins for button_pins

startMillis = millis();

}



void loop() {

for (int button=0; button<N_BUTTONS ; button++){
  if(digitalRead(button_pins[button])){
    Pitches[button] = analogRead(A0)/13;   // As we have 77 pitches we divide the max Potentiometer value by 77. This equals 13.
    Durations[button] = analogRead(A1)*4;
   }
  }
////////////////////OUTPUT CODE////////////////////Sound generation code /////////////////////////////////

unsigned long currentMillis = millis(); // Gets the current time

if (currentMillis - startMillis >= period)  // Start event after 1 second
  {  
  tone(speakerPin, notes[Pitches[0]], period); 
  Serial.print("pitch1= ");
  Serial.println(Pitches[0]);
  Serial.print("duration1= ");
  Serial.println(period);
  Serial.print("millis = ");
  Serial.println(currentMillis);
  startMillis_2 = currentMillis;   // Saves the current time into the variable
  Serial.print("startMillis_2 = ");
  Serial.println(startMillis_2);
  }


if (currentMillis - startMillis_2 >= period) 
  {
  tone(speakerPin, notes[Pitches[1]], period); 
  Serial.print("pitch2= ");
  Serial.println(Pitches[1]);
  Serial.print("duration2= ");
  Serial.println(period);
  startMillis_3 = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis_3 = ");
  Serial.println(startMillis_3);
  }


if (currentMillis - startMillis_3>= period) 
  {
  tone(speakerPin, notes[Pitches[2]], period); 
  Serial.print("pitch3= ");
  Serial.println(Pitches[2]);
  Serial.print("duration3= ");
  Serial.println(period);
  startMillis_4 = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis_4 = ");
  Serial.println(startMillis_4);
  }

unsigned long startMillis_4;

if (currentMillis - startMillis_4 >= period) 
  {
  tone(speakerPin, notes[Pitches[3]], period); 
  Serial.print("pitch4= ");
  Serial.println(Pitches[3]);
  Serial.print("duration4= ");
  Serial.println(period);
  startMillis = currentMillis;
  Serial.print("millis = ");
  Serial.println(currentMillis);
  Serial.print("startMillis = ");
  Serial.println(startMillis);
  }

}

Мне удалось запустить код с задержкой. Это работает, но я очень ограничен в своих возможностях, если захочу большего. Я прочитал все ответы и комментарии, но все еще не смог найти решение для millis(), так как моя основная проблема заключалась в том, как запустить тон 2 и так далее. Я могу заставить первый тон воспроизводиться в цикле и исправлять интервалы, но я не понимаю, как вызвать начало тона 2. Вот мой код с задержкой. Если кто-нибудь может помочь мне использовать millis() специально для запуска тона 2, это было бы очень полезно.

ИЗМЕНИТЬ. Новый код:

#include "pitches.h"

int notes[]={
0,  
NOTE_B1,
NOTE_C2,
NOTE_CS2,
NOTE_D2,
NOTE_DS2,
NOTE_E2,
NOTE_F2,
NOTE_FS2,
NOTE_G2,
NOTE_GS2,
NOTE_A2,
NOTE_AS2,
NOTE_B2, 
NOTE_C3, 
NOTE_CS3,
NOTE_D3, 
NOTE_DS3,
NOTE_E3, 
NOTE_F3,
NOTE_FS3,
NOTE_G3, 
NOTE_GS3, 
NOTE_A3,  
NOTE_AS3, 
NOTE_B3,  
NOTE_C4,  
NOTE_CS4, 
NOTE_D4,  
NOTE_DS4, 
NOTE_E4,  
NOTE_F4,  
NOTE_FS4, 
NOTE_G4,  
NOTE_GS4, 
NOTE_A4,  
NOTE_AS4, 
NOTE_B4,  
NOTE_C5,  
NOTE_CS5, 
NOTE_D5,  
NOTE_DS5, 
NOTE_E5,  
NOTE_F5,  
NOTE_FS5, 
NOTE_G5,  
NOTE_GS5, 
NOTE_A5,  
NOTE_AS5, 
NOTE_B5,  
NOTE_C6,  
NOTE_CS6, 
NOTE_D6,  
NOTE_DS6, 
NOTE_E6,  
NOTE_F6,  
NOTE_FS6, 
NOTE_G6,  
NOTE_GS6, 
NOTE_A6,  
NOTE_AS6, 
NOTE_B6,  
NOTE_C7,  
NOTE_CS7, 
NOTE_D7,  
NOTE_DS7, 
NOTE_E7,  
NOTE_F7,  
NOTE_FS7, 
NOTE_G7,  
NOTE_GS7, 
NOTE_A7,  
NOTE_AS7, 
NOTE_B7,  
NOTE_C8, 
NOTE_CS8,
NOTE_D8,  
NOTE_DS8
};

int speakerPin = 3;

#define N_BUTTONS 8

// Input variables definitions

int button_pins[N_BUTTONS] = {6, 7, 8, 9, 10, 11, 12, 13}; // Putting button_pins into an array

int Pitches[N_BUTTONS] = {0}; // Define array to hold the pitch. Setting it to 0.

long Durations[N_BUTTONS]; // Define array to hold the duration of the note. Setting it to 500.


void setup() {

Serial.begin(9600);

for(int pin : button_pins) pinMode(pin, INPUT); // Define the input pins for button_pins


}

void loop() {
int tempo = analogRead(A2);
for (int button=0; button<N_BUTTONS ; button++){
  if(digitalRead(button_pins[button])){
    Pitches[button] = analogRead(A0)/13;   // As we have 78 pitches we divide the max Potentiometer value by 77. This equals 13.
    Durations[button] = (analogRead(A1)*4) + tempo;
   }
  }
////////////////////OUTPUT CODE////////////////////Sound generation code /////////////////////////////////
  for (int button=0; button <N_BUTTONS ; button++){
  tone(speakerPin, notes[Pitches[button]], Durations[button]);
  delay(tempo);
  Serial.print("Pitch");
  Serial.print(button);
  Serial.print(" = ");
  Serial.println(Pitches[button]);
  Serial.print("Duration");
  Serial.print(button);
  Serial.print(" = ");
  Serial.println(Durations[button]);
  Serial.println(tempo);
  }
}

, 👍1

Обсуждение

внимательно посмотрите на операторы if, @jsotola

Ваше описание последовательности событий запутано ... это просто «Воспроизведение тона 1 в течение 1 с», «Воспроизведение тона 2 в течение 1 с», «Воспроизведение тона 3 в течение 1 с», «Воспроизведение тона 4 в течение 1 с», @jsotola

Я все еще очень новичок в этом. Было бы проще объяснить, что я хочу, так: Воспроизвести тон 1 в течение 1 с, после окончания воспроизведения начать воспроизведение тона 2 в течение 1 с .... и так далее. Я до сих пор не совсем понимаю, как использовать операторы if., @Sushyoshi

оператор if довольно прост... посмотрите на выражение в квадратных скобках ()... если это выражение истинно, то выполните команды, заключенные в фигурные скобки {}, @jsotola


2 ответа


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

1

Вы слишком усложняете программу. Нет смысла вспоминать когда начиналась каждая из нот. Вам просто нужно помнить:

  • какая нота сейчас играет
  • когда вы начали играть эту ноту

Тогда логика loop() становится простой: «если мы закончили с текущую ноту, затем начните играть следующую». В коде:

ОБНОВЛЕНО: изменен код, чтобы включить цикл сканирования кнопок.

int current_button;
uint32_t note_started;

void loop() {
    // Отрегулируйте заметки о нажатиях кнопок.
    for (int button = 0; button < N_BUTTONS; button++) {
        if (digitalRead(button_pins[button])) {
            // Поскольку у нас есть 78 шагов, мы делим максимальное значение потенциометра
            // значение на 77. Это равно 13.
            Pitches[button] = analogRead(A0)/13;
            Durations[button] = analogRead(A1)*4;
        }
    }

    // Мы закончили с текущей заметкой?
    uint32_t now = millis();
    int tempo = analogRead(A2);
    if (now - note_started >= Durations[current_button] + tempo) {

        // Затем переходим к следующей ноте.
        ++current_button;

        // Закончили мелодию?
        if (current_button == N_BUTTONS) {
            current_button = 0;  // затем перезапустить сначала
        }

        // Воспроизвести ноту.
        tone(speakerPin,
                Pitches[current_button], Durations[current_button]);

        // Обратите внимание, когда это началось.
        note_started = now;
    }
}
,

Спасибо за ваш комментарий. Мне потребовалось некоторое время, чтобы понять ваш код, но я не могу понять, как адаптироваться к моему коду. Массив моих шагов — это переменная, зависящая от кнопки и потенциометра. Каждая сыгранная подача выбирается моим пользователем. Длительность ноты также является входной переменной с потенциометром и кнопкой. Взгляните на мой код ниже. Я предоставил тот, который использует задержки. Спасибо., @Sushyoshi

Спасибо. Ваш код работает по назначению. хотя мне нужно было бы настроить некоторые вещи, например, как контролировать темп, но в целом это отличное решение., @Sushyoshi


0

Ваш код пропускает (пропускает) первый оператор if в выходном коде, потому что его период времени еще не прошел.

Затем он начинает использовать startMillis_2, который еще не инициализирован (и может иметь любое значение), в следующем «если».

Инициализация startMillis_2 происходит только внутри первого оператора if, но этот код еще не выполнен.

То же самое касается startMillis_3 и 4.

Но я думаю, что в вашем коде есть что-то более фундаментальное. Вы выполняете все операторы «если» внутри цикла, который постоянно повторяется. Последовательности нет. Вы должны убедиться, что тон 2 может быть запущен только после тона 1 и так далее.

,

В том-то и дело, что я не умею. Как убедиться, что тон 2 начинается только после окончания тона 1. Я могу достичь этой цели с задержкой, но я буду очень ограничен в своем коде. Прямо сейчас мой код делает именно то, что я хотел, за исключением того, что задержки мешают входным сигналам моих потенциометров. Я обновил свой код в своем посте., @Sushyoshi