google-site-verification: google3bd66dd162ef54c7.html

Arduino, シリアル出力の完了待ちはSerial.flush()で

 Arduinoでシリアルにデーターを出力した場合、ハードウェアのバックグラウンドで処理されます。つまりデーター送った後はソフトは何もしないでいいのですが、代償としてシリアルの出力が何時終わったか判りません(ソフトウエアシリアルは別です)。そういう事情があるので、シリアルの送信が全部終わった後で次のプログラムを動かしたい場合は、delay関数を使ってタイミングを調整することが行われます。

 ところで、このdelay関数でどれくらいの時間待たせればいいかは、文字数とボーレートから計算すればいいのですが、細かく計算するのが面倒なので多めに設定することが多いと思います。(私だけか?)

 あと、シリアルがバックグラウンドで実行されることを利用して、シリアルにデーターを投げておいて、その後で別の処理を開始することがあります。こうすると処理が並列に行われるので処理効率が上がります。ただ delay でどれくらい待たせればいいかが簡単に決まらなくなるので、多めにdelayの時間を設定することになるはずです。

 他にも色々なケースが考えられるますが、シリアル出力が終わるのをdelay関数で待つのは、あまり良い方法では無い気がします。

 この問題のうまい解決方法は無いかと、リファレンスを読んでいたら、Serial.flush()という関数がありました。この関数はArduino 1.0になる以前は、「受信バッファをクリアする」という動作だったらしいのですがArduino1.0以降では、「送信の完了を待つ」という仕様に変更になったそうです。まだ古いIDEの時代に書かれたスケッチがたくさん使われているためか、このSerial.flush()関数を使ったスケッチを私は見掛けたことがありません。

 ということで、Serial.flash()の効果を確認するスケッチを書いてみました。

// Serial.flush()のテスト 
// 2016/02/15 ラジオペンチ http://radiopench.blog96.fc2.com/

#include <avr/sleep.h> // スリープライブラリ

void setup() {
Serial.begin(9600);
Serial.println("Entering power save mode"); // メッセージ出力
// delay(10); // delay関数でシリアル出力完了を待つ
Serial.flush(); // Serial.flushでシリアル出力完了を待つ
set_sleep_mode(SLEEP_MODE_PWR_SAVE); // スリープモード指定
sleep_mode(); // ここでスリープ
}

void loop() {
}
 シリアルモニタにEntering power save mode と表示して、パワーセーブモードでスリープするプログラムです。スリープから復旧するルーチンが無いので一回実行されるだけです。もう一度実行するにはリセットする必要があります。

 このプログラムはSerial.flush(); を使うようになっています。実行するとシリアルモニタに以下のよう表示します。

▼Serial.flush()での実行結果
正常表示
 ちゃんと出力されています。

 ここで9行目のコメントアウトを外してdelay(10)を使い、10行目をコメントアウト、つまりSerial.flush()を使わないようにすると、

▼delay(10)を使った実行結果
表示不良
 文字が途中で途切れています。シリアル出力が全部終わる前にパワーセーブモードが始まってしまうので、こういうことが起きてしまいます。ここで、時間を延ばして、delay(30); とかに変更すれば文字の途切れは無くなります。

 でもそんなことするより、Serial.flush(); を使った方がスマートだと思います。

◆flashとflushの違い
 ところで、ちょうどいい機会なので flash と flush の違いについて説明します。というか自分も混乱したので、頭の整理を兼ねて文章にしておきます。ちなみに日本人にはどちらもフラッシュとしか読めませんが、英語の発音では違うのだそうです。

 ストロボのフラッシュはflashでピカリと光ること、ちなみにフラッシュメモリーもflashです。一方のflushには意味がいろいろあるようですが、「流し去る」というのが一番ピッタリすると思います。ちなみに水洗トイレの水を流すのはflushです。

 元のSerial.flush()という関数は、受信バッファの中身を消去するという機能だったのでflushという単語がピッタリします。でも、現在のように送信完了まで待つという仕様なら、Serial.wait()とでもしておいてもらった方が判り易かった気がします。まあネイティブな人達が決めたのでしょうから独り言なんですが。
関連記事

コメントの投稿

管理者にだけ表示を許可する

SoftwareSerialでも使えました

SoftwareSerialで受信側でエラーが多発していたのですが、SSerial.flush();
を発信側に追加したら、計算時間内で受信できるようになりました。

re:SoftwareSerialでも使えました

たろうさん情報ありがとうございます。

ソフトウエアシリアルは呼びだした関数から戻れば送信の処理が完了していると思っていたのですが、どうもそうでは無かったんですね。勉強になります。
カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード