9

これはマイクロコントローラーに関連していますが、アルゴリズムとデータ型の問題であり、ハードウェアの問題ではないため、ここに投稿することを考えました。ハードウェアの知識がない人でも参加できるように問題を説明します:)

  1. マイクロコントローラーには、10ビットの分解能を持つアナログ-デジタルコンバーターがあります。(0から1023までの値を出力します)

  2. シリアルポートを使用してこの値をPCに送信する必要があります。

  3. ただし、一度に書き込むことができるのは8ビットのみです。(バイトを書き込む必要があります)。これはマイクロコントローラーの制限です。

  4. したがって、上記の場合、少なくとも2バイトを送信する必要があります。

  5. 私のPCアプリケーションは、プロットのために一連の数字を読み取るだけです。したがって、2つの連続したバイトをキャプチャし、数値を元に戻す必要があります。ただし、ここでは区切り文字も必要になります。ただし、区切り文字のASCII値は0〜255であるため、プロセスが混乱します。

では、これを行う最も簡単な方法は何ですか?値を一連の文字として送信する必要がありますか?

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

要約すると、10ビット番号のシーケンスをシリアル経由で最速の方法で送信する必要があります。:)

4

4 に答える 4

15

10ビットを送信する必要があり、一度に1バイトを送信するため、16ビットを送信する必要があります。大きな問題は、速度がどれだけ優先されるか、そして送信者と受信者がどの程度同期しているかということです。これらの条件に応じて、3つの答えが考えられます。

定期的なサンプリング、不明な参加ポイント

デバイスが常に稼働している場合、いつ接続するかはわかりませんが(シーケンスのどの時点でも参加できます)、サンプリングレートは通信速度よりも遅いため、サイズは気にしないと思います。おそらく次のようにします。10ビットabcdefghij(各文字は1ビット)を送信しようとしているとします。

pq0abcde次にpq1fghij、を送信します。ここで、pおよびqエラーチェックビットです。こちらです:

  • 区切り文字は必要ありません(どのバイトを読んでいるかは0または1でわかります)
  • 1ビットエラーを確実に見つけることができるので、悪いデータについて知っています

私は良い2ビットエラー訂正コードを見つけるのに苦労しているので、ビット2、3、4(0、上記のab)にはpaパリティビットを、5 6、7(c、上記のd、e)。これは、例を使用するとより明確になる可能性があります。

  1. 714=1011001010を送信するとします。
  2. 2に分割10110、01010
  3. 1番目と2番目のバイトを示すビットを追加する010110、101010
  4. 各半分のパリティを計算します:p0 = par(010)= 1、q0 = par(110)= 0、p1 = par(101)= 0、q1 = par(010)= 1
  5. その場合、バイトは10010110、01101010になります。

次に、さまざまなエラー状態を検出し、同期が失われた場合に送信されているバイトをすばやく確認できます。マイクロコントローラーでは、どの操作にもそれほど時間はかかりません(8エントリのルックアップテーブルと同等の処理を行います)。

高密度データ、既知のジョインポイント

リーダーがライターと同時に起動することがわかっている場合は、4つの10ビット値を5バイトとして送信するだけです。一度に常に5バイトを読み取る場合は、問題ありません。さらにスペースを節約したい場合で、すでに優れたサンプルデータがある場合は、ハフマンコーディングを使用して圧縮します。

高密度データ、不明な参加ポイント

7バイトでは、6つのスペアビットを含む5つの10ビット値を送信できます。次のように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

これはとても楽しい問題です!

于 2010-10-19T08:10:59.307 に答える
7

最良の方法は、データをASCII文字列に変換して送信することです。これにより、デバッグがはるかに簡単になり、さまざまな通信の問題(特定の制御文字の特別な意味など)が回避されます。

ただし、実際に使用可能なすべての帯域幅を使用する必要がある場合は、4つの10ビット値を5つの連続する8ビットバイトにパックできます。同期に注意する必要があります。

于 2010-10-19T08:01:53.400 に答える
4

「最速の方法」を指定したので、ASCIIに数値を拡張することは除外されていると思います。

私の意見では、コードの単純さとパフォーマンスの適切な妥協点は、次のエンコーディングによって得られます。

2つの10ビット値はこのように3バイトでエンコードされます。

最初の10ビット値ビット:= abcdefghij

2番目の10ビット値ビット:= klmnopqrst

エンコードするバイト:

1abcdefg
0hijklmn
0_opqrst

エラーチェックのために20ビットすべてのパリティに使用できるか、固定値に設定するだけで、もう1ビット(_)を使用できます。

いくつかのサンプルコード(位置_に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;
}
于 2010-10-19T08:45:22.127 に答える
0

私は通常、開始バイトとチェックサムを使用しますが、この場合は固定長なので、4バイトを送信すると、受信者は開始バイトを探すことができ、次の3つが既知の量になる場合は、真ん中の2つを取り出すのに適したパケットです。探し続けるのでなければ、バイト。受信機はいつでも再同期でき、ASCIIの帯域幅を浪費しません。Asciiは他のオプションであり、数値ではなく、おそらく10進数の場合は4つの数値である開始バイトです。マイクロコントローラーでは10進数は絶対に面白くないので、たとえばXのような16進数以外のものから始めて、次に3バイトで数値の16進数のASCII値を指定します。xを検索して、次の3バイトを調べ、最良のものを期待します。

于 2010-10-19T12:08:13.173 に答える