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

时间:2010-10-19 07:57:12

标签: algorithm embedded microcontroller pic

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

  
      
  1. 在微控制器中有一个带有10的模数转换器   比特分辨率。 (它将输出一个   值介于0和1023之间)

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

  4.   
  5. 但是你一次只能写8位。 (你需要写字节)。它是   微控制器的局限性。

  6.   
  7. 所以在上面的例子中至少我需要发送2个字节。

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

  10.   

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

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

总之,我需要以最快的方式在Serial上发送一个10位数的序列。 :)

4 个答案:

答案 0 :(得分:15)

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

定期抽样,未知连接点

如果设备一直在运行,您不确定何时连接(您可以在序列中的任何时间加入)但采样率低于通信速度,因此您不关心大小我想我可能会这样做。假设您尝试发送十位abcdefghij(每个字母一位)。

我发送pq0abcde然后pq1fghij,其中pqerror checking bits。这样:

  • 不需要分隔符(您可以通过0或1判断您正在读取哪个字节)
  • 你绝对可以发现任何1位错误,所以你知道坏数据

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

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

    密集数据,已知连接点

    如果您知道阅读器与编写器同时启动,则只需将4个10位值作为5个字节发送。如果你总是一次读5个字节那么没问题。如果您想节省更多空间并且已经拥有良好的样本数据,我将使用huffman coding进行压缩。

    密集数据,未知连接点

    在7个字节中,您可以发送5个10位值和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个连续的,120个以16个字节发送的比特):

    • 字节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

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

答案 1 :(得分:7)

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

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

答案 2 :(得分:4)

由于您指定了“最快的方式”,我认为将数字扩展为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;
}

答案 3 :(得分:0)

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