Go Down

Topic: Trying to program SOS sound with Piezo buzzer without using delay.  (Read 2302 times) previous topic - next topic

Ian_McElrath

Hey guys!  I'm trying to program my piezo buzzer to sound an SOS once triggered by a button without using any delays in my code.  Can anyone help?  Thanks!

robtillaart

Yes, if you post your code we can help you find the problem area's.

Blink without delay is a good starting point.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Jobi-Wan

Whether your buzzer should be on or off depends on how long ago the button was pressed.

So you need to mark the time when the button gets pressed, then in your loop calculate how much time has elapsed since. Then translate the elapsed time into a high or low (buzzer on or off).

Grumpy_Mike

Whether your buzzer should be on or off depends on how long ago the button was pressed.
Sorry that is totally wrong. That is not needed at all.

For producing stuff without delay
See my
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html
Or Robin2's several things at once
http://forum.arduino.cc/index.php?topic=223286.0

Jobi-Wan

Sorry that is totally wrong.
The part you quoted is actually a profound truth.

The part you didn't quote:
So you need to mark the time [.. etc ..]
..could be considered 'wrong' (if you want) because you don't need to do it this way; it is just one of the possible approaches.

But the idea of marking and measuring time to determine the buzzer state is not wrong. (A state machine does that too, but in a more indirect way.)



Code: [Select]
#define buttonPin 4
#define buzzerPin 3

unsigned long buttonTime = 0;
boolean buzzerState = false;

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

void loop()
{
  unsigned long elapsedTime;
  
  if (buttonTime)
  {
    // How long ago was the button pressed?
    elapsedTime = millis() - buttonTime;

    // This determines whether the buzzer should be on..
    switch (elapsedTime)
    { // ON for these value ranges.. (dit dit dit dah dah dah dit dit dit)
      case    0 ...  200: // These could be put in
      case  500 ...  700: // an array, to make the
      case 1000 ... 1200: // code a bit more compact
      case 1500 ... 2000: // and flexible.
      case 2300 ... 2800: // But it demonstrates how
      case 3100 ... 3600: // the mechanism works.
      case 3900 ... 4100:
      case 4400 ... 4600:
      case 4900 ... 5100:
        if (!buzzerState)
        {
          tone(buzzerPin,1000);
          buzzerState = true;
        }
        break;

      // OFF otherwise.
      default:
        if (buzzerState)
        {
          noTone(buzzerPin);
          buzzerState = false;
        }

        if (elapsedTime > 5100)
          buttonTime = 0; // Ready to accept new button press
        break;
    }
  }
  else if (digitalRead(buttonPin) == LOW)
  {
    buttonTime = millis();
  }
}

Grumpy_Mike

Quote
The part you quoted is actually a profound truth.
Rubbish. Read the original question again.
He is not trying to generate mores code through tapping it out on a button, he is trying to generate an SOS  message automatically, initiated by pressing a button. No one gives a flying fig how long the button is pressed for, just that once it is pressed the message is produced.

You seem to be totally out of touch with this project and its needs.

Quote
But the idea of marking and measuring time to determine the buzzer state is not wrong.
It is the way you are suggesting to do it:-
// These could be put in
// an array, to make the
// code a bit more compact
// and flexible.
// But it demonstrates how
// the mechanism works.
No it doesn't it is total crap!

Jobi-Wan

he is trying to generate an SOS  message automatically, initiated by pressing a button. No one gives a flying fig how long the button is pressed for, just that once it is pressed the message is produced.
That is exactly what I wrote.


Grumpy_Mike

It looks like you are not going to give up on this one. What you suggested is absolute *****.
Here is some code I knocked up that really works.
Code: [Select]

// Morse code state machine - By Mike Cook
// sends a fixed SOS when a button is pressed
// trigger button wired between input pin and ground

const byte outPin = 13;
const byte triggerPin = 2;
// message is SOS
int message[] = {1,1,1,3,2,2,2,3,1,1,1,3}; // dot = 1, dash = 2, inter letter space = 3, inter word space = 4
int messageLength = 12; // length of the dots, dashes, and spaces info
int messagePointer = 0;
unsigned long interval = 300; // mS per morse unit time
unsigned long workingInterval = 0;
unsigned long stateTime = 0;
boolean generatingMessage = false;

void setup() {
  pinMode(outPin, OUTPUT);
  pinMode(triggerPin, INPUT_PULLUP);
}

void loop() {
  if(generatingMessage) { // continue to send message
    if(millis()- stateTime > workingInterval) updateMessage();
  }
  else { // see if we should send a message
    if(digitalRead(triggerPin) == LOW) {
      generatingMessage = true;
      workingInterval = 0;
    }
  }
  // do other loop stuff here
}

void updateMessage(){
  // set up time to next call of this function
  if(message[messagePointer] == 1) workingInterval = interval;
  if(message[messagePointer] == 2) workingInterval = interval * 3;
  if(message[messagePointer] == 3) workingInterval = interval * 3;
  if(message[messagePointer] == 4) workingInterval = interval * 7;
  stateTime = millis();
  // toggle output
  if(message[messagePointer] == 1 || message[messagePointer] == 2){
   if(digitalRead(outPin) == LOW) {
     digitalWrite(outPin, HIGH);
   }
   else {
    digitalWrite(outPin, LOW);
    updatePointer();
   }
  }
   else {
    updatePointer();
  }
}

void updatePointer(){
  messagePointer++;
  if(messagePointer >= messageLength){ // end of message
    generatingMessage = false;
    messagePointer = 0;
  }
}



Now I suspect you will say this is exactly what you suggested. It might be in your head but it is not on the page.

Jobi-Wan

The code I posted works. You seem to suggest that it doesn't. I tested it before I posted it. Try it.
I'm sure yours works too.
Like I said, it is just one of the possible approaches.


I think mine is easier to follow, but I'm obviously biassed. It has one case per beep and very little extra bookkeeping.


This is the idea behind the code:
If you want to play an SOS sequence after you press a button, that means you're turning the buzzer on and off at times relative to when you pressed the button. In other words: "Whether your buzzer should be on or off depends on how long ago the button was pressed". (This is true regardless of the implementation.) If the elapsed time falls inside one of nine ranges (the nine beeps that form the SOS message) then the buzzer should be on, otherwise off.

The code I wrote follows this idea very closely and (in my mind) easy to see:
- Mark button press time.
- Calculate elapsed time.
- Check if it falls inside a 'beep'.
- Turn on/off buzzer accordingly.
It does these things and pretty much nothing else.



Again, I'm not saying that this is the only way. I'm also not saying that your way is wrong (or crap or five asterisks), but no, it is not exactly what I would have suggested.
What I posted is what I would suggest. Putting those ranges into an array would make the code more compact and more flexible, but not more obvious. That's why I didn't.



You vehemently state things that are just not true. Your track record suggests that you probably know they aren't true. So I will assume that you were just trying to get me to write down this explanation. Well .. it worked.

The buzzer timings depending on the button press time is not wrong, nor is it rubbish.
You suggest that my code cares about how long you press a button. It doesn't. It marks time only when the button is closed.
You suggest that it doesn't play the entire SOS sequence with one button press. It does play the entire sequence.
The switch with nine ranges does demonstrate the mechanism.
I am not out of touch with the project specs, but follow it to the letter.
In fact you and I made the same 2 assumptions that were not strictly specified:
1 - You have to be able to do it multiple times.
2 - Button presses are ignored while the sequence is playing.


Right now, OP has 2 working examples along with explanations.
Originally, I tried to have OP pick up on the idea, but I didn't intend to write/post the code. I guess neither did you.

Grumpy_Mike

Quote
The code I posted works. You seem to suggest that it doesn't. I tested it before I posted it. Try it.
No need I can see that it doesn't generate the proper spacing for mores code.
But basically it is very poor code. It falls far below the standard we expect here from someone trying to help.

Go Up