Вопрос об использовании millis для сигнальных условий - Arduino
Я новичок в программировании вообще и в Arduino в том числе. Я работаю над небольшим проектом, чтобы улучшить свою способность писать полные и полезные скетчи программирования.
Я столкнулся с проблемой. Я использую в своей схеме несколько вещей, таких как 7-сегментный дисплей, реле, несколько индикаторных светодиодов и зуммер.
Предположим, что при возникновении какого-то условия я хочу, чтобы один светодиод мигал, в то время как все еще работает нормально и отправляет данные на дисплей и управляет реле, и я решил это с помощью функции millis.
Но проблема возникла, когда я попытался реализовать ту же концепцию для зуммера (который в моем случае я хочу жужжать в течение заданного промежутка времени, а затем остановиться, не продолжая жужжать все время, что может быть слишком долго), без использования функции задержки
.
Я перепробовал много кода, но пока ничего не получалось. Вот простой код моего скетча. Я надеюсь, что вы, ребята, поможете мне найти решение
const byte buzzer = 13; // buzzer_PIN
const byte switch1 = 3; // PUSH-BUTTON PIN
/* please NOTE:
that the switch in my project will actually represent a condition to start the buzzer alarm, then maybe that condition will not exist, and after that the condition might come back and need the buzzer again
*/
unsigned const int delaytime = 500; // delay time needed between on and off states for the buzzer
unsigned long previousBuzz = 0; // Variable for millis
unsigned long currentTime = millis();
boolean buzzPreState = true; // Boolean made to avoid repetition for the buzzer when not needed
void setup() {
pinMode(buzzer,OUTPUT);
pinMode(switch1,INPUT_PULLUP);
}
void loop() {
unsigned long currentTime = millis();
int switchVal = digitalRead(switch1);
if (switchVal == LOW && currentTime - previousBuzz > delaytime && buzzPreState == true) {
previousBuzz = currentTime;
buzzPreState = false;
buzzerStart(5);
buzzPreState = true;
}
}
void buzzerStart(int repeat) {
for (byte i=0; i<repeat; i++) {
digitalWrite(buzzer, !digitalRead(buzzer)); // to switch buzzer ON and OFF alternatively
}
}
@Maher, 👍0
Обсуждение1 ответ
Здесь вы упускаете задержку:
for (byte i = 0; i < repeat; i++) {
digitalWrite(buzzer, !digitalRead(buzzer));
}
Без задержки весь цикл завершается так быстро, что вы ничего не слышите.
Теперь, если вам нужен неблокирующий код, вместо этого вы должны использовать подход учебника Blink Without Delay:
- пусть программа запомнит текущее состояние
- когда придет время переключать состояния (как определено
millis()
), обновите текущее состояние.
Трудность в том, что, хотя состояние программы в этом учебнике тривиально (либо светодиод выключен, либо включен), в вашем случае оно более сложное. В дополнение к времени последнего переключения, вы должны отслеживать:
- независимо от того, выключен или включен зуммер
- должен ли он издавать звук
- счетчик циклов жужжания.
Подход, который я бы использовал, состоит в том, чтобы иметь счетчик (назовем его
buzzer_remaining
) сообщает, сколько циклов ему еще предстоит выполнить.
Счетчик будет уменьшаться, когда контакт опустится НИЗКО
. Когда он достигает
нуля, жужжание прекращается. Обратите внимание, что этот выбор подразумевает, что, когда
условие жужжания станет истинным, мы начнем с середины цикла
жужжания.
Вот предварительная реализация этого подхода:
const uint32_t buzzer_half_period = 500; // 500 мс в каждом состоянии
const uint8_t buzzer_count = 5; // жужжание в течение 5 циклов
uint8_t buzzer_remaining; // оставшиеся циклы жужжания
uint8_t buzzer_state; // НИЗКИЙ или ВЫСОКИЙ
uint32_t buzzer_last_toggle; // millis() в последнее время переключения
void buzzer_start() {
// Игнорировать запрос на запуск, если мы уже жужжим.
if (buzzer_remaining > 0)
return;
// Инициализировать состояние зуммера.
buzzer_remaining = buzzer_count;
buzzer_state = HIGH;
digitalWrite(buzzer, buzzer_state);
buzzer_last_toggle = millis();
}
// Вызывайте это периодически из loop().
void buzzer_update() {
// Ничего не делай, если мы не должны жужжать.
if (buzzer_remaining == 0)
return;
// Ничего не делайте, если слишком рано переключать состояние.
uint32_t now = millis();
if (now - buzzer_last_toggle < buzzer_half_period)
return;
// бновите состояние зуммера.
if (buzzer_state == LOW) {
buzzer_state = HIGH;
} else {
buzzer_state = LOW;
buzzer_remaining--;
}
digitalWrite(buzzer, buzzer_state);
buzzer_last_toggle = now;
}
Я сопротивлялся искушению поместить все это в класс. Это было бы чище, но я думаю, что этот стиль программирования “plain C” может быть проще для новичка.
Обратите внимание, что вызов buzzer_start ()
, когда программа уже гудит
, не имеет никакого эффекта: запрос на запуск зуммера игнорируется. Это не
единственный возможный выбор: вместо этого можно захотеть сбросить счетчик,
чтобы жужжание длилось дольше. Выбор, который я сделал, произволен,
и я сделал его только потому, что в вашем вопросе требования к программе
не полностью указаны.
- Использование задержки 1 мс () в цикле for для проверки входных данных.. Плохо?
- Как независимо запускать позиционные и непрерывные сервоприводы с помощью millis()?
- Использование millis вместо задержки перезагрузки реле
- Как справиться с rollover millis()?
- Использование millis() и micros() внутри процедуры прерывания
- Цепь с зуммером не работает
- ардуино - миллисекунды ()
- Пассивный зуммер работает с AnalogWrite(), но не с DigitalWrite(). Он также имеет постоянный статический шум.
активный или пассивный зуммер? для пассивного зуммера вы можете использовать функцию
tone ()
, где вы можете указать продолжительность. он не блокирует выполнение. https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/, @Juraj@Juraj Спасибо за ваш повтор, мой друг, на самом деле это активный зуммер.., @Maher
Тогда почему вы переключаете вывод зуммера несколько раз без какого-либо промежутка времени в
buzzerStart()
? Для меня это не имеет особого смысла. Активный зуммер просто нужно включать и выключать (с помощью функции digitalWrite ()). Таким образом, вы можете заменитьbuzzerStart(5)
однимdigitalWrite(buzzer, ! digitalRead(buzzer);
, @chrisl