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

Algorithm 将数据发送到串行端口的最佳方式是什么?,algorithm,embedded,microcontroller,pic,Algorithm,Embedded,Microcontroller,Pic,这与微控制器有关,但我想把它贴在这里,因为这是算法和数据类型的问题,而不是任何硬件的问题。我将解释这个问题,以便没有任何硬件知识的人仍然可以参与:) 在微控制器中,有一个模拟到数字转换器,具有10 位分辨率。(它将输出一个 值介于0和1023之间) 我需要使用串行端口将此值发送到PC 但您一次只能写入8位。(您需要写入字节)。它是 微控制器的局限性 所以在上面的例子中,我至少需要发送2个字节 我的PC应用程序只是读取一系列用于打印的数字。所以 它应该捕获两个连续的 字节,然后重新生成数字。但是

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

  • 在微控制器中,有一个模拟到数字转换器,具有10 位分辨率。(它将输出一个 值介于0和1023之间)

  • 我需要使用串行端口将此值发送到PC

  • 但您一次只能写入8位。(您需要写入字节)。它是 微控制器的局限性

  • 所以在上面的例子中,我至少需要发送2个字节

  • 我的PC应用程序只是读取一系列用于打印的数字。所以 它应该捕获两个连续的 字节,然后重新生成数字。但是 这里我们需要一个分隔符 性格也是如此。但是分隔符字符的ascii值仍然在0-255之间,那么它将混合处理

  • 那么,最简单的方法是什么呢?我应该以字符序列的形式发送值吗

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

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

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


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

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

    常规采样,未知连接点 如果设备一直在运行,您不确定何时连接(您可以在序列中的任何时间连接),但采样率低于通信速度,因此您不关心大小。我想我可能会按照以下方式进行连接。假设您试图发送十位(每个字母一位)

    我会发送
    pq0abcde
    然后发送
    pq1fghij
    ,其中
    p
    q
    是。这样:

    • 不需要分隔符(您可以通过0或1判断正在读取的字节)
    • 您完全可以发现任何1位错误,这样您就可以了解坏数据
    我正在努力寻找一个好的两位纠错码,所以我想我应该让p成为位2、3和4(0,上面的AB)的奇偶校验位,让q成为位5、6和7(上面的c、d、e)的奇偶校验位。举个例子,这可能更清楚

  • 假设我想发送714=1011001010
  • 分成210101010份
  • 添加位以指示第一和第二字节010110、101010
  • 计算每一半的平价:p0=par(010)=1,q0=par(110)=0,p1=par(101)=0,q1=par(010)=1
  • 然后字节为10010110、01101010
  • 然后,您可以检测许多不同的错误情况,如果失去同步,可以快速检查正在发送的字节,并且在微控制器中没有任何操作需要很长时间(我会使用8项查找表进行奇偶校验)

    密集数据,已知连接点 如果您知道读卡器与写卡器同时启动,只需将4个10位值作为5个字节发送即可。如果您总是一次读取5个字节,那么没有问题。如果您想要节省更多空间,并且已经有了好的示例数据,我会使用压缩

    密集数据,未知连接点 在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分之一的时间,因此可以使效率更高,但您必须一次发送更多的数据。例如(5个连续的1,以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
    这是一个很有趣的问题

    由于您指定了“最快的方式”,我认为将数字扩展为ASCII是不可能的

    在我看来,通过以下编码可以很好地兼顾代码的简单性和性能:

    两个10位值将以3字节的形式编码,如下所示

    前10位值位:=abcdefghij

    第二个10位值位:=klmnopqrst

    要编码的字节:

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

    一些示例代码(将0放在位置u):

    #包括
    #包括
    无效的
    写入字节(uint8字节);/*将字节写入串行*/
    无效的
    编码(uint16\u t a,uint16\u t b)
    {
    写入字节((a>>3)和0x7f)| 0x80);
    写入字节((a&3)>6)和0x7f);
    写入字节(b&0x3f);
    }
    uint8\u t
    读取字节(空);/*从串行存储器中读取一个字节*/
    无效的
    解码(uint16\u t*a,uint16\u t*b)
    {
    uint16_t x;
    而((x=read_byte())&0x80)==0{}/*sync*/
    *a=x>4)和3;
    
    *b=x我通常使用一个起始字节和校验和,在这种情况下是固定长度的,因此发送4个字节,接收器可以查找起始字节,如果接下来的三个字节加起来是一个已知数量,则为
    #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;
    }