【问题标题】:How to send a big array (96000 samples) to the ESP32 serial-port via MATLAB?如何通过 MATLAB 向 ESP32 串口发送一个大数组(96000 个样本)?
【发布时间】:2026-01-24 02:40:02
【问题描述】:

简而言之,我正在 MATLAB 中读取一个 .wav 文件,以便将其发送到 ESP32 进行 FFT 分析。有问题的 .wav 文件包含电晕效应的记录。输入 MATLAB 时,我的文件有 96223 个样本。

目前,我正在尝试取回校验和,以便知道数据已正确发送。

我已经尝试使用我为较小样本量编写的代码。例如,当我发送 200 个样本时,我得到了正确的校验和,尽管代码花费的时间比我想要的要长,这并不好。不仅如此,而且由于超时,我再也没有得到任何回报。

这是我的 MATLAB 代码:

esp = serial('COM3');
set(esp, 'DataBits' , 8);
set(esp, 'StopBits', 1);
set(esp, 'BaudRate', 9600);
set(esp, 'Parity', 'none');
set(esp, 'terminator', 'LF');

%filename = 'test100.wav';
%corona = audioread(filename);

load('corona')
fopen(esp);
pause(0.1)
for i = 1:200
   fprintf(esp, '%5.9f\n', corona(i,1)); 
   pause(0.1);       
end
output = fscanf(esp, '%f\n') %read the checksum
fclose(instrfind);

这是我的 Arduino 代码:

#include <Arduino.h>
float sentData[200]; //initialize data array
int i = 0;
const int ledPin = 26;
float checksum = 0;
int CNT = 0;

void printFloat(float value, int places);

void setup()
{
  Serial.begin(9600);

  pinMode(ledPin, OUTPUT);

  while (Serial.available() < 200)
  {
    digitalWrite(ledPin, HIGH); //keep the LED on while the data is being sent
  }

  while (Serial.available() != 0)
  {
    sentData[i] = Serial.parseFloat(); //parse the data to the array
    i++;
  }
  Serial.flush();
  delay(500);
  digitalWrite(ledPin, LOW); //turn off the LED when data is fully parsed

  for (size_t x = 0; x < 200; ++x)
  {
    checksum += sentData[x]; //calculate the sum of all elements in the sentData array
  }
  printFloat(checksum, 10); //send the checksum to the serial port for reading
}
void loop()
{
}

void printFloat(float value, int places)
{
  // this is used to cast digits
  int digit;
  float tens = 0.1;
  int tenscount = 0;
  int i;
  float tempfloat = value;

  // if this rounding step isn't here, the value  54.321 prints as 54.3209

  // calculate rounding term d:   0.5/pow(10,places)
  float d = 0.5;
  if (value < 0)
    d *= -1.0;
  // divide by ten for each decimal place
  for (i = 0; i < places; i++)
    d /= 10.0;
  tempfloat += d;

  // first get value tens to be the large power of ten less than value

  if (value < 0)
    tempfloat *= -1.0;
  while ((tens * 10.0) <= tempfloat)
  {
    tens *= 10.0;
    tenscount += 1;
  }

  // write out the negative if needed
  if (value < 0)
    Serial.print('-');

  if (tenscount == 0)
    Serial.print(0, DEC);

  for (i = 0; i < tenscount; i++)
  {
    digit = (int)(tempfloat / tens);
    Serial.print(digit, DEC);
    tempfloat = tempfloat - ((float)digit * tens);
    tens /= 10.0;
  }

  // if no places after decimal, stop now and return
  if (places <= 0)
    return;

  // otherwise, write the point and continue on
  Serial.print('.');

  // now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value
  for (i = 0; i < places; i++)
  {
    tempfloat *= 10.0;
    digit = (int)tempfloat;
    Serial.print(digit, DEC);
    // once written, subtract off that digit
    tempfloat = tempfloat - (float)digit;
  }
}

我希望返回校验和,但在使用非常大的样本量时会超时。我还应该补充一点,即使 ESP32 应该能够处理我的文件,我也不能将整个文件推送到串行端口,因为我收到缓冲区溢出错误。有解决办法吗?

【问题讨论】:

  • 提高通讯速度!以 9600bps 传输任何东西都需要很长时间。使用支持高速的 FTDI usb 到串行转换器,我在 PC (matlab) 和 8 位 micro (8051) 之间以 3,000,000bps 的速度进行通信,它就像一个魅力。我相信您至少可以通过标准 USB 转串口适配器使用 115200bps。
  • 另外,使用float 数据类型作为校验和对我来说似乎很奇怪。两个平台上的浮点舍入误差可能不同,即使输入相似,校验和也可能不匹配。我宁愿使用整数类型(例如uint32)作为校验和,并在逐字节级别而不是在奇异的[4字节]数据类型上进行校验和。
  • 感谢您的信息。我将研究适配器,尽管这只会在编写代码和测试时帮助我,我不能将它用于我最终想要的实际项目(不想让你厌烦细节)。关于校验和的好提示,我会试试你的想法。

标签: arrays matlab arduino serial-port arduino-c++


【解决方案1】:

第一个 %5.9f 对我来说没有意义。

最少 5 个字符,精度为 9 位。那 5 没有意义,因为您总是有至少 11 个字符,精度为 9 位

那么让我为你做一些数学运算:

96000 个样本,每个 12 个字符(包括\n)一共是 10368000 位。

在 9600 波特时,传输时间为 1080 秒。 -> 18 分钟。

当您在每个样本后添加 0.1 秒暂停时,您会再添加 9600 秒。

这样您总共需要 178 分钟(3 小时)的转移时间。

你期待什么?

对于 200 个样本,它仍然是 22.25 秒。

【讨论】:

  • 据我所知,ESP32 可以轻松支持高达 115200 的波特率。所以我会测试一下。理想情况下,我想要 20 位数的精度。是否有可能以可接受的速度做到这一点?
  • @user3601507 您最大的问题是 matlab 中的暂停。删除它。 ESP8266 能够达到几兆位。如果您的连接良好。 9600 用于低质量连接,此时可靠性比速度更重要
  • 我删除了它,它仍然有效。虽然我收到了这个错误:警告:读取失败:在达到终结者之前发生超时。我以前得到过这个,但我忽略了它,但它似乎没有意义,因为我得到了想要的结果至少有 200 个样本。
  • 我在中途不小心按了 Enter 后立即编辑了我的评论。不知道您是如何在我编辑之前如此快速地阅读并做出回应的。
  • @user3601507 我对这个世界来说太快了。序列号是not recommended。试试serialport,看看是否还有问题。
最近更新 更多