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