1

つまり、2 つのマイクロコントローラー間に通信システムがあり、それらの間でデータを送信しています。つまり、1 つの µC から別の µC にセンサー データを送信し、コマンドを返します。センサー データは構造体から取得され、次のようなフレームに配置されます (識別子 "SENSORFRAME" は一定ではなく、フレームの内容によって異なります)。

sprintf(message, "\:\\SENSORFRAME\:%.2f;%.2f;%.2f;%d;%d;%u\r\r",
               input.temperature, input.current, input.voltage,
               input.dutycycle,input.lightsensor, input.message);

次のようなフレームになります。

:\SENSORFRAME:-12.40;1.42;0.53;500;1200;8\r\r

またはコマンドフレームの場合:

sprintf(message, "\:\\COMMANDFRAME\:%u;%.5f\r\r", input.command, input.data);

次のようなフレームになります。

:\COMMANDFRAME:3;1.42\r\r

バイトストリームが 1 つのマイクロコントローラーに到着すると、処理されるまで単純なリング バッファーに書き込まれます。

ここで私の 2 つの質問は、まず、バイトストリーム内のフレーム、つまり「:\」と「\r\r」の間のすべてを識別するための最良の方法は何か、そして次にそれを構造体に効率的に解析する方法 — いくつかの組み合わせです。 ( strtok" ;" および " :") の、およびatoi/ atof?

4

1 に答える 1

0

最後にダブル キャリッジ リターン (CR) を読み取るまでフレームのタイプを処理せず、ダブル CR の後にヌル バイトを挿入する場合は、sscanf()またはその他の解析手法を使用してフレーム タイプ情報を抽出できます。

char frame_type[32];
char colon[2];
int  offset;
if (sscanf(ring_buffer, ":\\%31[^:]%[:]%n", frame_type, colon, &offset) != 2)
    …deal with malformatted frame…

これで、フレーム タイプがframe_type文字列として取得されました。少し奇数%[:]はコロンのみに一致します。ただし、重要なのは、それが成功した変換としてカウントされ、%n変換が有効になることです。次のように変更された場合:

if (sscanf(":\\%31[^:]:%n", frame_type, &offset) != 1)
    …deal with malformatted frame…

末尾のコロンが一致したかどうかはわかりません。またoffset、有効な値 (前の文字であるコロンが見つかった文字列へのオフセット) が保持されているかどうかもわかりません。

少なくとも 2 つのフレーム タイプがあります。合計でいくつありますか (現時点では、将来的には可能性があります)? あるレベルでは、それは問題ではありません。可能なフレーム タイプに対して一連の文字列比較を使用するか、フレーム タイプ文字列のハッシュを使用してそれを有効なハッシュ値のセットと比較するか、別のメカニズムを考案することができます。

使用しているフレーム タイプがわかれば、残りのデータを読み取るために使用するフォーマット文字列がわかります。二重の CR まで読んだので、エンディングにそれが含まれていることがわかります — 再度検証する必要はありません。

たとえば、センサー フレームの場合、次のように使用できます。

if (sscanf(ring_buffer + offset, "%.2f;%.2f;%.2f;%d;%d;%u",
           &input.temperature, &input.current, &input.voltage,
           &input.dutycycle, &input.lightsensor, &input.message) != 6)
    …deal with malformatted sensor frame…

または、コマンド フレームの場合は、次を使用できます。

if (sscanf(ring_buffer + offset, "%u;%.5f\r\r", &input.command, &input.data) != 2)
    …deal with malformatted command frame…

唯一の複雑な要因は、リング バッファーを使用していることです。これは、最初の 5 バイトがリング バッファーの最後にあり、残りがバッファーの先頭にあるように、センサー フレームが分割されていることを意味している可能性があります。率直に言って、スペースとコピーに余裕がある場合は、リング バッファーを通常の (線形?) バッファーに変換するのが最も簡単です。それが絶対に不可能な場合は、おそらくまったく使用しないことsscanf()になります。sscanf()リング バッファの形状を伝えることができる独自のバリアントを記述してそれを操作するか、一度に文字を操作する必要があります。

おそらく、カスタム関数は次のとおりです。

int rbscanf(const char *rb_base, int rb_len, int rb_off, const char *format, ...);

リング バッファは から始まり、合計rb_baseでバイト長です。rb_lenデータは から始まります&rb_base[rb_off]rb_lenバッファー長とデータ長 (および)を指定する必要がある場合がありますrb_nbytes。リング バッファーを記述した構造体が既にある可能性があります。その場合は、それを関数に渡す (へのポインター) ことができます。

または、フレーム全体を読み取る前にデータを処理する場合は、バイトを読み取るときに検証できます。変換のために文字列と数値を蓄積する必要があります。strtol()andstrtod()ではなくatoi()and を使用することになるでしょうatof()atoi()およびatof()関数では通知できない、変換されていない文字の末尾などのエラーについて知る必要があります。機能には注意が必要ですが、strtoX()効果的です。

于 2015-12-16T00:49:23.350 に答える