Using tone function and pushbutton toggle problem

Hi:
I'm trying to use a momentary contact pushbutton to generate a click for about 1/10 of a second when the LED is on. There should be no click when the LED is off. The LED part works fine but I get nothing out of the tone function. Without the toggle code the system works fine. Can you help with this? I don't see what the problem is.
Thanks if you can help.
Bob

int LEDState = 0;
int LEDPin = 8;
int buttonPin = 12;
int buttonNew;
int buttonOld = 0;
int dt = 100;
int buzzerPin = 7;
int i;

void setup() {
  // put your setup code here, to run once:
  pinMode(LEDPin,OUTPUT);
  pinMode(buttonPin,INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  buttonNew = digitalRead(buttonPin);
  delay(dt);
  if(buttonOld == 0 && buttonNew ==1){
    if(LEDState == 0){
      digitalWrite(LEDPin,HIGH);
      for (i = 1; i < 10000;i++)
      {
        tone(buzzerPin,440,100);
        noTone;
      }
      LEDState = 1;
    }
    else{
      digitalWrite(LEDPin,LOW);
      LEDState = 0;
    }
  }
   buttonOld = buttonNew; 
}

At the very least, you probably meant

noTone();

if your desire was to stop the sounding tone.

Also, Tone() does not not block, so the duration can't matter if you immediately turn off the tone.

Also also 10000 iterations of something that appears to want to take 100 ms will go for quite a long time...

a7

Try this:

const int LEDPin = 8;
const int buttonPin = 12;
const int buzzerPin = 7;
const int dt = 100;
int buttonNew;
int buttonOld = 0;

void setup() 
{
  pinMode(LEDPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() 
{
  buttonNew = digitalRead(buttonPin);
  delay(dt);

  if (buttonOld == LOW && buttonNew == HIGH) 
  {
    if (digitalRead(LEDPin) == LOW) 
    {
      digitalWrite(LEDPin, HIGH);
      tone(buzzerPin, 440, 100);
    }
    else 
    {
      digitalWrite(LEDPin, LOW);
    }
  }
  buttonOld = buttonNew;
}

I'm trying to get a click about every one second for my wife to count as she does timed exercises. The LED was just to see if the toggle was working. It is a passive piezo buzzer. The code now reads as:

int LEDState = 0;
int LEDPin = 8;
int buttonPin = 12;
int buttonNew;
int buttonOld = 0;
int dt = 100;
int buzzerPin = 7;
int i;

void setup() {
  // put your setup code here, to run once:
  pinMode(LEDPin,OUTPUT);
  pinMode(buttonPin,INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  buttonNew = digitalRead(buttonPin);
  delay(dt);
  if(buttonOld == 0 && buttonNew ==1){
    if (LEDState == 0){
      digitalWrite(LEDPin,HIGH);
      tone (buzzerPin,440,100);
      LEDState = 1;
    }
    else{
      digitalWrite(LEDPin,LOW);
      LEDState = 0;
    }
  }
   buttonOld = buttonNew; 
}

THX. Now say what it is doing that it shouldn't, is isn't doing what it should.

At a glance you get a beep every time you press the button.

And the use of 100 milliseconds in two places might confuse operation. You have to (sometimes) hold the button down for 100.

Turn dt down to an entirely adequate 20 and see what you get.

Also your switch logic is bad, where did you get it? OK if you made it up, but if someone is legit offering this as valid they have mislead you.

Try this traditional logic seen everywhere:

void loop() {
  delay(20);    // very poor man's debounce: throttle the loop
  buttonNew = digitalRead(buttonPin);

  if (buttonOld != buttonNew) {

    if (buttonNew) {
      if (LEDState == 0) {
        digitalWrite(LEDPin,HIGH);
        tone (buzzerPin,440,100);
        LEDState = 1;
      }
      else {
        digitalWrite(LEDPin,LOW);
        LEDState = 0;
      }
    }

    buttonOld = buttonNew;
  }
}

a7

I'm trying to get a sharp tone about every second. I want the tone to start on the pushbutton and not stop until I press the button again. I believe that I could use an active buzzer but I have a passive one and I would like to use it.
I'm not getting the sound out of the buzzer at all with this sketch. I picked it up from another helper. It seems to me to be about the same.
Can I do what I want to do with the passive buzzer?

OK, do you mean one button press starts a continuous one beep per second, and the second press turns it off?

Active or passive buzzer makes no difference to the logic.

Use whatever buzzer you have, and first just get it to turn in and off making sound. You can follow the example called blink without delay:

Passive buzzer will need Tone() and noTone() where the LED is turned on and off.

Active buzzer will just use digitslRead() setting the output line the buzzer is on HIGH or LOW.

Once you have that blinking beeping or buzzing along merrily, use the toggle from the pushbutton and do or don't do the "blink" now beep code.

If you press the button when the buzzer is buzzing, send it a noTone() or appropriate digitalWrite() command to cut it off.

Or always be sure to turn it off when it isn't sounding… yeah, kidding, don't do that. It would be very annoying.

a7

Yes to your statement. "OK, do you mean one button press starts a continuous one beep per second, and the second press turns it off?"
The LED responds as staying waiting for the next button push. Then the LED is off until a further button push. The buzzer does nothing. I appreciate your continuing to try to help.
Bob

I will try the blinker code as you suggest.

Here's the idea. Once you figure out turning "blink without delay" into "beep without delay", that code can be conditionally executed. Here I just print or not, on and off by the button.

int LEDState = 0;
int LEDPin = 8;
int buttonPin = 12;
int buttonNew;
int buttonOld = 1;    // input_pullup are normaly high
int dt = 100;
int buzzerPin = 7;
int i;

void setup() {
  Serial.begin(9600);
  pinMode(LEDPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  static bool doIt;    // flag to inhibit/allow - initially false

// see if the button got presssed and fix the flag

  delay(20);    // very poor man's debounce: throttle the loop
  buttonNew = digitalRead(buttonPin);
  if (buttonOld != buttonNew) {

    if (buttonNew)
      doIt = !doIt;   // toggle the flag on button action (release)

    buttonOld = buttonNew;
  }

// now either do or don't <whatever> based on the flag

  static unsigned int counter;    // just so we can differentiate the spam lines this produces
  if (doIt) {
    Serial.print(counter);
    Serial.println(" do this stuff here!");
    counter++;
  }
}

I throttle the loop so it only runs 50 times a second, but that won't matter too much to blink (or beep) without delay.

Play with it here:

a7

Thanks alto777. This code works.

int LEDState = 0;
int LEDPin = 8;
int buttonPin = 12;
int buttonNew;
int buttonOld = 1;    // input_pullup are normaly high
int dt = 100;
int buzzerPin = 7;
int i;

void setup() {
  Serial.begin(9600);
  pinMode(LEDPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  static bool doIt;    // flag to inhibit/allow - initially false
  Serial.println("Bob  ");
// see if the button got presssed and fix the flag

  delay(20);    // very poor man's debounce: throttle the loop
  buttonNew = digitalRead(buttonPin);
  if (buttonOld != buttonNew) {

    if (buttonNew){
      doIt = !doIt;   // toggle the flag on button action (release)
      }
    buttonOld = buttonNew;
  }

// now either do or don't <whatever> based on the flag

  static unsigned int counter;    // just so we can differentiate the spam lines this produces
  if (doIt) {

       tone(buzzerPin,440);
       delay(100);
       digitalWrite(13,LOW);
       Serial.println("LOW");
       digitalWrite(buzzerPin,HIGH);
       digitalWrite(13,HIGH);
       Serial.println("HIGH");
       noTone(buzzerPin);
       delay(900);
    counter++;
  }  
  noTone(buzzerPin);
}

@StAugustine if you done and happy, I'm done. I don't argue with success.

But your lines of code doing the beeping and blinking are blocking. Meaning your pushbutton is sluggish... as you don't look at it but once a second when the beep/blink is being timed out (delay() driven).

Did you take a stab at coming to an understanding of how BWOD "blink without delay" accomplishes a slow periodic task at human speeds without blocking?

If you plan to add to this sketch or do something next-level in this hobby, the sooner you can competently write non-blocking code without relying on delay() for timing, the better. delay() is kinda like a crutch or training wheels.

Srsly, it isn't that hard - there is an Aha! moment and you life changes. I would not want to guess what large fraction of problems here can be laid off on the use of blocking code.

BWOD is the first step of a few, each of which will give you a real boost on your code chops. I will say I do like to see ppl get over this hump, and there is no perfect way to learn it, and no foolproof source for doing. It seems each must strukkle a bit with this, no matter how highly some think of their own. Tutorials.

Either way, good work.

a7

Hello alto777.

Done and happy for present. Are you talking about employing interrupts? The button is sluggish. Thanks so much for your help. My wife likes it and I guess that is the mark of success.

Hi alto777:

I've reviewed the code and see that they are using the millis() line of instructions. I'll give it a go. I see that you are removing the delay() times as they are the inactive times when if you needed an event you would have to wait for the delays to end. Thanks again.

Bob

No, def not. You won't need (shouldn't even think about) interrupts for this. They are so rarely appropriate and will be there when they are the solution: then will be time enough for what some might argue is the deeper waters.

This. Look at blink without delay, and for starters, you could literally cut and paste the "blinking without delay code" into the if (doIt) block.

Then my hope would be that it would be straight on to replacing the BWOD code with your custom version of a periodic process, beep 1 sient 9, with LED.

When you get to it. For now

My wife likes it and I guess that is the mark of success.

Is there another mark of success? :wink:

a7

Hi alto777:

I'm going to try to transition to the millis() concept. what is the purpose of counter ++ in the code that you showed me? Have a good day.

Bob

It's just so that as the sketch spams the serial output window with endless and frequent do this stuff here! lines that demonstrate that anything in the doIt block is getting regular attention (that would be beeping and blinking) each line has a sorta serial number so you can tell things are really happening.

Making counter a static variable means it is not a new variable every time you loop, thus will just increment.

There is no need for that when you replace the doIt guts with the BWOD logic, or your riff on that to make periodic beeping and blinking, which you may have already seen is structural identical. The attention will be obvious - you see and hear it.

I tag Serial output with something like that; a simpler alternate method what I sometimes remember to do is just print the value of millis(), like:

  if (doIt) {
    Serial.print(millis());  // just so we can differentiate the spam lines this produces
    Serial.println(" do this stuff here!");
  }

HTH

a7

Hi Alto777:

This is my latest small move to get the button and buzzer to work. I hope to add a bit of code each day.

bob

6493C48CA6C1403F86688D5B6A588C5A.png

int LEDState = 0;
int LEDPin = LED_BUILTIN;
int buttonPin = 12;
int buttonNew;
int buttonOld = 1;    // input_pullup are normaly high
int dt = 100;
int buzzerPin = 7;
int i;

void setup() {
  Serial.begin(9600);
  pinMode(LEDPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  static bool doIt;    // flag to inhibit/allow - initially false

// see if the button got presssed and fix the flag

  delay(20);    // very poor man's debounce: throttle the loop
  buttonNew = digitalRead(buttonPin);
  if (buttonOld != buttonNew) {

    if (buttonNew)
      doIt = !doIt;   // toggle the flag on button action (release)

    buttonOld = buttonNew;
  }

// now either do or don't <whatever> based on the flag

  static unsigned int counter;    // just so we can differentiate the spam lines this produces
  if (doIt) {
    Serial.print(counter);
    Serial.println(" do this stuff here!");
    digitalWrite(LEDPin,HIGH);
    counter++;
  }
  else{
    digitalWrite(LEDPin,LOW);
    Serial.println(" Bob ");
  }
}

Step by step.

I was able to copy the chunk that differs into my wokwi and execute your new block.

I think this thread I found might be worth a look.

a7