Помогите с millis, чтобы получить точное время
По сути, я пытаюсь создать музыкальную шкатулку, которая активируется светом с помощью LDR. Когда он открыт, играет песня, в то время как сервопривод вращает фигурку взад и вперед, а светодиод тускнеет и загорается синхронно с сервоприводом. Код работает, когда я не включаю аналоговую запись для светодиода, но даже в этом случае время воспроизведения музыки невелико. Когда я включаю аналоговую запись для светодиода, музыка полностью искажается и вообще не работает. Есть ли какая-то очевидная ошибка, которую я совершил? Неужели миллис просто плохо следит за временем? Я уверен, что есть лучший способ подойти к этому в целом, но я все еще любитель arduino. Мой код работает, используя массив для заметок и продолжительности каждой из них. Я ссылаюсь на массив длительности и использую его в качестве динамических интервалов для своих миллиметров, чтобы сохранить время. Надеюсь, это имеет смысл, мой жаргон кодирования довольно прост!
#include <Servo.h>
//defining the value of the notes
#define NOTE_C4 262
#define NOTE_D4 294
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_G4 392
#define NOTE_A4 440
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_D5 587
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_G5 784
#define NOTE_A5 880
#define NOTE_B5 988
//order of the notes
int melody[] = {
NOTE_E4, NOTE_G4, NOTE_A4, NOTE_A4, 0,
NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, 0,
NOTE_C5, NOTE_D5, NOTE_B4, NOTE_B4, 0,
NOTE_A4, NOTE_G4, NOTE_A4, 0,
NOTE_E4, NOTE_G4, NOTE_A4, NOTE_A4, 0,
NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, 0,
NOTE_C5, NOTE_D5, NOTE_B4, NOTE_B4, 0,
NOTE_A4, NOTE_G4, NOTE_A4, 0,
NOTE_E4, NOTE_G4, NOTE_A4, NOTE_A4, 0,
NOTE_A4, NOTE_C5, NOTE_D5, NOTE_D5, 0,
NOTE_D5, NOTE_E5, NOTE_F5, NOTE_F5, 0,
NOTE_E5, NOTE_D5, NOTE_E5, NOTE_A4, 0,
NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, 0,
NOTE_D5, NOTE_E5, NOTE_A4, 0,
NOTE_A4, NOTE_C5, NOTE_B4, NOTE_B4, 0,
NOTE_C5, NOTE_A4, NOTE_B4, 0,
NOTE_A4, NOTE_A4,
NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, 0,
NOTE_C5, NOTE_D5, NOTE_B4, NOTE_B4, 0,
NOTE_A4, NOTE_G4, NOTE_A4, 0,
NOTE_E4, NOTE_G4, NOTE_A4, NOTE_A4, 0,
NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, 0,
NOTE_C5, NOTE_D5, NOTE_B4, NOTE_B4, 0,
NOTE_A4, NOTE_G4, NOTE_A4, 0,
NOTE_E4, NOTE_G4, NOTE_A4, NOTE_A4, 0,
NOTE_A4, NOTE_C5, NOTE_D5, NOTE_D5, 0,
NOTE_D5, NOTE_E5, NOTE_F5, NOTE_F5, 0,
NOTE_E5, NOTE_D5, NOTE_E5, NOTE_A4, 0,
NOTE_A4, NOTE_B4, NOTE_C5, NOTE_C5, 0,
NOTE_D5, NOTE_E5, NOTE_A4, 0,
NOTE_A4, NOTE_C5, NOTE_B4, NOTE_B4, 0,
NOTE_C5, NOTE_A4, NOTE_B4, 0,
NOTE_E5, 0, 0, NOTE_F5, 0, 0,
NOTE_E5, NOTE_E5, 0, NOTE_G5, 0, NOTE_E5, NOTE_D5, 0, 0,
NOTE_D5, 0, 0, NOTE_C5, 0, 0,
NOTE_B4, NOTE_C5, 0, NOTE_B4, 0, NOTE_A4,
NOTE_E5, 0, 0, NOTE_F5, 0, 0,
NOTE_E5, NOTE_E5, 0, NOTE_G5, 0, NOTE_E5, NOTE_D5, 0, 0,
NOTE_D5, 0, 0, NOTE_C5, 0, 0,
NOTE_B4, NOTE_C5, 0, NOTE_B4, 0, NOTE_A4
};
// duration of each note
int duration[] = {
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 375, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 375, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 125, 250, 125,
125, 125, 250, 125, 125,
250, 125, 250, 125,
125, 125, 250, 125, 125,
125, 125, 375, 375,
250, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 375, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 375, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 250, 125, 125,
125, 125, 125, 250, 125,
125, 125, 250, 125, 125,
250, 125, 250, 125,
125, 125, 250, 125, 125,
125, 125, 375, 375,
250, 125, 375, 250, 125, 375,
125, 125, 125, 125, 125, 125, 125, 125, 375,
250, 125, 375, 250, 125, 375,
125, 125, 125, 125, 125, 500,
250, 125, 375, 250, 125, 375,
125, 125, 125, 125, 125, 125, 125, 125, 375,
250, 125, 375, 250, 125, 375,
125, 125, 125, 125, 125, 3000
};
Servo myservo; // create servo object to control a servo
int servoPin = 9;
int ledPin = 11;
int buzzerPin = 3;
int sensorPin = A4;
int sweep = 0; // variable to control which direction the servo is moving
int sensorValue = 0;
int counter = 0; //a counter to keep track of which note the song is up to
float tempo = 1; // a variable for the tempo - lower number = faster temp (2 = double speed)
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
int threshold = 500;
void setup()
{
myservo.attach (servoPin);
pinMode (ledPin, OUTPUT);
pinMode (buzzerPin, OUTPUT);
pinMode (sensorPin, INPUT);
Serial.begin(9600);
}
void loop(){
sensorValue = analogRead (sensorPin);
if (sensorValue > threshold)
{
if (sweep == 0)
{
for (int pos = 0; pos <= 180; pos ++) // goes from 0 degrees to 180 degrees in steps of 1 degree
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
analogWrite(ledPin, map(pos, 0, 180, 0, 255)); //mapping the value from the for loop to get the full range of PWM for led fading
currentMillis = millis();
if (currentMillis - previousMillis > duration[counter]/tempo)
{
tone(buzzerPin, melody[counter], duration[counter]/tempo);
counter++;
previousMillis = currentMillis;
}
if (counter == 196)
{
counter = 0; //reset the counter so the song starts again
}
if (pos == 179)
{
Serial.println("SWEEP 1");
sweep = 1;
}
sensorValue = analogRead (sensorPin);
if (sensorValue < threshold)
{
break;
}
}
}
if (sweep == 1)
{
for (int pos = 180; pos >= 0; pos --) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
analogWrite(ledPin, map(pos, 0, 180, 0, 255));
currentMillis = millis();
if (currentMillis - previousMillis > duration[counter]/tempo)
{
tone(buzzerPin, melody[counter], duration[counter]/tempo);
counter++;
previousMillis = currentMillis;
}
if (counter == 196)
{
counter = 0;
}
if (pos == 1)
{
sweep = 0;
Serial.println("SWEEP 2");
}
sensorValue = analogRead (sensorPin);
if (sensorValue < threshold)
{
break;
}
}
}
}
if (sensorValue <= threshold) //if the light is low turn the servo back to starting point and stop doing anything
{
Serial.println("OFF");
noTone(buzzerPin);
myservo.write(0);
counter = 0;
}
}
@TonyStark, 👍2
Обсуждение1 ответ
Если вас все еще интересует переработанный код, вот ваш код с удаленными и реструктурированными циклами for, чтобы состояние отслеживалось/обновлялось соответствующим образом в цикле
void ()
, как показано ниже:
[your variable declaration code as given]
...
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
int threshold = 500;
int pos = 0;
int dir = 1;
void setup()
{
myservo.attach (servoPin);
pinMode (ledPin, OUTPUT);
pinMode (buzzerPin, OUTPUT);
pinMode (sensorPin, INPUT);
Serial.begin(9600);
pos = 0;
dir = 1;
previousMillis = millis();
}
void loop(){
sensorValue = analogRead (sensorPin);
if (sensorValue > threshold)
{
pos += dir;
if (pos == 180) || (pos == 0)
{
dir *= -1;
}
myservo.write(pos);
analogWrite(ledPin, map(pos, 0, 180, 0, 255));
currentMillis = millis();
if ((currentMillis - previousMillis) > duration[counter]/tempo)
{
tone(buzzerPin, melody[counter], duration[counter]/tempo);
counter += (counter > 195) ? -196 : 1;
previousMillis = currentMillis;
}
}
else
{
Serial.println("OFF");
noTone(buzzerPin);
myservo.write(0);
counter = 0;
pos = 0;
dir = 1;
}
}
- Как справиться с rollover millis()?
- Использовать timer0, не влияя на millis() и micros().
- Arduino Мигает двумя светодиодами без задержки (количество повторений)
- Как отслеживать миллисекунды в спящем режиме
- Запуск двигателя постоянного тока в течение заданного промежутка времени
- Как запустить 4 светодиода последовательно на основе кнопочного входа?
- Использование mills() вместо задержки() на реле, не обеспечивающих надежное переключение
- Когда GPS не видит спутники, как я могу продолжать отмечать плавное время?
Какую плату вы используете? Попробуйте переместить светодиод на вывод 5, 6 или 10 (в Uno), " тон " и "Аналоговая запись" будут использовать один и тот же таймер на выводах 3 и 11 в Uno, что звучит проблематично., @Mat
Что сказал Мэт. Кроме того, время воспроизведения музыки находится внутри цикла for, который управляет сервоприводом; вы также можете отделить их и настроить таймер миллиса для музыки и таймер миллиса для сервопривода, чтобы цикл выполнял свою работу без цикла for. Это не решит проблему с таймером, но код будет намного короче и проще для чтения, а музыка и тайминги сервопривода будут независимыми (но настраиваемыми). Я опубликую код, который покажет, как это сделать, в ответе, если вы хотите., @ocrdu
@Mat Arduino pin 10 использует тот же таймер для ШИМ, что и библиотека сервоприводов (таймер 1). Поэтому я бы придерживался вывода Arduino 5 или 6 для светодиода., @Gerben
@Гербен: а, хорошая мысль. Или, может быть, просто поместите светодиод на тот же вывод, что и сервопривод, если он просто должен быть включен, когда сервопривод движется. Освобождает таймер :-), @Mat