Issues with Serial input and buzzer

Hello,

I have an issue that I can't solve so any help is appreciated!

The code includes a function with two variables (number of repetition and duration).

The idea is for the active buzzer to play a different sequence depending on the character ('p' or 's') that is entered in the serial monitor by the user.

However, this doesn;t work as indented. If I press "p" or "s" I get a continuous beeping until I press again the same key where it stops beeping. More like an ON/OFF toggle.

I also included a wokwi but with a LED instead of an active buzzer but the begviour is the same of course. Thanks!

const int buzzerPin = A5; // Pin that the buzzer is connected to

char pyInput;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;

void setup() {

  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT); // Set Buzzer Pin A5 to OUTPUT.

  Serial.println("Hello Arduino\n");


}

void loop() {

  if (Serial.available() > 0) {

    pyInput = Serial.read();

    switch (pyInput) {
      case 'p':
        buzzerBeep(2, 300); // Beep once for 300ms
        break;

      case 's':
        buzzerBeep(8, 80); // Beep 4 times for 80ms each time
        break;
    }
  }
}

// Function for buzzer's sequence/ beeps
void buzzerBeep(int rep, long buzzer_interval) {

  static int buzzer_toggleCount = 0;
  static int buzzer_currentState = LOW;

  if (buzzer_toggleCount < rep) {
    currentMillis = millis();

    if (currentMillis - previousMillis >= buzzer_interval) {
      if (buzzer_currentState == LOW) {
        digitalWrite(buzzerPin, HIGH);
        buzzer_currentState = HIGH;
      } else {
        digitalWrite(buzzerPin, LOW);
        buzzer_currentState = LOW;
      }
      previousMillis = currentMillis;
      buzzer_toggleCount++;
    }
  }
}

  if (buzzer_toggleCount < rep) {

This should be a while so that the code loops inside the function

You also need to reset the value of pyInput after calling buzzerBeep so as to avoid it being called again

Thanks UKHeliBob,

Replacing the 'if' with 'while' will defeat the purpose of using millis() as it'll pause the execution, no?

Yes it will, but your current code won't work at all using an if because buzzer_toggleCount will always be less that top

You need to restructure your sketch so that it tests whether the required number of LED flashes has occurred and, if not, does another one

1 Like

Not sure what you mean. Could you please elaborate cause I'm far from expert :slight_smile:

If I simply call buzzerBeep() inside the loop, it behaves as expected without blocking the execution.

const int buzzerPin = A5; // Pin that the buzzer is connected to

char pyInput;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;

void setup() {

  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT); // Set Buzzer Pin A5 to OUTPUT.

    Serial.println("type 's' or 'p' below and hit enter\n");


}

void loop() {

buzzerBeep(10,1000);

 /* if (Serial.available() > 0) {

    pyInput = Serial.read();

    switch (pyInput) {
      case 'p':
        buzzerBeep(2, 300); // Beep once for 300ms 
        break;
        
      case 's':
        buzzerBeep(8, 80); // Beep 4 times for 80ms each time 
        break;
    }
  }*/

  Serial.println(millis());
}


// Function for buzzer's sequence/ beeps
void buzzerBeep(int rep, long buzzer_interval) {

  static int buzzer_toggleCount = 0;
  static int buzzer_currentState = LOW;

  if (buzzer_toggleCount < rep) {
    currentMillis = millis();

    if (currentMillis - previousMillis >= buzzer_interval) {
      if (buzzer_currentState == LOW) {
        digitalWrite(buzzerPin, HIGH);
        buzzer_currentState = HIGH;
      } else {
        digitalWrite(buzzerPin, LOW);
        buzzer_currentState = LOW;
      }
      previousMillis = currentMillis;
      buzzer_toggleCount++;
    }
  }
}

Take a look at this

const byte flashPin = 3;

void setup()
{
    Serial.begin(115200);
    pinMode(flashPin, OUTPUT);
}

void loop()
{
    static bool flashing = false;
    static byte targetCount;
    static int interval;
    if (!flashing)
    {
        if (Serial.available())
        {
            char inChar = Serial.read();
            if (inChar == 's')
            {
                targetCount = 4;
                interval = 500;
                flashing = true;
            }
            else if (inChar == 'p')
            {
                targetCount = 8;
                interval = 200;
                flashing = true;
            }
        }
    }
    if (flashing)
    {
        flashing = doFlashes(interval, targetCount);
    }
}

bool doFlashes(int interval, byte targetCount)
{
    static byte flashCount = 0;
    unsigned long currentTime = millis();
    static unsigned long prevFlashTime = 0;
    if (currentTime - prevFlashTime >= interval)
    {
        digitalWrite(flashPin, !digitalRead(flashPin));
        flashCount++;
        prevFlashTime = currentTime;

        if (flashCount >= targetCount)
        {
            flashCount = 0;
            return false;
        }
        else
        {
            return true;
        }
    }
}

Thank you! I will try it s soon as I get a moment. Also, I need to read it a few times to digest it. :slight_smile:

It seems to behave as expected. Many thanks!

Do you understand how it works and how it differs from your original sketch ?

I think so but I need to look into it a bit more carefully when I find some time. Hopefully, during the weekend.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.