I've been trying to get this to work for a few days and tried various things that have just ended up with a garbled nasty constant sound coming from the piezo, and perhaps I can get a suggestion as to how to run this interval tone.
I've got a piezo hooked to pin 4 of the Arduino Micro and called is 'speaker', and I am able to make regular intervals of beeping happen, however I have a tone that requires different timing (as apposed to 250ms on, 250ms off, repeat.)
Below is the interval:
125ms @ 3000Hz
10ms Silence
125ms @ 3000Hz
145ms Silence
125ms @ 3000Hz
10ms Silence
125ms @ 3000Hz
145ms Silence
125ms @ 3000Hz
10ms Silence
125ms @ 3000Hz
645ms Silence
-Repeat-
This will just go into a function and will run when the function is called. I need to refrain from using delay() and I have tried quite a few things with millis(), but I haven't gotten it down correctly. I can also think of a couple ways to do this by making each on/off cycle its own function, but there has to be a more efficient way to accomplish this rather than bloating the code and taking up a lot more memory than is needed.
Any suggestions will be appreciated. Thank you.
Here is a sketch which will work but you have to add some code.
Figure out what has to be placed HERE.
I also put a bug in the code for you to find and correct.
Do you understand how everything works?
//Constants
const int silence[6] = {10,145,10,145,10,640}; //repeating sequence
const int playTime = 125; //duration of the tone
//RAM
unsigned long millisNow;
boolean playing;
int i;
int playingNow;
void setup()
{
Serial.begin(9600);
pinMode(4,OUTPUT);
tone(4,3000);
playing = true;
playingNow = millis();
i = 0;
} // END of setup()
void loop()
{
//Tone On timing
if (playing == true && (millis() - playingNow >= playTime))
{
noTone(4);
playing = false; //indicate tone not playing
millisNow = millis(); //gets ready for off timing
}
//Tone Off timing
if (playing == false)
{
if ( HERE >= silence[i])
{
i++; //point to next delay off time
if (i>5)
{
i = 0;
}
playing = true;
tone(4,3000);
playingNow = millis();
}
}
} // END of loop()
Well this is quite the exercise, I've come to understand arrays much better now, however I am unable to get this working. I'm pretty sure I have everything down correctly, but it doesn't operate correctly.
What I have right now is:
//Constants
const int speaker = 4; //piezo
const int silence[6] = {10,145,10,145,10,640}; //repeating sequence
const int playTime = 125; //duration of the tone
//RAM
unsigned long millisNow;
boolean playing;
int i;
int playingNow;
void setup()
{
Serial.begin(9600);
pinMode(speaker,OUTPUT);
tone(speaker,3000);
playing = true;
playingNow = millis();
i = 0;
void twentyspeaker()
{
//Tone On timing
if (playing == true && playingNow >= playTime)
{
noTone(speaker);
playing = false; //indicate tone not playing
millisNow = millis(); //gets ready for off timing
}
//Tone Off timing
if (playing == false)
{
if (millisNow >= silence[i])
{
i++; //point to next delay off time
if (i>5)
{
i = 0;
}
playing = true;
tone(speaker,3000);
playingNow = millis();
}
}
}
I'm assuming that the bug in the program is in: if (playing == true && (millis() - playingNow >= playTime))
As I can't figure out why playingNow would subtract millis(). However, if this is not the correct assumption, then why would millis() subtract playNow?
Then, I'm almost certain that millisNow is the "fill-in" piece.
As far as I can figure, it should be working, however I'm probably wrong. If I am correct though, then that would mean that there is something else that I need to fix somewhere else.
Is this piezo a "buzzer"?
A buzzer will produce audible noise, but will not be suitable to play a tune. If you want tunes (tones), try a speaker, or even an earphone. Maybe a small resistor would help if your speaker is 8 ohms.
The piezo buzzer is http://www.radioshack.com/product/index.jsp?productId=2062403 (http://www.radioshack.com/product/index.jsp?productId=2062403) and it works just fine when I apply a tone of 125ms at 3000Hz, 10ms silence, repeat. I can't imagine that it would work any differently when different duration of silence is applied, other than just the timing sounding different.
I have two other intervals working on it:
250ms @ 2500Hz
250ms Silence
Repeat
and
125ms @ 3000Hz
10ms Silence
Repeat
Both of which sound just as I had intended and can be easily achieved using the millis() timing (blink without delay type of function), I am just new to programming and wasn't able to figure out how to switch the silence durations to be different throughout the loop. Of which, I am still trying to work out right now, I still haven't worked out the issues in the above code.
You need a loop() function
This is OK.
What do you think this does?
I'm assuming that the bug in the program is in: if (playing == true && (millis() - playingNow >= playTime))
The bug I left in will only shows up after about 40-60 seconds of operation and won't stop things from working until then.
This is OK.
, I don't think so. Seems to be more than one "not OK"
int playingNow;
void setup()
{
Serial.begin(9600);
pinMode(speaker,OUTPUT);
tone(speaker,3000);
playing = true;
playingNow = millis();
Don't think millis() will work to well being saved into an int.
I still don't see the loop(function). And I will stop at those two problems right now.
Well I've already changed some of the variables to be unsigned long numbers just in case:
//Constants
const unsigned long silence[6] = {10,145,10,145,10,640}; //repeating sequence
const int playTime = 125; //duration of the tone
//RAM
unsigned long millisNow;
boolean playing;
int i;
unsigned long playingNow;
However, with the above code, it still just produces an almost constant squeal. It sounds like the noTone() is not being used, but I'm still working it out...
As for the loop(), it is:
void loop() {
displayDate();
}
The loop which is being discussed here is called inside of displayDate();
Its an alarm of sorts that plays if a countdown time is below 15 seconds and will continue to play until the time reaches 10 seconds.
@jackwp
It will work as is for 40=60s then fail so that's the bug.
Let brevik fix it though.
the missing loop() is in @brevik code.
So brevik, what has to go HERE
if (playing == true && (millis() - playingNow >= playTime))
HINT: it is similar to the above.
Now I did get the code to work with
if (millis() - millisNow >= silence[i])
However, I am still trying to envision the cycle of process and how the "millis()" part gets store and reset.
I'm guessing that this instance of millis() should actually be stored as a separate variable and that is why the loop will not function past 40 - 60 seconds.
For the application, I don't need the loop to go on for that long, but this is a really good opportunity for learning, so for that I thank you for the time and patience.
@brevik
I did get the code to work
Good for you!
Note: millis() returns the value in unsigned long format equal to the number of milliseconds since the Arduino has been on.
if (playing == true && (millis() - playingNow >= playTime))
Has the bug.
The problem is int playingNow; being of an integer.
It is not big enough to hold the value millis() since this is unsigned long.
Hence it should be unsigned long playinNow;
Would you know how to add to the sequence 900 128 etc?
How?
The question is, "is there anything in the code you do not understand"?
I don't need the loop to go on for that long
Well, you can adjust the code to have it run as long as you want.
PS
Make the following addition, what does this do and what use is it?
if (i>5)
{
i = 0;
}
Serial.println(silence[i]);
Ohh ok, so I was correct in changing the playingNow to an unsigned long number, as have gotten into the habit of always making any millis() variables into unsigned long numbers.
Now if I wanted to add more pauses, with different values, I would just add to the array:
const unsigned long silence[8] = {10,145,10,145,10,640,900,128};
and then change the comparison inside of the loop:
if (i>7)
{
i = 0;
}
To accommodate for the additional numbers so that it will go to the end of the array and make the pauses.
Now this array is accounting for the values from 0-7 and then the eighth value for null, correct?
I have not seen you full sketch, that shows the loop() function
You say:
As for the loop(), it is:
Code:
void loop() {
displayDate();
}
The loop which is being discussed here is called inside of displayDate();
Its an alarm of sorts that plays if a countdown time is below 15 seconds and will continue to play until the time reaches 10 seconds.
The loop is a standard function, and runs without being called. If it
is called inside of displayDate();,
, and displayDate() is called from within loop(); then you could run out of stack memory pretty fast.
PS
Make the following addition, what does this do and what use is it?
if (i>5)
{
i = 0;
}
Serial.println(silence[i]);
That should return the position inside of the silence array when the pause is initialized.
the eighth value for null,
You are thinking about a string of characters.
This array has no null termination, hence you are using 0-7 in your code to control things.
The purpose of the Serial.println(..) is it can be used to help debug your program.
i.e. you place lines like this at strategic locations to see if want you think is happening is really happening.
You can then remove them when your code is functional.
@jacwp
//Constants
const int silence[6] = {10,145,10,145,10,640}; //repeating sequence
const int playTime = 125; //duration of the tone
//RAM
unsigned long millisNow;
unsigned long playingNow;
boolean playing;
int i;
void setup()
{
Serial.begin(9600);
pinMode(4,OUTPUT);
tone(4,3000);
playing = true;
playingNow = millis();
i = 0;
} // END of setup()
void loop()
{
//Tone On timing
if (playing == true && (millis() - playingNow >= playTime))
{
noTone(4);
playing = false; //indicate tone not playing
millisNow = millis(); //gets ready for off timing
}
//Tone Off timing
if (playing == false)
{
if (millis()- millisNow >= silence[i])
{
i++; //point to next delay off time
if (i>5)
{
i = 0;
}
Serial.println(silence[i]);
playing = true;
tone(4,3000);
playingNow = millis();
}
}
} // END of loop()
Also:
You obviously would not code things like 5 or 7 directly, it would be better to use #define count 7 in your definitions part of you code. Then if (i>count) later in the sketch.
@larry, I am a bit confused I guess. I was wanting to see the script that the OP is having trouble with. Are you two sitting next to each other? How do yu have his script?
The OP showed a snippet
void loop() {
displayDate();
}
Which is not shown in the script you uploaded.
What makes you think the script you uploaded, is the script the OP is currently using?
I am a bit confused I guess.
Sorry, I just uploaded the sketch that I originally offered with the fixes.
EDIT:
In post #2 brevik was working off my Sketch not his (we never saw his).
Ok Larry, I see. I do appreciate all your input/suggestions.
I figure, you can lead the horse to water, but you can't make them drink. LOL, so what you offered him, may or may not be what he is running.
Lets keep plugging away at this.
Thanks, Jack
Ah string, yes, I got all jumbled up. I tried unsuccessfully working with strings last week.
As for the entire code, the whole thing will be too long to post the entire thing in one post, but the displayDate() function is:
//setting up seconds time conversion
#define secondsinaday 86400 //((60*60)*24)
#define secondsinhour 3600 //(60*60)
#define secondsinminute 60
long countpreviousMillis = 0; //stores count milliseconds
long countinterval = 1000; //1 second
void displayDate(){
unsigned long countcurrentMillis = millis();
if(countcurrentMillis - countpreviousMillis > countinterval) {
// save the last time counted
countpreviousMillis = countcurrentMillis;
totalsectime--; //decrement of 1 second
unsigned long sectime = totalsectime;
/*takes the totalsectime variable and converts it inside of this function
so that the time conversions do not interfere with the later functions */
unsigned long days = sectime/secondsinaday; //calculates seconds in a day
sectime = sectime % secondsinaday; //takes the remainder of the previous calculation
unsigned long hours = sectime/secondsinhour; //calculates seconds in an hour
sectime = sectime % secondsinhour; //takes the remainder of the previous calculation
unsigned long minutes = sectime/secondsinminute; //calculates seconds in a minute
unsigned long seconds = sectime % secondsinminute; //takes the remainder, and that is seconds
/*below takes the values generated from above and makes variables for each digit to display
based on on dividing the values by hundreds/tens/single numbers*/
unsigned long days_hundreds = days/100;
unsigned long days_tens = (days %100)/10;
unsigned long days_units = (days %100)%10;
unsigned long hours_tens = (hours %100)/10;
unsigned long hours_units = (hours %100)%10;
unsigned long minutes_tens = (minutes %100)/10;
unsigned long minutes_units = (minutes %100)%10;
unsigned long seconds_tens = (seconds %100)/10;
unsigned long seconds_units = (seconds %100)%10;
//sends digit to: 7221 device
//digit order
//variable from above calculations
//true/false for the decimal point
lc.setDigit(1,0,days_hundreds,false);
lc.setDigit(1,1,days_tens,false);
lc.setDigit(1,2,days_units,false);
lc.setDigit(0,0,hours_tens,false);
lc.setDigit(0,1,hours_units,false);
lc.setDigit(0,2,minutes_tens,false);
lc.setDigit(0,3,minutes_units,false);
lc.setDigit(0,4,seconds_tens,false);
lc.setDigit(0,5,seconds_units,false);
}
if(totalsectime==15){ //wrap-around when time reaches 15 seconds
displayWrap();
return;
}
if(totalsectime<=15){ //wrap-around when time reaches 15 seconds
lc.shutdown(0,false);
lc.shutdown(1,false);
}
if(totalsectime <=5 ) { //lights emitter LEDs when time reaches 5 seconds and keeps speaker solid
digitalWrite(emitters, HIGH);
}
else{
digitalWrite(emitters, LOW);
}
if(totalsectime > 20){
updatespeaker();
}
if(totalsectime > 5){ //colon blink function for normal countdown
colonBlink();
}
if(totalsectime < 21){
twentyspeaker();
}
if(totalsectime < 10){
tenspeaker();
}
if(totalsectime <= 0){
zerospeaker();
delay(2500);
displayFade();
genserOne();
displayWrap();
delay(5000);
displayWrap();
totalsectime = random(16756131);
}
}
I'm sure the code is bloated and inefficient, but it does operate currently, and I will work on making the code more efficient and memory conservative as I work on it. Still working on the learning curve.
I'm also using the LedControl Library for the 72xx display drivers to drive seven segment displays.
I didn't have any code previously to the suggestions, as I wasn't sure how to achieve what I wanted other than just regular intervals of on/off using millis().
It looks like I am just adding more confusion to this thread than help, so I will step aside. You two carry on, and good luck. Jack
I see the potential of the bug ;) that I earlier discussed.
millis() is unsigned long
long countpreviousMillis = 0; //stores count milliseconds
long countinterval = 1000; //1 second
OR
unsigned long countpreviousMillis = 0; //stores count milliseconds
unsigned long countinterval = 1000; //1 second
@jackwp
Thanks for participating.
Jackwp: Any input is always appreciated, I'm always happy to answer any questions that may clear up any confusion.
LarryD: you got me there, I have those millis() assigned as a long number by mistake. Fixed.
Visuals are always good, so here is a video of the code in action:
Beware, it may come out as very high-pitched sounding, check your volume.
http://youtu.be/HFCiaQTHPhE (http://youtu.be/HFCiaQTHPhE)
I do need to work out the timing of the audio and getting the audio function to stop looping at appropriate times, but at the moment, your suggestions solved my initial issue and got me up and running. Thank you very much for your assistance.
Nice little project.
Looks like it would fit on your wrist quite nicely ;)
Make sure you have some decoupling capacitors on the breadboard.
You may want to try these jumpers as they are multi colored and easily traced:
Haha yeah, I ran out of jumpers so I started to make some out of a spool of solid core wire, all the same color, which works for now, just as long as I don't take an extended break from the project. Then I'll forget where everything is.
The final project that I am aiming towards is going to look something like:
http://www.youtube.com/watch?v=rVJYx9rvMp4
Slowly but surely plugging away at getting it done. The Arduino forums have been a great help to me too. Everyone is very helpful here. Thanks again.