シンプルなコマンドラインインターフェイス
コンポーネントと消耗品
> |
| × | 1 |
このプロジェクトについて
コマンドライン
センサーの値を見つける必要があるとき、またはロボットに「左に移動」のようなことをするように指示したいときが来ます。変数の実行時の値をプログラムに要求するか、デジタルポテンショメータの値を設定する必要があるかもしれません。
必要なのはコマンドラインです。はい、Arduinoにテキストコマンドに応答させるのは簡単です。
<図>これがあなたが構築できるものです。シンプルで高速、そして非常にメモリ効率の良いコマンドラインインターフェース (CLI)数分で自分のコードにカットアンドペーストして、稼働させることができます。コマンドは、名前とそれに続く複数の引数で構成されます。コマンドを入力するときにバックスペースもサポートします。
クイック概要
すべてのスケッチには loop()
があります 関数。以下のような単純なものにすることができます。 CommandLine.h
という名前の別のタブで2つのルーチンを呼び出します 。これらの2つのファイルについて説明します。これで、稼働状態になります。
ループ
機能: 毎回 loop()
実行して、シリアルポートからのコマンドがあるかどうかを確認し、 getCommandLineFromSerialPort()
を呼び出します。 。変数 CommandLine
CommandLine.h
で宣言されています ただし、スタイル的には、メインの[ループ]タブに移動することをお勧めします。完全なコマンドがシリアルポートに到着し、コマンドバッファにコピーされた場合:
char commandLine [COMMAND_BUFFER_LENGTH + 1];
次に、 loop()
DoMyCommand()
を呼び出します 適切なコマンドを実行します。
それでは、 CommandLine.h
の内容を見てみましょう。 。すべてのコードを CommandLine.h
に配置したことを指摘しておく必要があります 、それからあなたがしなければならないのはあなたのArduinoIDEの新しいタブにこのコードをカットアンドペーストすることだけだからです(タブに「 .h
」で終わる名前を付けてください ")。次に、このファイルをメインファイルに含めます。つまり
#include "CommandLine.h"
これにより、すべてのコマンドラインコードを1つのタブに配置しながら、追加のコードなしでプログラムの他の場所でそのルーチンを参照できるようになります。
CommandLine.hを見る
ファイル CommandLine.h
この投稿の最後に含まれています。 CommandLine.h
内 、変更する必要のある各行には、コメント //ここで変更
が付けられています。 。このファイルには、2つのサンプルコマンド add
が含まれています および sub
DoMyCommand
内からそれらがどのように呼び出されるかを示します 。
多くの人にとって、必要なのはそれだけです。 CommandLine.h
を実行するだけです 。より詳細な外観が必要な場合は、読み続けてください。
深く見る
CommandLine.h
内 最初に
を含めます 。 String.h
C標準ライブラリです 。これまでにCライブラリに遭遇したことがない場合は、インターネットで「Cプログラミング言語」をすばやく検索してください。聖書は何年も前にブライアン・カーニハンとデニス・リッチーによって書かれ、最新の状態に保たれています。ほとんどの人がコピーを所有していますが、オンラインで無料で見つけることができます。
strtok()
のみを使用します
からのルーチン(文字列からトークン) 。このルーチンは、トークン、つまり特定の文字で区切られた単語( strtok
の2番目のパラメーター)を読み取ります。 )。このように機能します。
- 最初に呼び出すときに、文字列
ptr
を渡します。 最初のトークンを返します
- 後続の呼び出しで(ここに素晴らしいハック部分があります)、文字列
ptr
の代わりにNULLを渡します そして、最初の文字列で中断したところから続行するため、一度に1つのトークン(おおよそ1つの単語)を取得します。
も含まれています ここからは atoi()
のみを使用します ASCIIから整数への変換用。心配しないでください。コンパイラには、ライブラリ全体ではなく、この1つのルーチンのみが含まれますが、これらのライブラリの他のルーチンは便利なのでチェックすることをお勧めします。
次は、私が書いた print2:
というオプションの小さなマクロです。
#define print2(x、y)(Serial.print(x)、Serial.println(y)
いつもラベルと文字列を印刷したいです。次のように使用します:
print2( "myVar ="、myVar);
myVarが25の場合、これはシリアルウィンドウに出力されます:
myVar =25
CommandLine.h
getCommandLineFromSerialPort()
が含まれています シリアルポートからコマンドラインをアセンブルします。呼び出されるたびに、シリアルポートから読み取り、入力をグローバル入力バッファー CommandLine []
に格納します。 。 return
に達したとき コマンドの終わりを示す文字は、 true
を返します 。
完全にアセンブルされたバッファが DoMyCommand()
に渡されるようになりました これは、ユーザーがどの機能を要求しているかを把握し、それを呼び出します。多数のコマンドを使用すると、かなり扱いにくいif-the-elseステートメントを取得できます。
本当に膨大な数のコマンドがある場合、ハッシュ関数と呼ばれるものを採用するなど、処理を高速化する方法はたくさんあります。または、コマンドを1文字だけにして、その1文字をswitch-caseステートメントのラベルとして使用することもできます。これらのどちらもあまり必要ではないと思います。単語は単一の文字よりもはるかに覚えやすく、これがArduinoであることを考えると、チップのスペースが不足する前に実際にいくつのコマンドを使用できますか?
追加とサブ
各コマンド関数は、それ自体の引数を解析する責任があります。これは簡単な方法であり、変更も簡単です。これに代わる方法は、 DoMyCommand
ですべての引数をすぐに読み取ることです。 。個々の引数を文字列のグローバル配列に入れることができます argv []
。
この例の目的のために、2つのコマンドを定義しました: add
および sub
。これらは両方とも数値引数を使用しますが、 readWord
を含めました (これは readStringToken
と呼ぶことができます )単語を返します。この readStringToken
を変更することもできます 「 this is a string
」などの文字列を許可するには 「。読者に任せた演習だと考えてください。
実行するための最速の方法
上記のようなメインループファイルがある場合は、Arduino IDEウィンドウの右側にある下向きの三角形を使用して新しいタブを作成し、 CommandLine.h
をコピーします。 (下の)ファイルに、 add
と入力できるはずです。 および sub
コマンド。
今はあなた次第です!
コード
- Arduino用のシンプルなコマンドラインインタープリター
Arduino用のシンプルなコマンドラインインタープリター C / C ++
Arduinoスケッチに簡単なコマンドラインを追加するには、この記事またはコードのコメントを参照してください。次のようなコマンドを追加できます。
5、10を追加
10、5を引く
または他に必要なもの
/ ***************************************** ************************************コマンドラインの使用方法:スケッチを作成します。サンプルセットアップとメインループコードを以下で確認し、それをコピーして新しいスケッチに貼り付けます。新しいタブを作成します。 (Arduinoエディターの右端にあるドロップダウンメニュー(小さな三角形)を使用します。タブにCommandLine.hという名前を付けます。このファイルをそのファイルに貼り付けます。テスト:作成したスケッチを通常どおりArduinoにダウンロードし、シリアルウィンドウを開きます。これらのコマンドを入力してからreturnを実行します。add5、10 subtract 10、5含まれているaddおよびsubtractコマンドを確認してから、独自のコマンドを記述します。********************* ************************************************** ******これがカバーの下で起こっていることです************************************* ****************************************シンプルで明確なコマンドラインインタープリターこのファイルでは、 Arduinoで実行されているスケッチに23,599blink 5 playSong昨日を追加して、シリアルウィンドウにコマンドを入力し、実行します。実装上の注意:これは、コマンドラインが必要な場合の前提に基づいて、文字列オブジェクトではなくC文字列を使用します。通訳、あなたはおそらく不足していますスペースもあり、Stringオブジェクトはスペース効率が悪い傾向があります。 1)単純なプロトコルコマンドは、スペースまたはコンマで区切られた単語と数字です。最初の単語はコマンドで、追加の各単語は引数です。「\ n」は各コマンドを終了します。2)Cライブラリルーチンstrtokの使用:コマンドは、スペースまたはコンマ。特定の文字(スペースやコンマなど)で区切られた単語は、トークンと呼ばれます。トークンを1つずつ取得するには、C libルーティングstrtokを使用します(C stdlib.hの一部で、トークンを含める方法を以下に示します)。これは、オンラインで検索できるC言語ライブラリの一部です。基本的にあなたは:1)文字列(および使用するデリメータ、つまりスペースとコンマ)を渡すと、文字列から最初のトークンが返されます2)後続の呼び出しで、(文字列ptrの代わりに)NULLを渡します。最初の文字列で中断したところから続行します。いくつかの基本的なヘルパールーチンを作成しました。readNumber:strtokとatoi(atoi:asciiからint、これもC stdlib.hの一部)を使用して整数を返します。 atoiはintを返すことに注意してください。また、uint8_tのような1バイトのintを使用している場合は、lowByte()を取得する必要があります。 readWord:ptrをテキストワードに返します。4)DoMyCommand:各コマンドのif-then-elsesのリスト。すべてのコマンドが単一の文字である場合、これをcaseステートメントにすることができます。単語を使用すると読みやすくなります。この例では、次のようになります。AddSubtract nullCommand * // ******************サンプルメインループコード************* *********************** #include "CommandLine.h" void setup(){Serial.begin(115200); } void loop(){bool receive =getCommandLineFromSerialPort(CommandLine); //グローバルコマンドラインはCommandLine.hで定義されていますif(received)DoMyCommand(CommandLine); } ************************************************* ********************************* ///このタブに名前を付けます:CommandLine.h#include #include //この次のマクロは、デバッグに適しています。例: print2( "myVar ="、myVar); #define print2(x、y)(Serial.print(x)、Serial.println(y))#define CR '\ r'#define LF '\ n'#define BS '\ b'#define NULLCHAR '\ 0'#define SPACE '' #define COMMAND_BUFFER_LENGTH 25 //着信コマンドのシリアルバッファの長さcharCommandLine [COMMAND_BUFFER_LENGTH + 1]; //シリアルからこのバッファにコマンドを読み込みます。終了の長さ+ 1charconst char * delimiters ="、\ n"; //コマンドは、return、space、またはコンマで区切ることができます/ ************************************* ************************************************** **********************ここにコマンド名* / const char * addCommandToken ="add"; // hereconstcharを変更します* subtractCommandToken ="sub"; //ここで変更/ ********************************************* ************************************************** ************** getCommandLineFromSerialPort()次のコマンドの文字列を返します。コマンドはreturnで区切られます "HandleBackSpace文字すべての文字を小文字にします************************************* ************************************************** ********************** / boolgetCommandLineFromSerialPort(char * commandLine){static uint8_t charsRead =0; //注:COMAND_BUFFER_LENGTHは255文字未満である必要があります// (Serial.available()){char c =Serial.read(); switch(c){case CR://現在バッファに完全なコマンドがある可能性があります。コマンドはCRおよび/またはで終了します。 LSケースLF:commandLine [charsRead] =NULLCHAR; //コマンドchar配列をnullで終了if(charsRead> 0){charsRead =0; // charsReadは静的であるため、Serial.println(commandLine);をリセットする必要がありますtrue; } break; case BS://入力でバックスペースを処理する:最後のchにスペースを入れるar if(charsRead> 0){//そしてcommandLineとcharsReadを調整しますcommandLine [-charsRead] =NULLCHAR;シリアル<<バイト(BS)<<バイト(スペース)<<バイト(BS); //これがどのように機能するかわからない、インターネットで見つけた} break;デフォルト:// c =tolower(c); if(charsRead 合計は="、result); } else {if(strcmp(ptrToCommandName、subtractCommandToken)==0){//ここで変更result =extractCommand(); // K&R string.hpg。 251 print2( ">違いは="、result); } else {nullCommand(ptrToCommandName); }}}
製造プロセス