I have a simple circuit that makes use of the tone()
function to produce some sounds.
I also have a button, hooked with an interrupt function, that whenever is pressed, a variable changes.
Sometimes, when the button is pressed, a high pitched sound is produced. What is weird is that this does not happen every time.
You can take a look at this simulation: https://wokwi.com/projects/291958456169005577
If you press the buttons continuously, you will hear the sound.
Why is this sound triggered? Is there a way to mitigate this?
Perhaps making changes to the tone()
function? Or perhaps placing a low-pass filter - as this seems like a high frequency sound?
2 Answers 2
Here is the result of my investigation.
The problem is caused by two factors.
First one is the contact bounce of the switch.
Second one is inadequate pullup strength at the switch, but this may be a simulator issue.
The attached picture shows the data that was captured by the Wokwi logic analyzer module.
The top trace pair shows the tone when the switch bounce is turned off in the simulator.
The rest of the traces are labeled.
-
Thank you so much for this investigation! I did manage to solve it by using the solution you provided in a comment. Specifically, i used
delay(1);
aftertone()
.user1584421– user15844212023年04月23日 19:30:35 +00:00Commented Apr 23, 2023 at 19:30 -
proper switch debouncing is the real solution ... ignore switch transitions for 5 ms after the initial transitionjsotola– jsotola2023年04月23日 23:23:31 +00:00Commented Apr 23, 2023 at 23:23
My explanation for this issue is that the last pulse generated by the tone()
function is interrupted while the output is on a high level. This results in the last pulse being shorter than it should be to correspond to the desired sound frequency.
While the pulse length doesn't matter for a continuous output (where the pulse frequency determines the sound frequency), a single short pulse can be interpreted as a pulse of a higher frequency. According to Fourier theory at least its fundamental frequency will be higher than the one of the longer pulses.
Observations that might substantiate my theory:
- the issue happens randomly in ~50% of the cases (for a 50% duty cycle signal).
- the frequency of the erronous tone varies and is always higher than the desired frequency, depending on how short the trailing pulse is.
These seem to be the case for the simulation.
Possible fixes:
a) provide the tone()
function with the optional duration
argument and hope the library itself addresses this problem (which it actually might not as the issue is even in the simulation)
b) make sure to only use multiples of the square wave period for duration
, so the wave always stops on a low level
According to my theory, a low-pass filter will not work as a fix because the fault frequency can be close to the desired frequency and is the "primary signal", not just some low amplitude harmonic which would be easier to filter from a (much stronger) fundamental.
-
1Thank you so much for taking the time to investigate and create drawings! I solved this issue using jsotola's suggesting and placing
delay(1);
after the call totone()
.user1584421– user15844212023年04月23日 19:31:48 +00:00Commented Apr 23, 2023 at 19:31
tone()
function generates a square wave and according to Fourier theory a square wave naturaly contains a lot of higher harmonics. If you have an unsuitable actuator which resonates at those harmonics, it could explain such a behaviour...delay(1);
after the tone ... checking why that works