Arduinoのシリアル通信でループ処理時間の高速化を行ってみました。
現在、全体のループ処理を250Hz(4ms)で行いたいプログラムがあるのですがシリアル通信で処理する情報が64byte程あり、通信速度は115200bpsで行ってます。
単純計算で考えるとシリアル通信処理のみで5.5ms程必要となってしまい、制御ループの4msを超えてしまいます。
今回、データ通信のやり取りは4msループで行う必要がないため、そこらへんを使ってループ処理の高速化を行ってみたいと思います。
シリアル通信の処理速度とその内容を確認しながら進めたいと思います。まずは単純なシリアル通信の処理速度を測定してみました。
▼ソース▼
uint32_t serialTime; void setup() { Serial.begin(115200); } void loop() { serialTime = micros(); for (int i = 0 ; i < 64 ; i++)Serial.print('A'); Serial.println(micros() - serialTime); }
ループでひたすらシリアル送信してます。その中で64byte分のシリアル送信処理時間を測ってます。伝送速度は115200bpsです。
▼結果▼
ちょっとわかり難いですが、最後の4桁がμ秒です。ざっくり計算すると115200bpsで64byte分の伝送時間はおよそ5.5ms(5500μs)ですのでだいたいあってる感じでしょうか。
▼次にこのソースで測定してみます▼
uint32_t serialTime; void setup() { Serial.begin(115200); } void loop() { serialTime = micros(); for (int i = 0 ; i < 64 ; i++)Serial.print('A'); Serial.println(micros() - serialTime); delay(10); }
先ほどのソースの最後にdelay(10);を追加しているだけです。
▼結果▼
64byte分のシリアル送信処理がおよそ424μs(≒0.4ms)となってます。先ほどと比べて10分の1以下の処理速度です。
Arduinoではデフォルトで送信バッファを64byte分準備しています。最初のソースではプログラム始動直後に送信バッファがいっぱいになってしまっています。ですのでSerial.printで送信要求をかけてもバッファに空きがでるまで待つことになります。単純に115200bpsの速度分の待ち時間が発生していることになります。
delay(10);を入れたソースでは、十分な送信時間を確保しているため、送信要求をかけるときにはバッファは常に空の状態です。ですのでSerial.printにかかる時間は純粋にCPUの処理時間のみということで瞬時に送信要求から戻ってくるため0.4msと高速になります。
今回、通信そのものはそれほど高速で行う必要がないため(50Hz程度で良い)、少しソースをいじって制御ループ250Hz(4ms)の中に、およそ50Hzのシリアル通信64byte分を組み込んでみました。
▼ソース▼
uint32_t loopTime; uint32_t serialTime; uint32_t dt; void setup() { Serial.begin(115200); } void loop() { Serial.print("LoopTime: "); Serial.print(dt); Serial.println(" us"); if (micros() - serialTime > 20000) { serialTime = micros(); for (int i = 0 ; i < 64 ; i++)Serial.print('A'); Serial.println(); } while (micros() - loopTime < 4000); //4000us(250Hz) dt = micros() - loopTime; //us loopTime = micros(); }
ループ処理を250Hzで行って、およそ50Hz周期(20ms毎)で64byte分のシリアル送信してます。上のソースだとデバッグ目的の送信要求があるため、バッファが空になりきる前にまた送信要求してしまってますが・・・。
▼結果▼
250Hz制御ループの間で64byte分の送信処理を行えてます。
記事タイトルではシリアル通信そのものの高速化みたいになってましたが・・・すみません。短い制御ループ時間の中でゆっくりシリアル通信しましょうというだけの内容です。
コメント