Hello there .. again. It has been a while, so today we will be messing around an electret microphone. The mission for now is : Make a simple voice recorder. Of course we won't be getting studio quality (obviously), and that is .. for several reasons..
So, we biased it, then what ? Then will just hook it onto one of Atmega16's differential input pins (Port A 3 - in my case) through a capacitor (~50 nF), and the negative pin of the differential input will be connected to the ground. Also, we could really use some gain. Well, 10x sounds tempting, let's see. Ok, we have the idea of inputs, now sampling rate and resolution.. AVR's ADC offers us up to 10 bit resolution. Sending 10 bits to the computer .. what a drag.. if it would have been 8 bits, we could send it over to the computer using UART, seems like the most effortless way. Sure, we will loose those two bits .. but whatever, too much effort, not worth it. As for sampling rate, the important information when speaking is contained around 1-4 khz, so I'd guess 10,000 samples per second sounds pretty good. Assemble the schematic on your breadboard, and lets move on to the code.
So, the function to start the Timer counter 0, pretty simple actually.
As for ADC initialization code, we set ADLAR (left adjust, for 8 bit resolution), highest possible clock speed, ADATE (automatic update trigger .. or whatever it was), and MUXes, for selected pins, at selected 10x gain. Also in SFIOR, we select the trigger for ADC to be Timer0 compare match.
The interrupt handler in our design had two jobs - send data over UART, and clear the Timer0 compare match flag.
And the main routine - just call all the init functions, and sit back, and relax.
The resulting wave looked like this. In case of any questions, comments are welcome. And all the code can be found here. Goodbye!
- ADC on Atmega16(the one that I got around) gives tops 15 kilosamples per second, and it's just 10 bits. While just CD quality requires 16 bit, 44100 kilosamples.
- Except for getting ADC values, we also need to send it somehow to the computer
- ... well you got the idea, whatever, moving on
The action plan ..
So, the name electret comes from two words - electrostatic and magnet (wiki). It basically has two conducting plates, one of which is serving as a membrane, and when mechanical waves (i.e. sound) hits the membrane plate, it causes change of capacity, which will cause a change in voltage. Mostly all this type of microphones have a FET inside for gain, so all you would need to do is bias it with a resistor. For my case I used a 1k resistor.So, we biased it, then what ? Then will just hook it onto one of Atmega16's differential input pins (Port A 3 - in my case) through a capacitor (~50 nF), and the negative pin of the differential input will be connected to the ground. Also, we could really use some gain. Well, 10x sounds tempting, let's see. Ok, we have the idea of inputs, now sampling rate and resolution.. AVR's ADC offers us up to 10 bit resolution. Sending 10 bits to the computer .. what a drag.. if it would have been 8 bits, we could send it over to the computer using UART, seems like the most effortless way. Sure, we will loose those two bits .. but whatever, too much effort, not worth it. As for sampling rate, the important information when speaking is contained around 1-4 khz, so I'd guess 10,000 samples per second sounds pretty good. Assemble the schematic on your breadboard, and lets move on to the code.
Code
Once again, what we decided:- 10 kilosmaples per second
- 8 bit resolution (ADLAR :)
- UART feedback to the computer
- Differential input channels
So, the function to start the Timer counter 0, pretty simple actually.
void init_timer0 (void) { /* * 8 bit timer counter 0 * Mode of operation: CTC * Divider: 8 / OCR - 199 (200 divider) * Interrupt frequency: 10000 hertz */ TCCR0 = _BV(WGM01) | _BV(CS01); // TIMSK |= _BV(OCIE0); OCR0 = 199; }
void adc_init (uint8_t muxx) { SFIOR |= _BV(ADTS1) | _BV(ADTS0); // TIMER0 compare match ADMUX = _BV(REFS0) | _BV(ADLAR)| muxx; ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADIE) | _BV(ADATE) /* | _BV(ADPS1) */; }
ISR (ADC_vect) { // send converted ADC data over uart UDR = ADCH; // clear TIMER0 compare match flag TIFR |= _BV(OCF0); }
Processing the audio
Well, good, we opened the serial terminal with logging, and got bunch of crap that seems to be changing when we talk. What next ? What we get is not just useless code, we get code, representing our analog signal, or otherwise called raw data. I found that Audacity has a feature of importing raw data.The resulting wave looked like this. In case of any questions, comments are welcome. And all the code can be found here. Goodbye!