最大化Arduino串行输出 [英] Maximize Arduino serial output

查看:23
本文介绍了最大化Arduino串行输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇文章中穿插了多个问题.请仔细阅读并回答您可以投票的部分.

There are a multiple questions intersperced throughout this post. Kindly read carefully and answer the pieces you can for an upvote.

创建压力读数的时间序列 csv 文件.这些读取需要具有最大频率,但我只需要它持续不到 10 秒左右.

Create a time series csv file of pressure reads. These reads need to be of maximum frequency, but I only need it to last less than 10 seconds or so.

  1. Arduino Uno Clone(不可更改)
  2. 通过 USB 2.0 串行(可更改)
  3. pyserial (Python 3)
  4. 固态硬盘

问题

识别并修复瓶颈,防止频率达到最大读取/秒.

Problem

Identify and fix the bottleneck preventing frequency from maximum reads/s.

void setup() {
  //speed over the usb serial interface
  Serial.begin(450000);
}

void loop() {
    //get sensor data: read the input on analog pin 0:
    int sensorValue = analogRead(A0); //returns value 0-1023
    //send over serial
    Serial.println(sensorValue);
}

Python

...
ser.serial()
ser.baudrate=450000
ser.open()
while True:
    try:
        serialData = float(ser.readline().decode().replace('\n', ''))
    except(ValueError):
        continue #I ran the code without this try/except and got 100 reads higher than when this is included in here. Caused no change in order of magnitude.
    now = datetime.datetime.now()
    serialData2 = serialData * voltageOffset #a couple of these happen
    outfile.write(now+', '+str(serialData2)+'\n')
except(KeyboardInterrupt):
    ...
    os.sys.exit(0)

带宽

一些计算来找出瓶颈所在.

Bandwidths

Some calculations to figure out where the bottleneck resides.

100 µs 读取模拟引脚

1 个数据包 = 10 位

1 packet = 10 bits

串口线速:450000/10 = 45000包/秒

serial wire speed: 450000/10 = 45000 packets / second

Arduino 采样串行/秒速率:

100 µs * 1s/(10^-6 µs) = 1 x 10^4 个样本/秒

100 µs * 1s/(10^-6 µs) = 1 x 10^4 samples / second

arduino 硅适配器:廉价的克隆芯片.假设性能不佳,因为它不是 arduino 许可的产品,但这被认为是可接受的损失,稍后将解释.假设具有无限带宽,尽管这显然会提高一个数量级的性能.

arduino silicon adapter: cheap cloned chip. Assumed to be underperforming as it is not an arduino-licensed product, but this is deemed acceptable loss as will be explained later. Assumed to have unlimited bandwidth, though this obviously will increase performance by an order of magnitude.

USB 2.0

包/秒 = 480 mb/s * 10^6 b/mb * 1 包/10 b = 48 x 10^6 包/秒

packets/s = 480 mb/s * 10^6 b/mb * 1 packet/10 b = 48 x 10^6 packets / second

PC文件写入速度

400 MB/s = 320 x 10^6 数据包/s

400 MB/s = 320 x 10^6 packets/s

PC python 脚本

未知.假设是无限的?已知 datetime.now() 查询需要大约 8 微秒.

Unknown. Presumed to be infinite? the datetime.now() query is known to take ~ 8 µs.

结论:瓶颈是串口波特率.

调整波特率证实了这一点.我发现 el-cheapo arduino uno 仅支持最大 450000 波特率,当 arduino 实际上支持 2-7 百万,我可以在网上收集到的数据.话虽如此,还是有些不对劲.

Adjusting the baud rate confirms this. I'm finding that el-cheapo arduino uno only supports a maximum 450000 baud rate, when the arduino actually supports 2-7 million from what I can gather online. That being said, something is still wrong.

回想一下,在这个波特率下,我们应该看到以 45000 包/秒的理论生成压力读取.

Recall that at this baud rate, we should be seeing pressure reads generated at a theoretical 45000 packets / second.

波特率-数据长度-无奇偶校验-1结束位:450000-8-n-1

baudrate-data length-no parity-1 end bit present: 450000-8-n-1

sensorValue = 1023.数据看起来像这样进入 println:1023\n

Let sensorValue = 1023. Data looks like this going into println: 1023\n

当我在 arduino 中运行 serial.println(sensorValue) 时,有多少数据包通过线路发送到 PC?这是如何序列化成数据包的?将通过线路发送多少数据包?以下哪一项是正确的:

When I run serial.println(sensorValue) in the arduino, how many packets are sent over the wire to the PC? How is this serialized into packets? How many packets will be sent over the wire? Which one of the following is true:

A.16 位 int 需要传输 2 个数据包.\n 需要 2 个.总计 = 4

A. 16 bit int requires 2 packets to be transmitted. The \n exacts 2 more. Total = 4

B.sensorValue 被转换为一个字符串并通过单独的数据包通过线路发送:1 表示 1,1 表示 0,1 表示 23 1 个,\ 1 个,n 1 个.总计 = 6

B. sensorValue is converted to a string and sent over the wire with separate packets: 1 for 1, 1 for 0, 1 for 2, 1 for 3, 1 for \, and 1 for n. Total = 6

C.其他(帮我优化??)

我没有看到预期的结果.

I'm not seeing results as I would expect.

baud = 450000.

更改 arduino 代码中的 value serial.println(value) 在我的 txt 文件中产生不同的读取/秒:

Changing value in the arduino code serial.println(value) produces different reads/second in my txt file:

value = readPin\n >> 5417 次压力读取/秒

value = readPin\n >> 5417 pressure reads/s

value = 1 >> 10201 次读取/秒

value = 1 >> 10201 reads/s

value = 1023 >> 4279 次读取/秒

value = 1023 >> 4279 reads/s

这告诉了我一些事情.读取analogPin 的值时存在开销.我还可以得出结论,arduino 也仅在需要时发送多个数据包(1 > 8 位数据,1023 > 16 位数据).等等,什么?这没有多大意义.这是怎么发生的?

This tells me a couple things. There is overhead when reading the analogPin's value. I can also conclude the arduino also only sends over multiple packets of data when it has to (1 > 8 bit of data, 1023 > 16 bit of data). Wait, what? That doesn't make very much sense. How does that happen?

调整波特率会导致读取次数发生变化,直到 arduino 达到最大值.但是让我们找出我应该期望的吞吐量.

Adjusting the baud rate causes the number of reads to change until the arduino maxes out. But lets find the throughput I should be expecting.

450000 b/s * (1 包/10b) * [1 读取/(4 或 6 包)] = 11250 读取或 7500 理论读取/秒

450000 b/s * (1 packet / 10b) * [1 read / (4 or 6 packets)] = 11250 reads OR 7500 theoretical reads/s

实际 = 5417 次读取/秒

Actual = 5417 reads/s

2,000 个读数消失到哪里去了?

推荐答案

你说的对,瓶颈是串口(在你传输数据的效率低下).但是,您的大多数其他假设都是错误的.

You are right that the bottleneck is the serial port (in the sense that you transmit data inefficiently). However, most of your other assumptions are wrong.

波特率代表什么

波特率是每秒不同符号变化的数量.这里相当于每秒位数.波特率将包括传输的所有位,而不仅仅是数据(开始、停止、奇偶校验).

Baud rate is the number of distinct symbol changes per second. Here it would be equivalent for bits per second. The baud rate would include all bits transmitted, not only data (start, stop, parity).

如何传输 10 位值

由于您使用 8n1 传输,因此您无法准确发送 10 位数据.它必须是 8 的倍数,因此 8、16、24 等. 10 位将在两个 8 位部分中发送,就像它们作为 int 存储在 Arduino 内存中一样.

As you have 8n1 transmission, you cannot send exactly 10 bits of data. It must be a multiple of 8, so 8, 16, 24, etc. 10 bits will be sent in two 8 bit parts, just like they are stored in Arduino memory as an int.

println() 是如何工作的

println() 将数字转换为字符串.您可以为此转换指定基数(DEC、BIN、HEX、OCT) - 默认为 DEC,因此 1023 将作为 4 个字节 + \n 传输,这是一个单字节(ASCII 10)和 \r (ASCII 13) 这也是一个单字节.总共 6 个字节.1 将需要 3 个字节 - 1 个用于数据,2 个用于换行和回车.

println() converts numbers to string. You can specify base for this conversion (DEC, BIN, HEX, OCT) - default is DEC, so 1023 will be transmitted as 4 bytes + \n which is a single byte (ASCII 10) and \r (ASCII 13) which is also a single byte. Total of 6 bytes. 1 will require 3 bytes - 1 for data and 2 for newline and carriage return.

如何让它更快

  1. 几乎无需更改任何内容 - 使用 println(val, HEX) - 对于大于 255 的数字,您最多需要 5 个字节.
  2. 使用 Serial.write() - 此函数将原始二进制数据放入串行中,因此如果您想发送值 10,它只会发送值 10 的一个字节.但是,当您想要发送 10 位变量,事情变得复杂 - 你需要 2 个字节,PC 需要知道哪个是第一部分,哪个是第二部分才能将其拼接在一起.您需要想出某种形式的简单传输协议来处理此问题,因此可能需要一些开始/停止字符.
  3. 您需要 10 位分辨率吗?如果您可以继续使用 8 位,则可以只传输纯数据,而无需任何其他字符.此外,正如评论中所建议的那样,您可以使用更快的 ADC 时钟.
  4. KIIV 也建议 - 您可以使用 ADC 转换中断,该中断会在测量完成后立即触发.
  1. Without changing almost anything - use println(val, HEX) - you will need 5 bytes maximum for numbers greater than 255.
  2. Using Serial.write() - this function puts raw binary data into serial, so if you want to send a value 10, it will send just one byte of value 10. However, when you want to send 10-bit variable, things get complicated - you need 2 bytes for that, and PC needs to know which is the first part and which is second to stitch it back together. You will need to come up with some form of simple transmission protocol to handle this, so probably some start/stop character.
  3. Do you need 10-bits resolution? If you could get on with 8-bits you could transmit just plain data, without any additional characters. Also, as suggested in the comments, you could use faster ADC clock then.
  4. Also suggested by KIIV - you could use ADC conversion interrupt that would trigger instantly when the measurement is completed.

如果您仍然使用 10 位,我建议使用 3 字节帧:1 个起始字节和 2 个字节的数据.通过这种方式,理论上您可以达到每秒 18 000 帧,高于最大 analogRead() 频率.

If you still go with 10-bit, I would suggest 3-byte frame: 1 start byte, and 2 bytes of data. This way you could theoretically reach ~18 000 frames per second, which is above the maximum analogRead() frequency.

这篇关于最大化Arduino串行输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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