I have a simple project for my arduino : light some leds when i send a certain frequency from my smartphone through the jack output . For example , I play a simple audio file generated with a frequency generator (it generates sinwaves, sawtooth, quadrate waves...) at 1kHz --> a red led turns on I play another frequency (5kHz) --> a green led turns on. I read similar questions , but they needed a precise reading of the signal frequency, so they had to convert from AC to DC and from 700mV to 2,5V, is it necessary in my case ? I can also prepare a track with a program called audacity with the current remaining always positive but oscillating between 0 and 0,7 mV. How can i realize my project in the simplest way possible ?

Thank you

• It might be easier use a single frequency, and turning this 'sound' on and off in a certain pattern. E.g. sound on for a second is red, sound on for half a second is green. Commented Feb 5, 2017 at 16:47
• With a relatively clean source like a direct connection, timing the zero crossings in software should be simple. The main issue is that you need to build a network which turns the audio signal into a digital one, by biasing it to cross the threshold, ideally rapidly. Some ideas to consider are utilizing the ATmega's built-in comparator pin, bias resistors and a DC block capacitor, or even using a tiny audio transformer to create a high impedance signal that rapidly swings across the full logic range, and then clip it to safe levels. This is a problem that has been solved many times before. Commented Feb 5, 2017 at 21:32
• @ChrisStratton, do you have a link to this “tiny audio transformer”? I haven't been able to find any that are tiny. Small, yes; eg EI14 Audio Transformer 1300 : 8 Ohm about 12 mm on a side; but tiny, no. Commented Feb 5, 2017 at 23:20
• That is the kind of thing I meant, yes. Compared to the radios of the era where it was used, it was tiny. Congrats on even still finding one - they used to be all over the place, but with the change to class D IC amps they are mostly relegated to history... struggled to find even one to experiment with when I wanted to try mis-purposing one a few years ago. Commented Feb 6, 2017 at 0:33

Connect the signal to an analogue input on the Arduino, via a DC blocking capacitor, with a potential divider centring it around 2.5v. Make sure the voltage swing is within range, which it should be.

Keep the frequencies of the signal low, under say 2KHz. For example, use 500Hz, 1000Hz, 1500Hz, 2000Hz.

Sample (`analogRead()`) the signal as fast as you can (which is about 10KHz) for a short while, recording the min and max values. From this, you can find the centre value, 1/4 value and 3/4 value.

Now to find your frequency, sample until the signal goes above the 3/4 value. Get the time with `micros()`. Sample until the signal goes below 1/4, and then sample until it goes above 3/4 again and get the time with `micros()`. Do this a few times and average them. The difference between the two times is approximately your sample period, so you can easily find the frequency.

Determine which of your chosen frequencies most closely matches the frequency you've sampled.

If you can properly bias your signal, say with a cap and a pot, you could read it with a digital input. You can then time the rising edges with `micros()`, either by polling the pin or using an interrupt. You could achieve greater accuracy by using the “input capture” feature of a 16-bit timer, if you are using an AVR-based Arduino and are not afraid of getting your hands dirty with low-level programming.

You need to get the right voltage range for this to work though. On an Arduino Uno, for example, the thresholds for the input switching from `HIGH` to `LOW` and back are typically around 2.1 and 2.6 V respectively, so you must make sure that your signal amply covers this range. If you can get 1 V peak to peak, that should be enough, and you can then use the pot to tune the offset.