Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an Arduino sample audio in microseconds for 1-4 kHz?

I've just hooked up a electret microphone to an Arduino, and I'd like to sample between the ranges of 1 kHz and 4 kHz.

I understand this is limited to the machine code and the ADC, so I'm trying to keep the sketch simple.

Is it possible to sample between these frequencies with the sketch below?

const int analogPin = 0;
int ledPin = 13;

void setup() {
    pinMode(ledPin, OUTPUT);
}

void loop() {
    int mn = 1024;
    int mx = 0;
    for (int i = 0; i < 5; ++i) {
        int val = analogRead(analogPin);
        mn = min(mn, val);
        mx = max(mx, val);
    }
    if (mx-mn >= 50) {
        digitalWrite(ledPin, HIGH);
    }
    else {
        digitalWrite(ledPin, LOW);
    }
}
like image 958
user2119971 Avatar asked Nov 12 '22 07:11

user2119971


1 Answers

Arduino is a prototyping platform consisting of a number of hardware boards plus a software abstraction layer. For a question like this, it is useful to consider the capabilities of the underlying hardware, as these provide the ultimate limits. I'll assume you are using Arduino Uno/Nano, the story is different for Due.

According to the datasheet, each ADC reading (beyond the first one) takes 13 ADC clock cycles. ADC clock (different from the MCU) clock is derived by dividing the system clock by some factor, at least 2. So at 16Mhz board this amounts to 0.6 million samples per second. So far so good. However, that's not the end of the story, you still need to read the data. If you use interrupts, even if you do something very simple, experience suggests that you will lose about 100 clock to interrupt processing. Now you are down to 126K samples/second. But this is a theoretical maximum.

The datasheet states that for maximum accuracy for the ADC requires 50kHz - 200kHz ADC clock. In the Arduino code (in wiring.c), a division factor of 128 is chosen:

sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);

This means that each conversion takes 128*13 = 1764 clocks, which yields a theoretical maximum of 10K samples per second. It is a little bit worse than that given that the readAnalog() function does something beyond just starting the ADC conversion and waiting for it to finish, but it shouldn't be too much worse. This doesn't involve your code of course: any processing you do on the results of readAnalog() will make it more difficult to capture more samples. But yes, to capture at 4Khz you will need to make sure that you code spends less than 1.5k clock cycles/sample, which should be doable. Note that if you are doing five readings like you are doing in the code you posted, the maximum capture rate will be 2kHz if your code does very little.


As far as how to capture the data, you need to make deal with the fact that microphones without amplification will not give you 0-5V readings that you might expect if you are using analogRead(). In fact, microphone output voltages swing from positive to negative, however, the negative voltages will not be picked up by the ADC, and show up as just zeros, unless you give your microphone a voltage offset.


I am not exactly sure what your code that compares minimum amplitude to maximum amplitude is supposed to be doing. Are you wanting to digitize the audio? In this case you need to save all the amplitude readings collected from analogRead(), and then you can run FFTs on them on another computer: Arduino is most likely not going to be fast enough to do frequency analysis on the data.

like image 90
angelatlarge Avatar answered Dec 17 '22 20:12

angelatlarge