Skip to content

Instantly share code, notes, and snippets.

@edgar-bonet
Created March 16, 2016 14:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save edgar-bonet/e693799f58a545ca89a2 to your computer and use it in GitHub Desktop.
Save edgar-bonet/e693799f58a545ca89a2 to your computer and use it in GitHub Desktop.
Arduino sound meter
/*
* sound-meter.ino: Arduino sound meter.
*
* This program continuously samples a sound signal on analog input 0
* and outputs the computed sound intensity through the serial port.
*
* The analog-to-digital converter is set to "free running mode" and
* takes one sample every 104 us. After subtracting a DC offset
* (constant dc_offset below), the samples are squared and low-pass
* filtered with a time constant of 256 sample periods (26.6 ms). They
* are then decimated by a factor 256 and transmitted as an ASCII stream
* at 9600/8N1 through the serial port.
*
* The program is intended for an Arduino Uno, and is likely to work on
* any AVR-based Arduino having an ADC and clocked at 16 MHz.
*
* Copyright (c) 2016 Edgar Bonet Orozco.
* Released under the terms of the MIT license:
* https://opensource.org/licenses/MIT
*/
// Analog input connected to the microphone (between 0 and 5).
const uint8_t mic_pin = 0;
// DC offset, i.e. ADC reading of silence.
const int dc_offset = 512;
// Intensity readings provided by the ADC interrupt service routine.
volatile uint32_t intensity_reading;
volatile bool intensity_reading_ready;
// Low-pass filter for the sound intensity.
// Time constant = 256 * sampling period = 26.624 ms
static uint32_t low_pass(uint32_t x)
{
static uint32_t integral;
integral += x - integral / 256;
return integral / 256;
}
// ADC interrupt service routine.
// Called each time a conversion result is available.
ISR(ADC_vect)
{
// Read the ADC.
int32_t sample = ADC;
// Compute the average sound intensity.
uint32_t intensity = sq(sample - dc_offset);
uint32_t avg_intensity = low_pass(intensity);
// Decimate by a factor 256.
static uint8_t sample_count;
if (++sample_count == 0) {
intensity_reading = avg_intensity;
intensity_reading_ready = true;
}
}
void setup()
{
// Configure the ADC in "free running mode".
ADMUX = _BV(REFS0) // ref = AVCC
| mic_pin; // input channel
ADCSRB = 0; // free running mode
ADCSRA = _BV(ADEN) // enable
| _BV(ADSC) // start conversion
| _BV(ADATE) // auto trigger enable
| _BV(ADIF) // clear interrupt flag
| _BV(ADIE) // interrupt enable
| 7; // prescaler = 128
// Configure the serial port.
Serial.begin(9600);
}
void loop()
{
// Wait for a reading to be available.
while (!intensity_reading_ready) /* wait */;
// Get a copy.
noInterrupts();
uint32_t intensity_reading_copy = intensity_reading;
intensity_reading_ready = false;
interrupts();
// Transmit to the host computer.
Serial.println(intensity_reading_copy);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment