Created
March 16, 2016 14:29
-
-
Save edgar-bonet/e693799f58a545ca89a2 to your computer and use it in GitHub Desktop.
Arduino sound meter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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