Использование millis() для создания временной последовательности событий
Я надеялся, что кто-нибудь сможет помочь мне с моей проблемой.
Я пытаюсь воспроизвести последовательность тонов без задержки. Поэтому я полагаюсь на 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);
}
}
@Sushyoshi, 👍1
Обсуждение2 ответа
Лучший ответ:
Вы слишком усложняете программу. Нет смысла вспоминать когда начиналась каждая из нот. Вам просто нужно помнить:
- какая нота сейчас играет
- когда вы начали играть эту ноту
Тогда логика 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
Ваш код пропускает (пропускает) первый оператор if в выходном коде, потому что его период времени еще не прошел.
Затем он начинает использовать startMillis_2, который еще не инициализирован (и может иметь любое значение), в следующем «если».
Инициализация startMillis_2 происходит только внутри первого оператора if, но этот код еще не выполнен.
То же самое касается startMillis_3 и 4.
Но я думаю, что в вашем коде есть что-то более фундаментальное. Вы выполняете все операторы «если» внутри цикла, который постоянно повторяется. Последовательности нет. Вы должны убедиться, что тон 2 может быть запущен только после тона 1 и так далее.
В том-то и дело, что я не умею. Как убедиться, что тон 2 начинается только после окончания тона 1. Я могу достичь этой цели с задержкой, но я буду очень ограничен в своем коде. Прямо сейчас мой код делает именно то, что я хотел, за исключением того, что задержки мешают входным сигналам моих потенциометров. Я обновил свой код в своем посте., @Sushyoshi
- Как справиться с rollover millis()?
- Использование millis() и micros() внутри процедуры прерывания
- ардуино - миллисекунды ()
- Кнопка с таймером переключения и функцией сброса времени + светодиод обратной связи
- Использовать timer0, не влияя на millis() и micros().
- Торговый автомат Arduino для мониторинга ввода монет в слот во время ожидания ввода пользователя
- Разделить два целых числа в результате чего получится число с плавающей запятой
- Влияет ли `millis()` на длинные ISR?
внимательно посмотрите на операторы
if
, @jsotolaВаше описание последовательности событий запутано ... это просто «Воспроизведение тона 1 в течение 1 с», «Воспроизведение тона 2 в течение 1 с», «Воспроизведение тона 3 в течение 1 с», «Воспроизведение тона 4 в течение 1 с», @jsotola
Я все еще очень новичок в этом. Было бы проще объяснить, что я хочу, так: Воспроизвести тон 1 в течение 1 с, после окончания воспроизведения начать воспроизведение тона 2 в течение 1 с .... и так далее. Я до сих пор не совсем понимаю, как использовать операторы if., @Sushyoshi
оператор
if
довольно прост... посмотрите на выражение в квадратных скобках()
... если это выражение истинно, то выполните команды, заключенные в фигурные скобки{}
, @jsotola