Cheap Sound Sensor for AVR

I searched the web for a cheap method to let the ATmega respond to sound. My knowledge in analog circuits is very limited, but what I do remember, is that you can not attach a electret mircophone to a controller pin. The signal of the microphone is just too small and has to be amplified. There is much of information out there, especially on diy amplifiers. I stumbled upon this little circuit here. It consists only of a handful of components:

  • 2 resistors 10k
  • 1 resistor 100k
  • transistor 2N3904
  • 1 capacitor 0.1u
  • electret microphone

Prototyping the amplifier

Putting things together on a breadboard.

IMGP1255

Actually I had no 2N3904 around, so I replaced it with a BC337. The circuit is a emitter circuit with voltage degeneration (I dont know if that exists in english). I dropped the couple capacitor and took the signal right away at the collector.

Prototyping with the ATmega

The sound sensing is done with the ADC of the ATmega. A simple program reads the analog value of the amplifier over and over. If the value (loudness) exeeds a specific level, an LED is lit.
IMGP1253

The schematic for rebuilding.
mic-schematic

Here is the code. It is just hacked together and has lots of room for improvements.

/* -----------------------------------------------------------------------
 * Title:    sound sensor
 * Author:   Alexander Weber
 * Date:     19.05.2007
 * Hardware: ATmega8
 * Software: WinAVR 20060421
 * 
 */

#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>

#define LED_BIT PD4

/*
 * get_adc
 * Return the 10bit value of the selected adc channel.
 */
uint16_t get_adc() {

	uint16_t value;

	// warm up the ADC, discard the first conversion
	ADCSRA |= (1 << ADSC);
	while (ADCSRA & (1 << ADSC)); 
	value = ADCW;
	
	ADCSRA |= (1 << ADSC);				// start single conversion
	while (ADCSRA & (1 << ADSC)); 		// wait until conversion is done

	return ADCW;
}

int main(void) {

	uint8_t i = 0;
	
	DDRD |= 0x1c;	// PD2-PD3: col 6-7, PD4: debug LED

	// select channel
	ADMUX = 5;

	// ADC setup
	ADCSRA = 
		(1 << ADEN) |						// enable ADC
		(1 << ADPS1) | (1 << ADPS0);		// set prescaler to 8	
			
	// say hello	
	for (i = 0; i < 5; i++) {
		PORTD |= (1 << LED_BIT);
		_delay_ms(10);
		_delay_ms(10);
		_delay_ms(10);
		_delay_ms(10);
		_delay_ms(10);
		PORTD &= ~(1 << LED_BIT);
		_delay_ms(10);
		_delay_ms(10);
		_delay_ms(10);
		_delay_ms(10);
		_delay_ms(10);
	}
	_delay_ms(10);
	_delay_ms(10);


	while (1) {
		
		if (get_adc() > 180) {
			PORTD |= (1 << LED_BIT);
			_delay_ms(10);
			PORTD &= ~(1 << LED_BIT);
		}			
		
	}

	return 0;

}

Video

The video got lost :(

Conclusion

It was easy and worked pretty well. I enjoyed looking at the LED responding to the music. I haven’t recorded anything with this amplifier, it might sound awfull. Next steps could be playing the sound back or be able to analyze the sound (FFT). And (re-)learning more on analog circuit design.

Links

68 Comments

  1. Hello all, Interesting post.
    Hereis what I am looking for. Did analog circuit design 25 years ago. Looking for up to date methods:

    I have an Alpine card CD receiver that has an Interrupt lead. I would like to take an iPod headphone out and generate a trigger from a circuit every time there is audio on the headphone jack. the trigger signal wil be connected to the interrupt lead on the head unit. I also need to hold the lead high for say 1-4 seconds once the headphone out goes higher than a preset value.

    How do I do this?

    Thanks in anticipation. Cheers. -Amitabh

    Like

  2. Hello Alex,

    Great tutorial, very well explained! I tried to recreate the setup, but it doesn’t work very well. It only responds when I blow into the speaker.

    I used exact the components you described at the beginning, including the 2N3904.

    One difference, but I don’t know if it matters: my electret is connected via two cables of about 20 cm. Could this influence the gain? Any other idea why my preamp performs so badly?

    Thanks!
    Pieter

    Like

  3. Hi Pieter,
    the gain of the original circuit is really really small. Try to log the values you get while it’s silent. Then log the values while you are blowing or playing loud music. Maybe that can help.
    Otherwise you may want to choose another circuit with more gain.
    Cheers,
    Alex

    Like

  4. Hey, great tutorial! I’m thinking of recreating it, though not exactly the same.. Could you tell me if you really need capacitors C2 and C3 which are connected to ports 9 and 10 on the schematic above? Also, is Q1 needed? I’m thinking of using making the following circuit, connecting the “Output to next stage” to an ADC pin, and a servo to an output pin. http://www.reconnsworld.com/audio/simplepreamp.gif

    Thanks for your time,
    Vignesh R.

    Like

  5. Hi,
    I have no knowledge in microcontrollers but i can work with labview. I am searching for sound sensor that hear the noise from a pump. Do you have any idea to do this. I had a pump that can give noise when inside the storke is touched to mechanical parts. I need to adjust it by using sound sensor. Can you help with any idea,

    Like

  6. yaa i have no idea about sound sensor.may i know how much money should i have to spend for this projet??

    Like

  7. It’s only a couple of bucks. Only cents if you don’t count the microcontroller.

    Like

  8. Hi,
    thank you for this great setup. We built a RGB-LED Controller in a project and I added the Sound Sensor. We used only SMDs, so I choose the MMBT3904 instead of the 2N3904. Well, it does work. But I have the same problem as Josh(#38). My ADC output value is allways around 800 (10bit). And it only varies about +/- 10 when I play some sounds, so it is very tricky to find the right trigger level. What is your difference between silence and sound? I used an MCE101 instead of the MCE 100 but the only difference should be the cable… Has anyone an idea what could cause my high level?

    Like

  9. Sorry for the double post.
    It works just fine with a value of 800 now!
    My problem was, that I sent every single value to my console with printf and therefore the programm was to slow. Now it is really sensitiv, even to the sound of me writing on my keyboard!
    Again thank you for this real simple but great sound sensor!

    Like

  10. hey, i was jus wondering if i can put the output from the amplifier into an arduino uno?

    Like

  11. The diffrence between adc output is probably caused by AVREF specification. In atmega88 u can choose between AVcc/1.1V/AREF . I calculated aprox values with diffrent VRefs and thats what i got:

    for AVcc ~ 176
    for 1.1V ~ 800

    the formula is very simple ADC = AIN/AVREF * 1024

    PS. I used BC337 and output voltage was 0,86V.
    PS2. Nice and simple amp :)

    Like

  12. In the tutorial, you say you used 2 capacitors at 0.1uF but, i only see one in your design and schematics. Where is the second one located (if there is a second)?

    Like

  13. Hi Alex,I measured the output of the BJT used VOM and found it to stand still in a position (with sound-needle run).
    The sound sensor true or false? I don’t connect with AVR,i just test by voltage-VOM!
    PL help me,thank for your watching my question!

    Like

  14. Hi Luu,
    you probably can’t see changes on a voltmeter because it’s too slow and the changes are too small.
    Cheers,
    Alex

    Like

Comments are closed.