Monday, 10 July 2017

Testing tone();

At the weekend, I quickly cobbled together another of my little break-out boards, this time for a piezo crystal transducer (or a buzzer to you and me). 

One thing this taught me is that although we all call these things buzzers - actually, they are just 'clickers'.  If you apply voltage to it, it just goes click.  The tone comes from applying and disconnecting power 1000 times a second, to get a 1KHz tone for example.  A real ''buzzer' has components and circuitry built into it, so that all you need to do is apply power, and you get a nice tone generated.

Anyway - I digress... That was not really the point of this post.  I found out something else, which wasn't really immediately evident to me from the Arduino Reference manual, and even looking at it again with hindsight - I still didn't find anything about it...

To generate a tone on an Arduino, simply connect a 'clicker' thingy (I'm just going to call it a buzzer) to an output enabled pin and GND (NB - the buzzers are polarity sensitive, and have the positive pin marked on the casing, or indicated with a red lead), and then there is a nice easy tone command that does the work of generating the square wave for you.  Typically, the code looks something like this...

// start sending the tone of toneFrequency Hz to the device on buzzerPin
    tone(buzzerPin, toneFrequency);
// keep doing it for the period toneDuration milliseconds
    delay(toneDuration);
// at the end of the toneDuration delay, stop sending the tone
    noTone(buzzerPin);


I was using this code in a little sketch to make a hospital heartbeat monitor type 'beep', and also flashing the LED in time with the beep.  It all worked fine, and I should really have left well alone at this point (if it ain't broke, don't fix it!)

But then, I found an alternate version of the tone command, that includes the duration as a third parameter.  Why would anyone go to the lengths of typing 3 lines of code, when one will do..?  So I tried it...

// Same function, but all in one command
  tone(buzzerPin, toneFrequency, toneDuration);
// No need for the delay() or noTone() commands!


It worked!  Well, at first glance, it seemed to have worked, but then I noticed something odd - my LED was no longer flashing.  Actually, it was, but only for the briefest of moments, and unless you covered up the adjacent power LED (yeah - ALL the LEDs are clustered together on my clone - and very bright - it's a bit of a pain sometimes) you really wouldn't notice it.

I wondered about the potential for the buzzer to be drawing too much voltage and not leaving enough for the LED, so I disconnected the the buzzer.  The LED was still only giving the faintest of flickers.  I wondered if the 100ms period was too quick, though my gut was already saying "of course it's not".  I went back to basics and installed Blink, and changed it to 100ms.  Yes it was fast, but the LED lit up properly.  So I went back to my sketch and changed the toneDuration to 5000 millis. No change in the LED, but something else odd was now happening - the normal round-trip duration of the loop() section of my sketch was about 3 seconds, including a 1 second delay at the end. I was expecting my tone to now run for 5 seconds, followed by 1 second pause, but it was running constantly.

Then, the penny dropped - including the toneDuration as a parameter on the tone command, appears to switch it to background operation.  That means that the sketch starts generating the tone, and can carry on with the rest of the lines of code while the tone is being sounded.  So, what was happening is that my LED was switching on, staying on for probably just a few microseconds while the tone command was being evaluated, and then switched straight off again.  furthermore, if the toneDuaration value exceeds the time it takes for the rest of the code in loop() to run through - including any delay() commands, then the 'next' tone starts sounding before the first has finished, so it sounds like it is going constantly.

So - just be a little bit careful with the two flavours of the tone command - they are not the same beast at all, and make sure you know whether you want the duration of your tone to play an integral part in the progression of your code, or if it can be set off and left to run independently while your code goes and does something else...  If you choose the latter option, make sure there is room in your loop() code for the tone to finish before the loop does.

No comments:

Post a Comment