Arduino可以以微秒为单位采样1-4 kHz的音频吗?

时间:2013-04-09 11:12:32

标签: arduino signal-processing frequency sampling

我刚刚将electret microphone连接到Arduino,我想在1 kHz和4 kHz之间进行采样。

我知道这仅限于机器代码和ADC,所以我试图保持sketch简单。

是否可以使用下面的草图在这些频率之间进行采样?

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);
    }
}

3 个答案:

答案 0 :(得分:1)

Arduino是一个原型平台,由许多硬件板和软件抽象层组成。对于这样的问题,考虑底层硬件的功能是有用的,因为它们提供了最终的限制。我假设您使用的是Arduino Uno / Nano,故事的内容与Due不同。

根据数据表,每个ADC读数(超出第一个读数)需要13个ADC时钟周期。 ADC时钟(与MCU不同)时钟是通过将系统时钟除以某个因子(至少为2)得出的。因此,在16Mhz电路板上,这相当于每秒60万个采样。到现在为止还挺好。但是,这不是故事的结尾,您仍然需要阅读数据。如果您使用中断,即使您执行的操作非常简单,经验也表明您将丢失大约100个时钟来中断处理。现在你的速度低至126K样本/秒。但这是理论上的最大值。

数据表指出,要获得最高精度,ADC需要50kHz - 200kHz的ADC时钟。在Arduino代码中(在wiring.c中),选择了128的分频因子:

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

这意味着每次转换需要128 * 13 = 1764个时钟,这样每秒的理论最大值为10K样本。考虑到readAnalog()函数不仅仅是启动ADC转换并等待它完成,它还有点差,但它不应该太糟糕。这当然不涉及您的代码:您对readAnalog()的结果所做的任何处理都会使捕获更多样本变得更加困难。但是,是的,要以4Khz捕获,您需要确保编码花费少于1.5k时钟周期/样本,这应该是可行的。请注意,如果您正在使用您发布的代码执行五个读数,则如果您的代码很少,则最大捕获率将为2kHz。


就如何捕获数据而言,您需要处理这样一个事实,即如果您使用analogRead(),没有放大的麦克风将不会为您提供0-5V的读数。事实上,麦克风输出电压从正向摆动到负值,但是,负电压不会被ADC拾取,只会显示为零,除非你给麦克风一个电压偏移。


我不确定你的代码比较最小幅度和最大幅度应该做什么。你想要将音频数字化吗?在这种情况下,您需要保存从analogRead()收集的所有幅度读数,然后您可以在另一台计算机上对它们运行FFT:Arduino很可能不会足够快地对数据进行频率分析。< / p>

答案 1 :(得分:0)

我听说过,或者更确切地说还记得读取,ADC每秒可以处理高达10k样本,所以它应该可以达到5 kHz。但是,我没有试过这个,也没有链接支持它。

试试看。

现在我知道一些Arduino库函数很慢,特别是具有数百个周期开销的DigitalRead / Write。其中大部分是完整性检查,允许人们只是执行DigitalRead / Write而不必考虑设置所有内容。

然而,为了挤出最高性能,您可以考虑编写自己的针对您的用例进行优化的AnalogRead。

至少有一些关于这个主题的链接:

答案 2 :(得分:0)

我碰巧刚刚使用Arduino Uno和与您类似的代码进行了尝试,我平均每秒能够采样8000次。那是4 kHz的奈奎斯特频率,因此您不错,但误差范围不大。