Вопрос об использовании millis для сигнальных условий - Arduino

millis buzzer delay

Я новичок в программировании вообще и в 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 
  }  
}

, 👍0

Обсуждение

активный или пассивный зуммер? для пассивного зуммера вы можете использовать функцию tone (), где вы можете указать продолжительность. он не блокирует выполнение. https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/, @Juraj

@Juraj Спасибо за ваш повтор, мой друг, на самом деле это активный зуммер.., @Maher

Тогда почему вы переключаете вывод зуммера несколько раз без какого-либо промежутка времени в buzzerStart()? Для меня это не имеет особого смысла. Активный зуммер просто нужно включать и выключать (с помощью функции digitalWrite ()). Таким образом, вы можете заменить buzzerStart(5) одним digitalWrite(buzzer, ! digitalRead(buzzer);, @chrisl


1 ответ


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 (), когда программа уже гудит , не имеет никакого эффекта: запрос на запуск зуммера игнорируется. Это не единственный возможный выбор: вместо этого можно захотеть сбросить счетчик, чтобы жужжание длилось дольше. Выбор, который я сделал, произволен, и я сделал его только потому, что в вашем вопросе требования к программе не полностью указаны.

,