将数据发送到串行端口的最佳方式是什么?

发布于 2024-09-28 05:57:12 字数 614 浏览 0 评论 0原文

这与微控制器有关,但考虑将其发布在这里,因为这是算法和数据类型的问题,而不是任何硬件的问题。我会解释这个问题,以便没有任何硬件知识的人仍然可以参与:)

  1. 在微控制器中,有一个模数转换器,具有 10 位分辨率。 (它会输出一个 0 到 1023 之间的值)

  2. 我需要使用串口将该值发送到PC。

  3. 但是一次只能写入 8 位。 (您需要写入字节)。这是 微控制器的限制。

  4. 因此在上述情况下至少我需要发送 2 个字节。

  5. 我的 PC 应用程序只是读取一系列数字来进行绘图。所以 它应该捕获两个连续的 字节并构建该数字。但 这里我们需要一个分隔符 性格也是如此。但分隔符的 ascii 值仍然在 0 - 255 之间,那么它会混淆该过程。

那么最简单的方法是什么?我应该将值作为字符序列发送吗?

Ex : 1023 = "1""0""2""3" Vs "Char(255)Char(4)"

总之,我需要以最快的方式通过串行发送 10 位数字的序列。 :)

This is related with microcontrollers but thought to post it here because it is a problem with algorithms and data types and not with any hardware stuff. I'll explain the problem so that someone that doesn't have any hardware knowledge can still participate :)

  1. In Microcontroller there is an Analog to Digital converter with 10
    bit resolution. (It will output a
    value between 0 and 1023)

  2. I need to send this value to PC using the serial port.

  3. But you can only write 8 bits at once. (You need to write bytes). It is
    a limitation in micro controller.

  4. So in the above case at least I need to send 2 bytes.

  5. My PC application just reads a sequence of numbers for plotting. So
    it should capture two consecutive
    bytes and build the number back. But
    here we will need a delimiter
    character as well. but still the delimiter character has an ascii value between 0 - 255 then it will mixup the process.

So what is a simplest way to do this? Should I send the values as a sequence of chars?

Ex : 1023 = "1""0""2""3" Vs "Char(255)Char(4)"

In summary I need to send a sequence of 10 bit numbers over Serial in fastest way. :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

清风疏影 2024-10-05 05:57:12

您需要发送 10 位,并且因为一次发送一个字节,所以必须发送 16 位。最大的问题是速度有多重要,以及发送者和接收者的同步程度如何?根据这些条件,我可以想到 3 个答案。

定期采样,未知加入点

如果设备一直在运行,您不确定何时要连接(您可以按顺序随时加入),但采样率比通信速度慢,因此您不会关心尺寸我想我可能会这样做。假设您尝试发送十位abcdefghij(每个字母一位)。

我会发送 pq0abcde 然后发送 pq1fghij,其中 pq错误检查位。这样:

  • 不需要分隔符(您可以通过 0 或 1 来判断您正在读取哪个字节)
  • 您绝对可以发现任何 1 位错误,因此您了解不良数据

我正在努力寻找一个好的两位纠错代码,所以我想我只需为位 2,3 和 4(上面的 0、ab)设置 pa 奇偶校验位,为 5 6 和 7(上面的 c、d、e)设置 qa 奇偶校验位。通过一个例子可能会更清楚。

  1. 假设我要发送 714 = 1011001010。
  2. 分成 2 份 10110 , 01010
  3. 添加位来指示第一个和第二个字节 010110, 101010
  4. 计算每一半的奇偶校验: p0=par(010)=1, q0=par(110)=0, p1=par(101)=0, q1=par(010)=1
  5. 字节则为 10010110, 01101010

然后您可以检测到许多不同的错误情况,如果失去同步,则快速检查正在发送哪个字节,并且没有在微控制器中,这些操作需要很长时间(我会使用 8 项查找表进行奇偶校验)。

密集数据,已知连接点

如果知道读取器与写入器同时启动,只需将 4 个十位值作为 5 个字节发送即可。如果您总是一次读取 5 个字节,那么就没有问题。如果您想要节省更多空间,并且已经拥有良好的示例数据,我会使用 huffman 编码。

密集数据,未知连接点

在 7 个字节中,您可以发送 5 个十位值和 6 个备用位。发送如下 5 个值:

  • 字节 0: 0 (7 位)
  • 字节 1: 1 (7 位)
  • 字节 2: 1 (7 位)
  • 字节 3: 1 (7 位)
  • 字节 4: 0 (7 位)
  • 字节 5: 0 (7 位)
  • 字节 6:(8 位)

然后,每当您在最高有效位连续看到 3 个 1 时,您就知道您有字节 1、2 和 3。这个想法浪费了 56 中的 1 位,因此可以使偶数效率更高,但您必须一次发送更多数据。例如(连续 5 个,16 个字节发送 120 位):

  • 字节 0: 0 (7 位) 7
  • 字节 1: 1 (7 位) 14
  • 字节 2: 1 (7 位) 21
  • 字节 3: 1 (7 位) 28
  • 字节 4: 1 (7 位) 35
  • 字节 5: 1 (7 位) 42
  • 字节 6: 0 (7 位) 49
  • 字节 7: (8 位) 57
  • 字节 8: (8 位) 65
  • 字节 9: (8 位) 73
  • 字节 10:(8 位) 81
  • 字节 11:0(7 位) 88
  • 字节 12:(8 位) 96
  • 字节 13:(8 位) 104
  • 字节 14:(8 位)112
  • 字节 15:(8 位)120

这是一个非常有趣的问题!

You need to send 10 bits, and because you send a byte at a time, you have to send 16 bits. The big question is how much is speed a priority, and how synchronised are the sender and receiver? I can think of 3 answers, depending on these conditions.

Regular sampling, unknown join point

If the device is running all the time, you aren't sure when you are going to connect (you could join at any time in the sequence) but sampling rate is slower than communication speed so you don't care about size I think I'd probably do it as following. Suppose you are trying to send the ten bits abcdefghij (each letter one bit).

I'd send pq0abcde then pq1fghij, where p and q are error checking bits. This way:

  • no delimiter is needed (you can tell which byte you are reading by the 0 or 1)
  • you can definitely spot any 1 bit error, so you know about bad data

I'm struggling to find a good two bit error correcting code, so I guess I'd just make p a parity bit for bits 2,3 and 4 (0, a b above) and q a parity bit for 5 6 and 7 (c,d,e above). This might be clearer with an example.

  1. Suppose I want to send 714 = 1011001010.
  2. Split in 2 10110 , 01010
  3. Add bits to indicate first and second byte 010110, 101010
  4. calculate parity for each half: p0=par(010)=1, q0=par(110)=0, p1=par(101)=0, q1=par(010)=1
  5. bytes are then 10010110, 01101010

You then can detect a lot of different error conditions, quickly check which byte you are being sent if you lose synchronisation, and none of the operations take very long in a microcontroller (I'd do the parity with an 8 entry lookup table).

Dense data, known join point

If you know that the reader starts at the same time as the writer, just send the 4 ten bit values as 5 bytes. If you always read 5 bytes at a time then no problems. If you want even more space saving, and have good sample data already, I'd compress using a huffman coding.

Dense data, unknown join point

In 7 bytes you can send 5 ten bit values with 6 spare bits. Send 5 values like this:

  • byte 0: 0 (7 bits)
  • byte 1: 1 (7 bits)
  • byte 2: 1 (7 bits)
  • byte 3: 1 (7 bits)
  • byte 4: 0 (7 bits)
  • byte 5: 0 (7 bits)
  • byte 6: (8 bits)

Then whenever you see 3 1's in a row for the most significant bit, you know you have bytes 1, 2 and 3. This idea wastes 1 bit in 56, so could be made even more efficient, but you'd have to send more data at a time. Eg (5 consecutive ones, 120 bits sent in 16 bytes):

  • byte 0: 0 (7 bits) 7
  • byte 1: 1 (7 bits) 14
  • byte 2: 1 (7 bits) 21
  • byte 3: 1 (7 bits) 28
  • byte 4: 1 (7 bits) 35
  • byte 5: 1 (7 bits) 42
  • byte 6: 0 (7 bits) 49
  • byte 7: (8 bits) 57
  • byte 8: (8 bits) 65
  • byte 9: (8 bits) 73
  • byte 10: (8 bits) 81
  • byte 11: 0 (7 bits) 88
  • byte 12: (8 bits) 96
  • byte 13: (8 bits) 104
  • byte 14: (8 bits) 112
  • byte 15: (8 bits) 120

This is quite a fun problem!

痞味浪人 2024-10-05 05:57:12

最好的方法是将数据转换为 ASCII 字符串并以这种方式发送 - 它使调试变得更加容易,并且避免了各种通信问题(某些控制字符的特殊含义等)。

如果您确实需要使用所有可用带宽,那么您可以将 4 个 10 位值打包到 5 个连续的 8 位字节中。您需要小心同步。

The best method is to convert the data to an ASCII string and send it that way - it makes debugging a lot easier and it avoids various communication issues (special meaning of certain control characters etc).

If you really need to use all the available bandwidth though then you can pack 4 10 bit values into 5 consecutive 8 bit bytes. You will need to be careful about synchronization.

萌︼了一个春 2024-10-05 05:57:12

既然你指定了“最快的方法”,我认为将数字扩展到 ASCII 的可能性被排除了。

在我看来,可以通过以下编码获得代码简单性和性能的良好折衷:

两个 10 位值将像这样编码为 3 个字节。

第一个 10 位值位 := abcdefghij

第二个 10 位值位 := klmnopqrst

要编码的字节数:

1abcdefg
0hijklmn
0_opqrst

还有一位 (_) 可用,可用于对所有 20 位进行奇偶校验以进行错误检查或仅设置为固定值。

一些示例代码(在位置 _ 处放置 0):

#include <assert.h>
#include <inttypes.h>

void
write_byte(uint8_t byte);    /* writes byte to serial */

void
encode(uint16_t a, uint16_t b)
{
  write_byte(((a >> 3) & 0x7f) | 0x80);
  write_byte(((a & 3) << 4) | ((b >> 6) & 0x7f));
  write_byte(b & 0x3f);
}

uint8_t
read_byte(void);  /* read a byte from serial */

void
decode(uint16_t *a, uint16_t *b)
{
  uint16_t x;

  while (((x = read_byte()) & 0x80) == 0)  {}  /* sync */
  *a = x << 3;

  x = read_byte();
  assert ((x & 0x80) == 0); /* put better error handling here */

  *a |= (x >> 4) & 3;
  *b = x << 6;

  x = read_byte();
  assert ((x & 0xc0) == 0); /* put better error handling here */

  *b |= x;
}

Since you specified "the fastest way" I think expanding the numbers to ASCII is ruled out.

In my opinion a good compromise of code simplicity and performance can be obtained by the following encoding:

Two 10bit values will be encoded in 3 bytes like this.

first 10bit value bits := abcdefghij

second 10bit value bits := klmnopqrst

Bytes to encode:

1abcdefg
0hijklmn
0_opqrst

There is one bit more (_) available that could be used for a parity over all 20bits for error checking or just set to a fixed value.

Some example code (puts 0 at the position _):

#include <assert.h>
#include <inttypes.h>

void
write_byte(uint8_t byte);    /* writes byte to serial */

void
encode(uint16_t a, uint16_t b)
{
  write_byte(((a >> 3) & 0x7f) | 0x80);
  write_byte(((a & 3) << 4) | ((b >> 6) & 0x7f));
  write_byte(b & 0x3f);
}

uint8_t
read_byte(void);  /* read a byte from serial */

void
decode(uint16_t *a, uint16_t *b)
{
  uint16_t x;

  while (((x = read_byte()) & 0x80) == 0)  {}  /* sync */
  *a = x << 3;

  x = read_byte();
  assert ((x & 0x80) == 0); /* put better error handling here */

  *a |= (x >> 4) & 3;
  *b = x << 6;

  x = read_byte();
  assert ((x & 0xc0) == 0); /* put better error handling here */

  *b |= x;
}
余生一个溪 2024-10-05 05:57:12

我通常使用起始字节和校验和,在这种情况下是固定长度,因此发送 4 个字节,接收器可以查找起始字节,如果接下来的三个字节加起来达到已知数量,那么这是一个很好的数据包,取出中间两个字节字节,如果没有继续寻找。接收器总是可以重新同步,并且不会浪费ascii 的带宽。 Ascii 是您的另一个选择,一个不是数字的起始字节,可能是四个十进制数字。十进制在微控制器中绝对不好玩,所以从非十六进制的东西开始,例如 X,然后是您的数字的十六进制 ascii 值的三个字节。搜索 x 检查接下来的三个字节,希望得到最好的结果。

I normally use a start byte and checksum and in this case fixed length, so send 4 bytes, the receiver can look for the start byte and if the next three add up to a know quantity then it is a good packet take out the middle two bytes, if not keep looking. The receiver can always re-sync and it doesnt waste the bandwidth of ascii. Ascii is your other option, a start byte that is not a number and perhaps four numbers for decimal. Decimal is definitely not fun in a microcontroller, so start with something non-hex like X for example and then three bytes with the hex ascii values for your number. Search for the x examine the next three bytes, hope for the best.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文