Tone on/off in continuous 1 sec intervals per buttonswitch

I want the buzzer every second for about 1/4 second (not continuous). I have a sketch thanks to arlo777 based on using millis() . It is a great sketch but I have one running on an Uno now that uses something close to what I have below but I dabbled with my code and can't recreate it. My wife finds the timing device very useful in counting during exercise. It buzzes when toggle is pushed and released and turns off on next toggle push and release.

//  This is a sketch to help keep track of exercise when exercising.  Many of the activities are based on holding something for so many seconds
//  or counting so many reps.  This will make the Arduino Uno send an activate signal to a buzzer every second.
int buzzerPin =11;
int buzzerState = 0;
int buttonPin = 6;
int buttonOld = 1;
int buttonNew;
int dt = 100;
 
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(buzzerPin,OUTPUT);
pinMode(buttonPin,INPUT_PULLUP);
}
 
void loop() {
    buttonNew = digitalRead(buttonPin);
    Serial.println(buttonNew);
    delay(dt);
    if((buttonOld == 1) && (buttonNew == 0)){
      if (buzzerState == 0){
        digitalWrite(13,HIGH);
        tone(buzzerPin,440);
        delay(90);
        buzzerState = 1;}
       else{
          digitalWrite(13,LOW);
          buzzerState = 0;
          noTone(buzzerPin);
          }}
       buttonOld = buttonNew;    
       delay(dt);
}

If your implementation uses delay() calls you will not be able to reliably detect the button toggle! This is why arlo777's implementation works reliably. Why not use that one?

If you use the Autoformat tool in the IDE, you will see that you have misplaced, I am as sure as I can be from my chaise longue sur la plage, the update to

On closer inspection, the sketch is a mess, and Autoformat and your finger on the code "playing computer" will let you see that it is doing exactly what you wrote, not what you hope.

While you might be able to hammer this into some kind of functioning shape, your reliance on delay() will continue to be an impediment to making progress. Here and in the future if you go further in this hobby.

Go as far back as you need to in your previous work and spend time with the recommended example codes until the light bulb goes off.

The key idea is to separate the examination of the pushbutton from the creation (or not) of the tone generation.

Both those things should be done at relatively high speed, usually each section deciding it isn't time (or conditions) to do anything but wait, or wait on the button.

No section should hog the resource that is your loop() frequency. delay() in this kind of programming is like a chef using deflavorants.

a7

I love alto777's solution. It works well and I would use it on the implementation if I didn't have it working somehow with my code with the delay. I cannot recover my sketch and simply want to know how I was able to accomplish it with the delay. I'm simply trying to learn more. I will always use the millis() functions in the future but my working code with delays is simply something I want to figure out how it is working. Thanks for input.
Bob

Hi alto777:
Don't understand the Autoformat tool. I love your solution I just want to learn more about how my code is working.
Bob

Well not mine so much as how it is (or can be) done.

What you need to do with your (not) working sketch is as I may have suggested:

Get real, real dumb and put your finger on the code and pretend like you are the computer executing your code line by line.

Make no assumptions that might mislead you - the code has no idea of what it is up to at any time other than blindly executing the next line of code.

In the IDE, use the menu item Tools/Auto Format or ⌘T or however the shortcut is in Windoze.

Auto Format will put your code into one of the common standards formats as far as indenting and a few other details is concerned.

void loop() {
  buttonNew = digitalRead(buttonPin);
  Serial.println(buttonNew);
  delay(dt);
  if ((buttonOld == 1) && (buttonNew == 0)) {
    if (buzzerState == 0) {
      digitalWrite(13, HIGH);
      tone(buzzerPin, 440);
      delay(90);
      buzzerState = 1;
    }
    else {
      digitalWrite(13, LOW);
      buzzerState = 0;
      noTone(buzzerPin);
    }
  }
  buttonOld = buttonNew;
  delay(dt);
}

I read this as

  • when the button goes down, turn on the tone and waste some time.

  • when the button goes down again, turn off the tone.

rinse and repeat.

The delay(90) serves no purpose. All it does is make turning off the tone with the second (or fourth, sixth &c.) button press v e r y s l u g g i s h.

I removed a few delay() calls that you sprinkled in there, but left the imporatant one (poor man's debounce) and the show stopper delay(90);

int LEDState = LOW;

int LEDPin = 6;

int buttonPin = 12;
int buttonNew;
int buttonOld = 1;    // input_pullup are normaly high

int buzzerPin = 7;
int i;

int buzzerState = 0;

void setup() {

  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  buttonNew = digitalRead(buttonPin);
  Serial.println(buttonNew);

  delay(30); // loop throttle / lazy or poor man's debounce

  if ((buttonOld == 1) && (buttonNew == 0)) {
    if (buzzerState == 0) {
      digitalWrite(13, HIGH);
      tone(buzzerPin, 440);
      delay(90);
      buzzerState = 1;
    }
    else {
      digitalWrite(13, LOW);
      buzzerState = 0;
      noTone(buzzerPin);
    }
  }

  buttonOld = buttonNew;
}

Please please - fingers on the code, play dumb, watch it here and see that the code is doing exactly what you wrote, and there is no food way to fix it without landing up with "my" solution.

a7

1 Like

This works fine but the buzzer is continuous. I've "fingered" through the code and I can see that the buzzer statement to turn on is only visited once. I need a quick buzzer/second but the 1 second needs to be distinguishable for hearing counting purposes. Your millis() sketch does the trick. Again, I'm just trying to figure out this way of doing it. The code is doing exactly what i wrote.
Thanks as usual alto777.

This is what I want to do based on a pushbutton switch.

int buzzerPin = 7;
int buttonPin = 12;
int LEDPin = 13;


void setup(){
  pinMode(13,OUTPUT);
  pinMode(buttonPin,INPUT_PULLUP);
  pinMode(7,OUTPUT);
  Serial.begin(9600);

}

void loop(){
  tone(buzzerPin,440);
  delay(90);
  noTone(buzzerPin);
  delay(900);
}

You can use the same pattern form the other thread:

You'll get one beep and one silent period every loop(), assuming you can work out the same kind of separation of using the switch to set or reset a flag, then respect that flag to guard or gate the doIt+ing of those four lines of code.

But you'll just end up with the same problem: the button will be seem very unresponsive, being as you are killing the loop() with actions that take a full second to complete.

Turning on the beeping would be nearly instant, as in that case you are whistling through the loop many many times a second, doing nothing but looking at the button.

I know this is a different way of thinking and I don't think anyone has the best way to explain it, just keep reading, reading code and googling. Trust me if you haven't already you'll get an AHA! and wonder why it was ever so hard.

Like too many things in programming, really hard until they are easy, no shortcuts available.

I recommend you stop torturing this dead horse and spend more time or ask more questions if you need to come to an understanding of how the one that works well, well, works.

a7

Hi alto777 and Todd:
Thanks to you two I have a working sketch on wokwi and on the Uno using the delay(). I've learned much from the two of you. I will always use the millis() approach in the future but this was a learning experience. The advice was great and your patience was fantastic. Thanks.
Here is the code:

/// This is a sketch to help keep track of exercise when exercising.  Many of the activities are based on holding something for so many seconds
//  or counting so many reps.  This will make the Arduino Uno send an activate signal to a buzzer every second.
int buzzerPin =11;
int buzzerState = 0;
int buttonPin = 6;
int buttonOld = 1;
int buttonNew;
int doIT = 0;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(buzzerPin,OUTPUT);
pinMode(buttonPin,INPUT_PULLUP);
}

void loop() {
   //put your main code here, to run repeatedly:
    // tone(pin,frequency,duration)
    buttonNew = digitalRead(buttonPin);
    delay(20);
    Serial.println(buttonNew);
   // Serial.print("NEW");
   
      if(buttonOld == 1 && buttonNew == 0){
        if(doIT == 0){
          doIT = 1;
        }
        else{

          doIT = 0;
        }

        Serial.println(doIT);
        }
  
    if(doIT == 1){
      tone(buzzerPin,440);
      delay(90);
      noTone(buzzerPin);
      delay(900);
    }
    else{noTone(buzzerPin);}
     buttonOld = buttonNew;

}

@StAugustine nice!

You can always share a link to your wokwi.

When I do, it is my habit to lock it using the menu item in the simulator, that way there is way less chance of inadvertently modifying the sim and throwing it out of sync with the thread where riptide it was revealed.

You did, I don't always copy the code to the thread, but probably should, given that it seems ppl don't link out to the sim. I think it is a great tool and take any opportunity to use and promote it.

riptide, haha. Spellcheck - I'm at the beach, some kind of warning served me mysteriously?

a7

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