Sound & Vibration Project on Arduino

Discussion in 'The Projects Forum' started by Dualfire, Mar 12, 2013.

  1. Dualfire

    Thread Starter New Member

    Dec 5, 2012
    Hey guys! For this month, I want to do a small project using the Arduino. I have little experience with using it, and the alternative would be using the BASIC Stamp, but I chose to use the Arduino.

    I have a few question and will separate it into three steps for simplicity reasons, if you could help me with a one or two of those, or even all, that would be great!!!

    1., I am connecting a electret microphone to the Arduino.
    2., I am connecting a piezo vibration sensor, connect it in parallel with a 10M resistor (or a 2-3M resistor to make it less sensitive) to the Arduino.
    3. I want to combine the two on a 2-line LCD that I have purchased and want to output the sound and vibration level on each line.

    For the sound detector portion, I use the following code from "Arduino Cookbook"

    microphone sketch
    SparkFun breakout board for Electret Microphone is connected to analog pin 0
    const int ledPin = 13; //the code will flash the LED in pin 13
    const int middleValue = 512; //the middle of the range of analog values
    const int numberOfSamples = 128; //how many readings will be taken each time
    int sample; //the value read from microphone each time
    long signal; //the reading once you have removed DC offset
    long averageReading; //the average of that loop of readings
    long runningAverage=0; //the running average of calculated values
    const int averagedOver= 16; //how quickly new values affect running average
    //bigger numbers mean slower
    const int threshold=400; //at what level the light turns on

    void setup() {
    pinMode(ledPin, OUTPUT);
    void loop() {
    long sumOfSquares = 0;
    for (int i=0; i<numberOfSamples; i++) { //take many readings and average them
    sample = analogRead(0); //take a reading
    signal = (sample - middleValue); //work out its offset from the center
    signal *= signal; //square it to make all values positive
    sumOfSquares += signal; //add to the total
    averageReading = sumOfSquares/numberOfSamples; //calculate running average
    if (runningAverage>threshold){ //is average more than the threshold ?
    digitalWrite(ledPin, HIGH); //if it is turn on the LED
    digitalWrite(ledPin, LOW); //if it isn't turn the LED off
    Serial.println(runningAverage); //print the value so you can check it

    the code works good, however, how do I loop it so that it would output only, let's say, 5 values (the average of the 128 values that it gives me) per second?
    Also, how do output that number into dB?

    For the vibration detector portion, I am using the following code found in one of the Arduino tutorials, and modified the code just a little bit:

    const int ledPin = 13; // led connected to digital pin 13
    const int knockSensor = A0; // the piezo is connected to analog pin 0
    const int threshold = 3; // threshold value to decide when the detected sound is a knock or not

    // these variables will change:
    int sensorReading = 0; // variable to store the value read from the sensor pin
    int ledState = LOW; // variable used to store the last LED status, to toggle the light

    void setup() {
    pinMode(ledPin, OUTPUT); // declare the ledPin as as OUTPUT
    Serial.begin(9600); // use the serial port

    void loop() {
    // read the sensor and store it in the variable sensorReading:
    sensorReading = analogRead(knockSensor);

    // if the sensor reading is greater than the threshold:
    if (sensorReading >= threshold) {
    // toggle the status of the ledPin:
    ledState = !ledState;
    // update the LED pin itself:
    digitalWrite(ledPin, ledState);
    // send the string "Knock!" back to the computer, followed by newline
    delay(50); // delay to avoid overloading the serial port buffer

    This code also works well, was just also wondering how to loop this one. Every time I touch or flick the sensor, it will output around 3-10 numbers, not sure if averaging them would make sense, because I can't tell if I should omit a few of those numbers (noise) or if all those numbers are important. So I am not sure on this one yet, however I would still want only one or two values per seconds, if that is plausible.
    And I would like to convert this to the unit 'G'.

    3. I want to connect it to an LCD, and have to combine these two codes, but I am not sure, how and where to look for the code to put this on the Arduino.

    I will continue experimenting around. Any help would be appreciated!!!

    Thanks a bunch!
  2. Dualfire

    Thread Starter New Member

    Dec 5, 2012
    Can anybody help me on this? Pseudocode would also, if you are not familiar with the Arduino.
    I don't know how and where to add the loop for both parts (sound and vibration), also I don't know how to convert to, dB and G, respectively
  3. patricktoday


    Feb 12, 2013
    If you're only wanting to collect or display a result 1 or 2 times per second, you might want to create a timer of that frequency and then call your Loop() or CollectSample() function when the timer fires; that way the processor is only working as much as is needed to collect the info you actually need.

    Conceptually, I would say create a timer interval of your desired display rate; in the interrupt handler, call a CollectMicLevel() function that returns an int; then call a CollectVibrationLevel() function that returns an int. Then create a function called OutputLevelsToLCD(int micLevel, int vibrationLevel) in another file that will interact with the LCD to display your desired output; call this third function after the other two to output the results.

    It will be easier to organize your code with a more modular design as such where each function has a specific responsibility :)
  4. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    Decide number of averages, say 16 per second.
    Decide number of updates per second, say, 1.
    Code ( (Unknown Language)):
    2. start:
    3. ISR every 1/20th second or so (50 Hz).
    4. {
    5.      sample level of audio
    6.      Add audio level to audio array position i (i from 0 to 15)
    7.      sample piezo level to piezo array position i (i from 0 to 15)
    8. }
    10. every 1 second
    11. {
    12.      Sum audio array values, divide by 16, store in averageaudio
    13.      Sum piezo array values, divide by 16, store in averagepiezo
    14.      Clear LCD, Curasor LCD to 0,0
    15.      Print Average Audio
    16.      LCD Cursor Goto position 0,1
    17.      Print Average Piezo
    18. }
    Have the sampling occur in a timer interrupt, the update occur in the main loop. Avoid delay() statements at all costs. Another interrupt could be used to write LCD each second, so main simply resets flags set by ISRs, and calls routines based on those flags.

    50Hz sampling for 16 samples per second is to allow enough time for Arduino to do math and get output to display in 1 second. It could be a bit higher, see where the limit is before it overruns the ISR.
  5. patricktoday


    Feb 12, 2013
    And here's an averaging function that allows for upper and lower "ignore" thresholds. (Typed in notepad so forgive me if there's a bug ;) )

    Code ( (Unknown Language)):
    2. int GetAverageFromArray(int* values, int count, int minAllowedValue, int maxAllowedValue)
    3. {
    4.     long total = 0;
    5.     int samples = 0;
    6.     for (int t=0; t<count; t++){
    7.         int value = values[t];
    8.         if (value > maxAllowedValue || value < minAllowedValue)     continue;
    10.         total += value;
    11.         samples++;
    12.     }
    13.     if (samples==0)     return 0;
    14.     else            return total / (float)samples;
    15. }