0

I am new to programming in general and to Arduino as well. I am working on a small project to improve my ability to write complete and kind of useful programming sketches.

I am facing a problem. I am using a few things in my circuit like 7-segment display and relays and several indicating LEDs and a buzzer.

Let's sat that when a condition occurs I want one LED to blink while everything still works fine and sends data to the display and controls relays, and I solved that with the millis function.

But the problem came when I tried to implement the same concept to the buzzer (which in my case I want to buzz for a pre-set amount of time, and then stop, without keeping buzzing all the time which might be too long), without using the delay function.

I tried many many code but nothing would work for me so far. Here is the simple code of my sketch. I hope you guys will help me find a solution

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 
  }  
}
3
  • 2
    active or passive buzzer? for passive buzzer you can use tone() function where you can specify the duration. it doesn't block execution. arduino.cc/reference/en/language/functions/advanced-io/tone
    – Juraj
    Commented Jan 31, 2022 at 13:53
  • @Juraj Thank you for your replay my friend, actually it is an active buzzer..
    – Maher
    Commented Jan 31, 2022 at 15:23
  • Then why are you toggling the buzzer pin multiple times without any time inbetween in buzzerStart()? Doesn't make much sense to me. An active buzzer just has to be turned on and off (via digitalWrite()). So you could replace buzzerStart(5) with a single digitalWrite(buzzer, !digitalRead(buzzer);
    – chrisl
    Commented Jan 31, 2022 at 16:10

1 Answer 1

1

You are missing a delay here:

for (byte i = 0; i < repeat; i++) {
    digitalWrite(buzzer, !digitalRead(buzzer));
}

Without the delay, the whole loop terminates so fast that you cannot hear anything.

Now, if you want non-blocking code, you should instead use the approach of the Blink Without Delay tutorial:

  • have the program remember the current state
  • when it's time to switch states (as determined by millis()), update the current state.

The difficulty is that, whereas the program state in that tutorial is trivial (either the LED is off or it's on), in your case it is more complex. In addition to the time of the last toggle, you have to keep track of:

  • whether the buzzer is off or on
  • whether it is supposed to be making sound
  • a counter for the buzzing cycles.

The approach I would use is to have a counter (let's call it buzzer_remaining) telling how many cycles it still has to complete. The counter would decrement when the pin goes LOW. When it reaches zero, the buzzing is done. Note that this choice implies that, when the condition for buzzing becomes true, we will start at the middle of a buzzing cycle.

Here is a tentative implementation of this approach:

const uint32_t buzzer_half_period = 500;  // 500 ms in each state
const uint8_t buzzer_count = 5;  // buzz for 5 cycles
uint8_t buzzer_remaining;        // remaining buzzing cycles
uint8_t buzzer_state;            // LOW or HIGH
uint32_t buzzer_last_toggle;     // millis() at last toggle time

void buzzer_start() {

    // Ignore request to start if we are already buzzing.
    if (buzzer_remaining > 0)
        return;

    // Initialize the buzzer state.
    buzzer_remaining = buzzer_count;
    buzzer_state = HIGH;
    digitalWrite(buzzer, buzzer_state);
    buzzer_last_toggle = millis();
}

// Call this periodically from loop().
void buzzer_update() {

    // Do nothing if we are not supposed to be buzzing.
    if (buzzer_remaining == 0)
        return;

    // Do nothing if it is too early to switch state.
    uint32_t now = millis();
    if (now - buzzer_last_toggle < buzzer_half_period)
        return;

    // Update the buzzer state.
    if (buzzer_state == LOW) {
        buzzer_state = HIGH;
    } else {
        buzzer_state = LOW;
        buzzer_remaining--;
    }
    digitalWrite(buzzer, buzzer_state);
    buzzer_last_toggle = now;
}

I resisted the temptation to put all this inside a class. It would be cleaner, but I think this “plain C” style of programming might be easier on a newcomer.

Note that calling buzzer_start() when the program is already buzzing has no effect: the request to start the buzzer is ignored. This is not the only possible choice: one could instead want to reset the counter in order for the buzzing to last longer. The choice I made is arbitrary, and I only made it because, in your question, the program requirements are not fully specified.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.