Arduino I2S 正弦波 [英] Arduino I2S sine wave

查看:95
本文介绍了Arduino I2S 正弦波的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个项目,我想通过组合不同的正弦波来生成(简单的)声音.我使用的是 arduino mkrZero,因为它内置了 I2S 接口,而且它似乎有足够的处理能力来满足我的需求.

I'm working on a project where I want to generate (simple) sound by combining different sine waves. I'm using an arduino mkrZero, as it has I2S interface built in and it seems to have enough processing power for what I want.

我已经完全按照 arduino I2S simpleTone 教程中的方式连接我的系统:

I have wired my system exactly like in the tutorial for arduino I2S simpleTone:

教程代码运行良好,我得到了一个简单的方波来自扬声器的声音.

And the tutorial code works just fine, and I get a simple square wave tone from the speaker.

现在我已经修改了生成正弦波的代码,有一个 sin 函数的查找表来使它足够快:

Now I have modified the code to generate sine wave, there is a lookup table for the sin function to make it fast enough:

#include <I2S.h>

uint16_t isin16[] = {
 0, 1144, 2287, 3430, 4571, 5712, 6850, 7987, 9121, 10252, 11380,
 12505, 13625, 14742, 15854, 16962, 18064, 19161, 20251, 21336, 22414,
 23486, 24550, 25607, 26655, 27696, 28729, 29752, 30767, 31772, 32768,

 33753, 34728, 35693, 36647, 37589, 38521, 39440, 40347, 41243, 42125,
 42995, 43851, 44695, 45524, 46340, 47142, 47929, 48702, 49460, 50203,
 50930, 51642, 52339, 53019, 53683, 54331, 54962, 55577, 56174, 56755,

 57318, 57864, 58392, 58902, 59395, 59869, 60325, 60763, 61182, 61583,
 61965, 62327, 62671, 62996, 63302, 63588, 63855, 64103, 64331, 64539,
 64728, 64897, 65047, 65176, 65286, 65375, 65445, 65495, 65525, 65535,
 }; //0-90


const int sincount = 2;
int freqs[] = {50*360,51*360};
float amps[] ={0.1,0.1}; 

const int sampleRate = 8000; // sample rate in Hz

short sample = 0;
double t = 0;
double dt = 1.0/(1.0*sampleRate);

short LR[] = {0,0};

void setup() {
 Serial.begin(115200);
  // start I2S at the sample rate with 16-bits per sample
  if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) {
    while (1); // do nothing
  }
}

void loop() {
    sample = 0;
    for(int n= 0;n<sincount;n++)
    {
      sample += fSin(freqs[n]*t)*amps[n];
    }
    t += dt;
    LR[0] = sample;
    LR[1] = sample;

   I2S.write(LR[0]);//left channel
   I2S.write(LR[1]);//right channel
}


float fSin(long x)
{
 boolean pos = true;  // positive - keeps an eye on the sign.
 if (x < 0)
 {
   x = -x;
   pos = false;  
 }  
 if (x >= 360) x %= 360;  
 if (x > 180)
 {
   x -= 180;
   pos = !pos;
 }
 if (x > 90) x = 180 - x;
 if (pos) return isin16[x]; // = /65535.0
 return isin16[x];
}

这也很好用.

但是!

如果我稍微改变一下代码然后我写

If I change the code a bit and I write

I2S.write(LR,2);

代替

I2S.write(LR[0]);//left channel
I2S.write(LR[1]);//right channel

一切都中断了,扬声器的声音听起来像可怕的尖叫

Everything just breaks, the sound from the speaker sounds like a horrible scream

来自 I2S 库参考:

From the I2S library reference:

说明

将二进制数据写入 I2S 接口.此数据作为样本发送或系列样品.

Writes binary data to the I2S interface. This data is sent as a sample or series of samples.

语法

I2S.write(val)//阻塞

I2S.write(buf, len)//不阻塞

参数

val:作为单个样本发送的值

val: a value to send as a single sample

buf:作为一系列样本发送的数组

buf: an array to send as a series of samples

len:缓冲区的长度

退货

byte write() 将返回写入的字节数,虽然读取这个数字是可选的.

byte write() will return the number of bytes written, though reading that number is optional.

我想使用后一个版本的 write 函数,因为它不会阻塞,而且我可以在播放前一个样本的同时生成新样本.

I'd like to use the latter version of the write function, because it is not blocking and I can generate new samples while the previous ones are playing.

关于如何使缓冲版本也正常工作的任何想法?

Any ideas on how to make the buffered version work correctly as well?

推荐答案

在你的代码中,你将 LR 声明为一个 array of 2 short,一个 shortArduino 中的 大小为 2 字节.

In your code, you declare LR as an array of 2 short, a short in Arduino has size 2 bytes.

当你写这个时:

I2S.write(LR[0]); //left channel
I2S.write(LR[1]); //right channel

给定

size_t I2SClass::write(uint8_t data)
{
    return write((int32_t)data);
}

size_t I2SClass::write(int sample)
{
    return write((int32_t)sample);
}

您的 short 值应该自动提升以适应 int 类型.现在,我对您正在处理的 int 的大小有点不确定,因为我发现的唯一 I2S.h 库是用于SAMD其中 int 具有 4 bytes size,但通常在 Arduino 上,int 的大小为 2 bytes.无论哪种情况,都应按原样使用该值,没有问题.

your short values should be automatically promoted to fit into the int type. Now, I am a bit unsure on the size of int you are dealing with, because the only I2S.h library I found is for the SAMD board on which an int has 4 bytes size, but normally on Arduino the an int has size of 2 bytes. In either case, the value should be taken as is, without problems.

当你写这个时:

I2S.write(LR,2);

给定

size_t I2SClass::write(const uint8_t *buffer, size_t size)
{
    return write((const void*)buffer, size);
}

size_t I2SClass::write(const void *buffer, size_t size)
{
    ...
    written = _doubleBuffer.write(buffer, size);
    ...
}

你的 array of 2 short 应该被转换为 const void *.

your array of 2 short should be cast to const void *.

来自 I2SDoubleBuffer 中的代码:

size_t I2SDoubleBuffer::write(const void *buffer, size_t size) {
  size_t space = availableForWrite();

  if (size > space) {
    size = space;
  }

  if (size == 0) {
    return 0;
  }

  memcpy(&_buffer[_index][_length[_index]], buffer, size);

  _length[_index] += size;

  return size;
}

看起来_doubleBuffer 不知道样本声明大小(你声明它是16位),它只是将 size 字节从输入复制到内部缓冲区.

it looks like _doubleBuffer is not aware of the declared size of a sample (you declared it to be of 16 bits), it merely copies size bytes from the input to the internal buffer.

因此,我猜测真正发生的情况是,当您要求缓冲 2 shorts 时,实际上只复制了 2 个字节.

Therefore, I guess that what really happens is that when you ask for 2 shorts to be buffered only 2 bytes are actually copied.

示例:

假设您的 LR 包含以下值

Assume that your LR contains the following values

short LR[2] = { 0x89AB, 0xCDEF };

那么这就是我想象的它发生的

I2S.write(LR[0]); // actual left sample is 0x89AB
I2S.write(LR[1]); // actual right sample is 0xCDEF

I2S.write(LR, 2); // actual left sample is 0x89AB
                  // 0xCDEF is not copied
/* next loop iteration */
I2S.write(LR, 2); // actual right sample is 0x89AB 
                  // 0xCDEF is not copied

<小时>

建议的解决方案:

尝试要求复制4个字节:

I2S.write(LR, 4); // actual left sample is 0x89AB 
                  // actual right sample is 0xCDEF

这篇关于Arduino I2S 正弦波的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆