Arduino I2S 正弦波

2024-02-13

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

I have wired my system exactly like in the tutorial for arduino I2S simpleTone:enter image description here

And the tutorial https://www.arduino.cc/en/Tutorial/I2SSimpleTone代码工作得很好,我从扬声器中听到了简单的方波音。

现在我修改了代码来生成正弦波,有一个用于 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];
}

这也很好用。

BUT!

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

I2S.write(LR,2);

代替

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

一切都崩溃了,扬声器发出的声音听起来就像是可怕的尖叫声 https://www.youtube.com/watch?v=_Eos0wg7QJU

来自 I2S 库参考:

描述

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

Syntax

I2S.write(val)// 阻塞

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

参数

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

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

len:缓冲区的长度

Returns

byte write() 将返回写入的字节数,尽管读取 该号码是可选的。

我想使用后一个版本的写入功能,因为它不会阻塞,并且我可以在播放以前的样本时生成新样本。

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


在您的代码中,您声明LR as an array of 2 short, a short in Arduino有尺寸2 bytes.

当你写下这个:

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

given

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

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

your short值应该是自动的promoted以适应int类型。现在,我有点unsure的大小int你正在处理,因为唯一I2S.h我找到的图书馆是SAMD board 其上有一个int has 4 bytes size https://www.arduino.cc/en/Reference/Int,但正常情况下Arduino the an int大小为2 bytes。无论哪种情况,该值都应按原样采用,没有问题。

当你写下这个:

I2S.write(LR,2);

given

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

your array of 2 short应该投射到const void *.

从这段代码中I2S双缓冲器 https://github.com/arduino/ArduinoCore-samd/blob/master/libraries/I2S/src/utility/I2SDoubleBuffer.cpp:

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不知道declared的大小sample(你声明它是16 bits),它只是复制size从输入到内部缓冲区的字节。

因此,我guess真正发生的是当你要求2 shorts仅缓冲2 bytes实际上是复制的。


Example:

假设你的LR包含以下值

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 bytes待复制:

I2S.write(LR, 4); // actual left sample is 0x89AB 
                  // actual right sample is 0xCDEF
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Arduino I2S 正弦波 的相关文章

  • math.atan2 的逆?

    函数的反函数是什么 math atan2 我在 Lua 中使用它 我可以得到相反的结果math atan by math tan 但我在这里迷路了 EDIT 好的 让我向您提供更多详细信息 我需要计算 2 点 x1 y1 和 x2 y2 之
  • Arduino:字符串到整数得到奇怪的值

    我想转换一个String to an int 我所能找到的就是你必须将 String 转换为 char 数组 然后将该数组转换为int 但我的代码产生奇怪的值 我无法弄清楚问题是什么 void ledDimm String command
  • JavaScript 正弦波

    track function x y top ampl return top top 2 x x ampl Math sin top 20 y top this screenHeight lt 0 65 y 2 1 y ampl Math
  • 蓝牙 HC-05 发送错误 1F 仅适用于 INQ 命令

    我的新蓝牙 HC 05 模块有问题 在 AT 模式下 它可以与我需要的所有命令完美配合 除了 INQ 我已经尝试事先发送一大堆其他命令 AT INIT OK AT ORGL OK AT ROLE 1 OK AT CLASS 0 OK 他们都
  • 如何使用arduino从sim900模块的RTC读取日期和时间数据?

    include SIM900 h include
  • 如何在 Arduino 上比较 __FlashStringHelper* 和 char*?

    我有一个将文本行输出到串行的板 我需要将这些文本行与我所知道的文本进行比较 本质上 我想做strcmp thestring F knownstring 但是似乎没有一个采用 FlashStringHelper 类型的 strcmp 版本 有
  • Arduino:使用串口和软件串口与蓝牙模块

    我的目的是使用 Arduino 通过 HC 05 蓝牙模块在 PC 和 Android 设备之间建立通信 我使用 PC 和 Arduino 串行监视器 之间的 USB 通信以及 SoftwareSerial 来连接到 HC 05 我的问题是
  • python中余弦的高效计算

    我根据理论功率谱密度生成一些时间序列 基本上 我的时空函数由下式给出X t SUM n sqrt a n cos w n t phi n where a n是的值PSD在给定的w n and phi是一些随机阶段 为了获得现实的时间序列 我
  • 沿着某个方向移动 CGPoint 一定距离...iphone

    这似乎是一个简单的问题 但我一直无法找到答案 而且我不擅长数学 我正在尝试将 UIView 沿着某个方向移动到新的 CGPoint X 距离 确定新坐标的公式是什么 我不想让它变成动画 只是瞬时移动 就像是 x 100 current x
  • Python自动选择串口(适用于Arduino)

    目前 Python 程序必须知道设备 Arduino 位于哪个端口 然后 Python 才能与设备进行通信 Problem 每当设备拔出并重新插入时 其 COM 端口都会发生变化 因此必须再次向 Python 提供正确的串行端口 以便它找到
  • 同时使用 GPRS 和 GSM

    我正在尝试使用 GSM GPRS 调制解调器的 GPRS 功能将数据发送到远程服务器 但我无法这样做 我在 Arduino 论坛上发布了一个问题 但没有得到任何回复 这是问题的链接 https robotics stackexchange
  • 实现基于查表的三角函数

    对于我在业余时间实现的视频游戏 我尝试使用查找表实现我自己的 sinf cosf 和 atan2f 版本 目的是使实现速度更快 但准确性较低 我的初步实现如下 这些函数可以工作 并返回良好的近似值 唯一的问题是他们是slower而不是调用标
  • cos-extensions 安装 gpu 无法在 GCP Compute Engine 虚拟机上下载驱动程序签名

    我正在 GCP 计算引擎上使用支持 GPU 的虚拟机 作为操作系统 我使用容器优化版本 COS 89 16108 403 47 LTS 它支持通过 SSH 运行 cos extensions install gpu 来安装简单的 GPU 驱
  • C 中正弦函数的实现不起作用

    我尝试用 C 语言实现正弦函数 但得到了奇怪的结果 以下是我用来计算正弦的三个函数 define PI 3 14159265358979323846 define DEPTH 16 double sine long double long
  • 坐标三角学 - 计算飞行路径弧线的中点

    我正在尝试使用 SVG 在地图上绘制飞行路径 我在 Leaflet 之上使用 d3 但所使用的框架不应该对我的问题产生影响 这是三角函数 http fiddle jshell net zw8TR 26 http fiddle jshell
  • 带/不带类的回调函数指针 C++

    我被困 我正在尝试形成一个函数 它将吃掉无类函数指针和对象中的函数指针 这是我当前的代码 希望能解释更多 它应该在 Arduino 上运行 所以我不能使用大型库 首先 我在 Arduino 上使用这个库 SimpleTimer A time
  • HM10 ble改变特征值AT命令Arduino

    谁能帮我用AT命令写入特征值 或者如何使用Hm10模块将数据从arduino发送到另一个ble设备 HM10发送AT START后 会通告数据包 并且可以检测服务和特征 但特征值是默认的0x00 如何更改 多次检查数据表 但找不到能够执行相
  • 通过iPhone音频插孔读取数据

    我正在寻找一种方法来读取通过 iPhone 的音频插孔从 Arduino 发送的原始数据 我搜索了很多并发现this https github com sanjibahmad Is Headphone Plugged In tree mas
  • 在 Objective C 中使用余弦定律计算两点之间的距离?

    我从 Google 地图获取一些 GPS 坐标 我需要找到它们之间的距离 使用 Objective C 我已经实现了该公式 但得到的结果太大了 我通过将 Google 地图的值传回 Google 地球和互联网上的地理编码服务来测试这些值 一
  • 在二维空间中从 A 点前往 B 点?

    我正在开发一个项目 需要我计算从可变点 A 到可变点 B 的 0 360 度航向 以使 A 点的物体面向 B 点 现在 我不确定如何实现这一目标 我用谷歌搜索但没有找到任何好的解决方案 在任何情况下 如何计算二维空间中从 A 点到 B 点的

随机推荐