MATLAB Language
シリアルポートの使用
サーチ…
前書き
シリアルポートは、外部センサーやArduinosなどの組み込みシステムと通信するための共通のインターフェースです。最新のシリアル通信は、USBシリアルアダプタを使用したUSB接続で実装されることがよくあります。 MATLABは、RS-232およびRS-485プロトコルを含むシリアル通信用の組み込み関数を提供します。これらの機能は、ハードウェアシリアルポートまたは「仮想」USBシリアル接続に使用できます。ここの例は、MATLABでのシリアル通信を示しています。
パラメーター
シリアルポートパラメータ | それは何ですか |
---|---|
BaudRate | ボーレートを設定します。今日最も一般的なのは57600ですが、4800,9600、および115200もよく見られます |
InputBufferSize | メモリに保持されているバイト数。 MatlabにはFIFOがあります。つまり、新しいバイトは破棄されます。デフォルトは512バイトですが、問題なく20MBに簡単に設定できます。ユーザーがこれを小さくしたい場合のエッジケースはほんのわずかです |
BytesAvailable | 読み込み待ちのバイト数 |
ValuesSent | ポートが開かれてから送信されたバイト数 |
ValuesReceived | ポートが開かれてから読み込まれたバイト数 |
BytesAvailableFcn | 指定されたバイト数が入力バッファにあるか、ターミネータが読み込まれたときに実行するコールバック関数を指定する |
BytesAvailableFcnCount | bytes-available イベントを生成するために入力バッファで使用可能でなければならないバイト数を指定する |
BytesAvailableFcnMode | 指定されたバイト数が入力バッファーで使用可能になった後、またはターミネーターが読み取られた後に、 bytes-available イベントが生成されるかどうかを指定します |
Mac / Linux / Windowsでのシリアルポートの作成
% Define serial port with a baud rate of 115200
rate = 115200;
if ispc
s = serial('COM1', 'BaudRate',rate);
elseif ismac
% Note that on OSX the serial device is uniquely enumerated. You will
% have to look at /dev/tty.* to discover the exact signature of your
% serial device
s = serial('/dev/tty.usbserial-A104VFT7', 'BaudRate',rate);
elseif isunix
s = serial('/dev/ttyusb0', 'BaudRate',rate);
end
% Set the input buffer size to 1,000,000 bytes (default: 512 bytes).
s.InputBufferSize = 1000000;
% Open serial port
fopen(s);
シリアルポートからの読み取り
この例s
ようにシリアルポートオブジェクトs
を作成したとすると、
% Read one byte
data = fread(s, 1);
% Read all the bytes, version 1
data = fread(s);
% Read all the bytes, version 2
data = fread(s, s.BytesAvailable);
% Close the serial port
fclose(s);
紛失、削除、または上書きされたシリアルポートを閉じる
この例s
ようにシリアルポートオブジェクトを作成したと仮定して、それを閉じます
fclose(s)
しかし、誤ってポートを失うことがある(例えば、クリア、上書き、スコープの変更など)、 fclose(s)
が機能しなくなることがあります。ソリューションは簡単です
fclose(instrfindall)
シリアルポートへの書き込み
この例s
ようにシリアルポートオブジェクトs
を作成したとすると、
% Write one byte
fwrite(s, 255);
% Write one 16-bit signed integer
fwrite(s, 32767, 'int16');
% Write an array of unsigned 8-bit integers
fwrite(s,[48 49 50],'uchar');
% Close the serial port
fclose(s);
あなたのコミュニケーションモードを選ぶ
MATLABは、シリアルポートとの同期および非同期通信をサポートしています。適切な通信モードを選択することが重要です。選択肢は次の項目によって決まります。
- あなたが通信している機器がどのようにふるまうか。
- あなたのメインプログラム(またはGUI)がシリアルポートの管理以外に何をしなければならないのでしょうか。
最も簡単なものから最も要求の厳しいものまで、説明するために3つの異なるケースを定義します。 3つの例では、私が接続している機器は傾斜計を備えた回路基板であり、以下で説明する3つのモードで動作します。
モード1:同期(マスタ/スレーブ)
このモードは最も簡単です。これは、PCがマスターであり、機器がスレーブである場合に対応します。この機器はシリアルポートに何も送信しません。マスター(PC、あなたのプログラム)が質問/コマンドを聞いた後に答えを返すだけです。例えば:
- PCは次のコマンドを送信します。「私に測定値を与える」
- 計測器はコマンドを受信し、測定値を取得してシリアルラインに測定値を返します。「傾斜計の値はXXXです。
または
- PCは「モードXからモードYに変更する」コマンドを送信します。
- 機器はコマンドを受信して実行し、確認メッセージをシリアルラインに送り返します。「 コマンドが実行されました 」(または「 コマンドは実行されませんでした」)。これは、一般にACK / NACK応答と呼ばれます( "確認応答(d)" / "応答確認応答なし")。
要約:このモードでは、機器( スレーブ )は、PC( マスター )が尋ねた直後にシリアル回線にデータを送信するだけで、
モード2:非同期
ここで私の楽器を始めると仮定しますが、それは単なるダムセンサーではありません。それは常にそれ自身の傾向を監視し、垂直である限り(許容範囲内で+/- 15度と言う)、それは静かなままです。デバイスが15度以上傾いて水平に近づくと、アラームメッセージがシリアルラインに送信され、その直後に傾きが読み取られます。傾きが閾値を上回っている限り、5秒ごとに傾きを送り続けます。
あなたのメインプログラム(またはGUI)がシリアルラインに到着するメッセージを常に「待っている」場合、それはうまくいくかもしれませんが、その間に他のことはできません。メインプログラムがGUIの場合、GUIがユーザーからの入力を受け付けないため、GUIが「フリーズ」していると非常に不満です。基本的に、それはスレーブになり、楽器はマスターです。計測器からGUIを制御するための素晴らしい方法がない限り、これは避けるべきことです。幸いにも、 非同期通信モードでは次のことが可能になります:
- メッセージが受信されたときに何をすべきかをプログラムに知らせる別の関数を定義する
- コーナーにこの機能を残しておけば、メッセージがシリアルラインに到着したときにだけ呼び出されて実行されます 。残りの時間は、GUIが実行しなければならない他のコードを実行することができます。
概要:このモードでは、機器がいつでもシリアル回線に(必ずしも必要ではないが、すべての時間を)メッセージを送信することができます。 PCはメッセージを処理するために永久に待機しません。他のコードを実行することは許可されています。メッセージが到着したときだけ、メッセージを読み込んで処理する関数を起動します。
モード3:ストリーミング( リアルタイム )
さあ、私の楽器のフルパワーを引き出しましょう。シリアルラインに絶えず測定を送るモードにしました。私のプログラムは、これらのパケットを受信して、それをカーブまたはデジタルディスプレイに表示したいと考えています。上記のように5秒ごとに値を送信するだけで問題がない場合は、上記のモードを維持してください。しかし私の装置はフル・ホックで1000Hzでシリアル・ラインにデータ・ポイントを送ります。すなわち、1ミリ秒ごとに新しい値を送ります。上記の非同期モードに留まっていると、新しいパケットを処理するために定義した特別な関数は実行するのに1ms以上かかる(実際には保証されている)という危険性があります(値をプロットまたは表示する場合は、グラフィック関数は非常に遅く、フィルタリングや信号のFFTを考慮していません)。これは、関数が実行を開始することを意味しますが、終了する前に新しいパケットが到着し、関数を再度トリガーします。 2番目の関数は実行のためにキューに置かれ、最初の関数が終了すると開始されますが、今回はいくつかの新しいパケットが到着し、それぞれがキュー内で実行する関数を配置します。あなたはすぐに結果を予知することができます:私は5番目の点をプロットしている時点で、私はすでに何百ものプロットを待っています... GUIが減速し、最終的にフリーズし、スタックが成長し、バッファが一杯になるまで、最終的には、完全にフリーズしたプログラムまたは単にクラッシュしたプログラムが残っています。
これを克服するために、PCと計測器の同期リンクをさらに切断します。各パケット到着時にただちに機能をトリガーすることなく、機器が独自のペースでデータを送信できるようにします。シリアルポートバッファは受信したパケットを蓄積するだけです。 PCは、バッファ内のデータを一定の間隔(一定の間隔、PC側で設定)で収集し、何らかの操作を行い(バッファが装置によって補充されている間)、次に新しいバッチを収集します。バッファからのデータなど...。
要約:このモードでは、機器は連続的にデータを送信し、シリアルポートバッファによって収集されます。一定間隔で、PCはバッファからデータを収集し、それと何かを行います。 PCと計測器の間にハード同期リンクはありません。両方とも、自分のタイミングでタスクを実行します。
シリアルポートから受信したデータを自動的に処理する
シリアルポート経由で接続された一部のデバイスは、一定の速度(ストリーミングデータ)でプログラムにデータを送信したり、予測できない間隔でデータを送信したりします。データが到着すると自動的にデータを処理する機能を自動的に実行するようにシリアルポートを設定することができます。これは、シリアルポートオブジェクトの「コールバック関数」と呼ばれます。
この機能を使用するために設定する必要のあるシリアルポートには、コールバックに必要な機能の名前( BytesAvailableFcn
)と、コールバック関数を実行する条件( BytesAvailableFcnMode
)の2つがあります。
コールバック関数をトリガするには、次の2つの方法があります。
- シリアルポートで特定のバイト数(通常はバイナリデータ用)が受信されると、
- 特定の文字がシリアルポート(通常、テキストまたはASCIIデータのために使用される)で受信されると、
コールバック関数には、 obj
とevent
という2つの必須入力引数がありevent
。 obj
はシリアルポートです。たとえば、シリアルポートから受信したデータを印刷する場合は、 newdata
というデータを印刷する関数を定義します。
function newdata(obj,event)
[d,c] = fread(obj); % get the data from the serial port
% Note: for ASCII data, use fscanf(obj) to return characters instead of binary values
fprintf(1,'Received %d bytes\n',c);
disp(d)
end
たとえば、64バイトのデータを受信するたびにnewdata
関数を実行するには、次のようにシリアルポートを設定します。
s = serial(port_name);
s.BytesAvailableFcnMode = 'byte';
s.BytesAvailableFcnCount = 64;
s.BytesAvailableFcn = @newdata;
テキストまたはASCIIデータの場合、データは通常、ページ上のテキストと同様に、「ターミネータ文字」を含む行に分割されます。キャリッジリターン文字が受信されるたびにnewdata
関数を実行するには、次のようにシリアルポートを設定します。
s = serial(port_name);
s.BytesAvailableFcnMode = 'terminator';
s.Terminator = 'CR'; % the carriage return, ASCII code 13
s.BytesAvailableFcn = @newdata;