Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arduino I2S正弦波_Arduino_Trigonometry - Fatal编程技术网

Arduino I2S正弦波

Arduino I2S正弦波,arduino,trigonometry,Arduino,Trigonometry,我正在做一个项目,我想通过组合不同的正弦波来产生(简单的)声音。我使用的是arduino mkrZero,因为它内置了I2S接口,似乎有足够的处理能力满足我的需要 我的系统接线与arduino I2S SimpleOne教程中的完全相同: 代码工作得很好,我从扬声器得到一个简单的方波音调 现在我已经修改了生成正弦波的代码,为sin函数提供了一个查找表,使其速度足够快: #include <I2S.h> uint16_t isin16[] = { 0, 1144, 2287, 34

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

我的系统接线与arduino I2S SimpleOne教程中的完全相同:

代码工作得很好,我从扬声器得到一个简单的方波音调

现在我已经修改了生成正弦波的代码,为sin函数提供了一个查找表,使其速度足够快:

#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];
}
而不是

I2S.write(LR[0]);//left channel
I2S.write(LR[1]);//right channel
一切都中断了,扬声器发出的声音听起来像是

从I2S库参考:

说明

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

语法

I2S.write(val)
//阻塞

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

参数

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

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

len:缓冲区的长度

返回

byte write()将返回写入的字节数(尽管正在读取) 这个号码是可选的

我想使用write函数的后一个版本,因为它没有阻塞,而且我可以在播放前一个示例时生成新的示例


关于如何使缓冲版本正常工作,您有什么想法吗?

在您的代码中,您将
LR
声明为一个由2个短
组成的
数组,而Arduino中的
short
的大小为
2个字节

当你写这篇文章时:

I2S.write(LR[0])//左声道
I2S.写入(LR[1])//右通道
给定

size\u t I2SClass::write(uint8\u t数据)
{
返回写入((int32_t)数据);
}
size\u t I2SClass::write(int示例)
{
返回写入((int32_t)样本);
}
您的
short
值应自动提升,以适合
int
类型。现在,我有点不确定您正在处理的
int
的大小,因为我找到的唯一I2S.h库是用于SAMD板的,但通常在Arduino上,an
int
的大小为
2字节。在任何一种情况下,该值都应按原样取值,没有问题

当你写这篇文章时:

I2S.写入(LR,2);
给定

size\u t I2SClass::write(const uint8\u t*缓冲区,size\u t size)
{
返回写入((const void*)缓冲区,大小);
}
大小I2SClass::写入(常量无效*缓冲区,大小)
{
...
write=\u doubleBuffer.write(缓冲区,大小);
...
}
你的
数组中的2个short
应该被强制转换为
const void*

从以下代码:

size\u t I2SDoubleBuffer::write(const void*buffer,size\u t size){
size_t space=availableForWrite();
如果(大小>空间){
大小=空间;
}
如果(大小==0){
返回0;
}
memcpy(&_buffer[_index][_length[_index]],buffer,size);
_长度[_索引]+=大小;
返回大小;
}
看起来,
\u doubleBuffer
不知道样本的声明的大小(您声明它是
16位的
),它只是将
大小
字节从输入复制到内部缓冲区

因此,我猜测,真正发生的事情是,当你要求缓冲
2个短片时,实际上只复制了
2个字节


示例:

假设您的
LR
包含以下值

short LR[2]={0x89AB,0xCDEF};
那么这就是我想象中发生的事情

I2S.write(LR[0]);//实际左侧样本为0x89AB
I2S.写入(LR[1]);//实际正确的样本是0xCDEF
写(LR,2);//实际左侧样本为0x89AB
//未复制0xCDEF
/*下一个循环迭代*/
写(LR,2);//实际右侧样本为0x89AB
//未复制0xCDEF

建议的解决方案:

尝试要求复制
4个字节

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