AsyncSerial ‐ リングバッファ付きシリアル通信

Import libraryAsyncSerial

Asynchronous (Non-blocking) Serial Communication library with variable length software ring buffer (FIFO). You can use primary method of the RawSerial Library. Operability confirmed on mbed 2.0. (Rev.146)


AsyncSerialとは?

ソフトウェアFIFO(リングバッファ、First-in, First-outの略)を用いてノンブロッキング(非同期)のシリアル(UART)通信を行うためのライブラリです。

mbed標準のSerialライブラリやRawSerialライブラリはソフトウェアバッファを備えておらず、基本的にブロッキング通信となってしまいます(ハードウェアFIFOを備えるCPUなら、限られた長さでのノンブロッキング通信は可能です)。これらのライブラリにはwriteメソッドがあり、任意の長さの配列をノンブロッキングで送信する事ができるものとなっていますが、対応ボードが限られており、まともに使える代物ではありません。

そこで標準のRawSerialライブラリを拡張して実装したものがAsyncSerialです。RawSerialライブラリを拡張したことによって、Serial / RawSerialライブラリと同じメソッド名を用いて操作をすることが可能です。加えて、ArduinoのSerialライブラリに実装されているような peekc()、 flush()、 そして wait() メソッドを実装してあります。(詳しい説明は後述)

動作環境

mbed 2.0での動作のみ確認しております。 mbed OS 5での動作確認はしておりません。

追記: 現在、mbed標準ライブラリ Revision 147以降で正しく動作しない現象が確認されております。 対策方法は以下の通りです。

  • mbed Compilerにて左側のプログラムワークスペースにある歯車マークの”mbed”を選択し、上側のツールバーにある”リビジョンを選択
  • 中央に表示されるリスト上の、"Release 146 of the mbed library."を選択
  • 中央のツールバーにある、”切り替え”をクリック
  • 上側のツールバーにある”リビジョン”を再度クリック

mbed標準ライブラリに含まれるバグの可能性が高いと思われますが、今後のアップデートで改善される可能性もあります。


使用方法

基本的にはSerial / RawSerialライブラリと全く同じ使い方ができるので、そちらも参照してください。

また、AsyncSerialのAPIについては以下のページにも記載してあります。



シリアルポートの初期化

シリアルポートの初期化は、Serial / RawSerialと同じようにAsyncSerial クラスのオブジェクトを生成することで行います。

プロトタイプ

AsyncSerial(PinName txpin, PinName rxpin, uint32_t baudrate=9600, uint32_t buffer_size=256);

引数

引数説明
PinNametxpin送信するピン(PinNames.hで定義されたもの)
PinNamerxpin受信するピン(PinNames.hで定義されたもの)
uint32_tbaudrateボーレート(デフォルト引数のため指定しない場合はデフォルト値になります。デフォルト値: 9600bps)
uint32_tbuffer_size送信・受信バッファのサイズ(デフォルト引数のため指定しない場合はデフォルト値になります。デフォルト値: 256byte)

戻り値

コンストラクタのため、戻り値はありません。

記述例

AsyncSerial hoge(USBTX, USBRX);   // 送受信をmicroUSB経由で行う

AsyncSerial hoge(USBTX, USBRX, 115200, 128);   // 送受信をmicroUSB経由で行い、ボーレートを115200bpsに、バッファサイズを128byteに設定する



baud - ボーレート設定

ボーレートの設定はシリアルポートの初期化時だけでなく、以下のように設定することが可能です。

プロトタイプ

void baud(int baudrate);

引数

引数説明
intbaudrateボーレート(bps)

戻り値

戻り値はありません。

記述例

hoge.baud(115200);   // ボーレートを115200bpsに設定



format - 通信方式設定

ビット数、パリティ、ストップビットを設定します。 このメソッドを呼び出さなかった場合、デフォルトの8N1でシリアル通信が行われます。

プロトタイプ

void format(int bits=8, Parity parity=SerialBase::None, int stop_bits=1);

引数

引数説明
intbitsビット数(5 - 8)
ParityparityAsyncSerial::Noneパリティなし
AsyncSerial::Odd奇数パリティ
AsyncSerial::Even偶数パリティ
AsyncSerial::Forced1強制的に1
AsyncSerial::Forced0強制的に0
intstop_bitsストップビット(1 - 2)

戻り値

戻り値はありません。

記述例

hoge.format(8, AsyncSerial::Even, 2);   // シリアルポートを8E2に設定



getc - 1byte受信する

受信バッファからデータを1byte取り出します。

プロトタイプ

virtual int getc(void);

引数

引数はありません。

戻り値

説明
int受信したデータ

記述例

uint8_t data;
data = (uint8_t)hoge.getc();



peekc - 1byte受信する(読み取り位置変更なし)

受信バッファからデータを1byte取り出します。

なお、getc メソッドと違いバッファの読み取り位置を変更しません。すなわち、peekc メソッドは同じデータを繰り返し読み取ります。

プロトタイプ

virtual int peekc(void);

引数

引数はありません。

戻り値

説明
int受信したデータ

記述例

if( hoge.peekc() == '@' ){
	// Code
}



readable - 受信したデータのサイズを取得する

受信バッファにデータが何byte届いているかを取得します。 ArduinoにおけるSerial.available メソッドのようなものです。

プロトタイプ

virtual int readable(void);

引数

引数はありません。

戻り値

説明
int受信バッファに届いているデータのサイズ(byte)

記述例

if( hoge.readable() > 0 ){
	hoge.putc( 0x0A );
}



flush - 受信バッファをクリア

受信バッファのデータを強制的にクリアします。

プロトタイプ

virtual void flush(void);

引数

引数はありません。

戻り値

戻り値はありません。

記述例

hoge.flush();



putc - 1byte送信する

送信バッファに1byteのデータを追加することによって、データを1byte送信します。

プロトタイプ

virtual void putc(int c);

引数

引数説明
intc送信するデータ

戻り値

戻り値はありません。

記述例

hoge.putc( 0x0A );



puts - 1行の文字列を送信する

文字列に改行文字(CR+LF)を付けて送信します。

プロトタイプ

virtual void puts(const char *str);

引数

引数説明
const char*str送信する文字列

戻り値

戻り値はありません。

記述例

hoge.puts("Hello, World!");



printf - 書式付き文字列を送信する

書式付きの文字列を送信します。おなじみのprintfと同じような動作をします。

プロトタイプ

virtual int printf(const char *format, ...);

引数

引数説明
const char*format送信する書式付き文字列
可変個引数

戻り値

説明
int0エラー
1以上送信した文字列の長さ(byte)

記述例

int num = 4;
hoge.printf("Hi, I'm Cortex-M%d.\n", num);



write - バイト列を送信する

1byteの配列をまるごと送信します。

プロトタイプ

virtual int write(const uint8_t *buffer, int length);

引数

引数説明
const uint8_t*buffer送信するバイト列
intlength送信するバイト数(byte)

戻り値

説明
int0エラー
1以上正常終了

記述例

uint8_t array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
hoge.write(array, 11);



wait - すべての送信が完了するまで待機する

すべての送信が完了するまで、すなわち送信バッファが空になるまで待機します。

プロトタイプ

virtual void wait(void);

引数

引数はありません。

戻り値

戻り値はありません。

記述例

hoge.wait();



サンプルコード

  • シリアルポートを2ポート用意し、片方に届いたデータをもう片方のポートから送信するプログラム

// -*- coding: utf-8 -*-
// Board: NUCLEO_F303_K8

#include "mbed.h"
#include "AsyncSerial.hpp"

AsyncSerial ser(D5, D4);
AsyncSerial pc(USBTX, USBRX);

int main(){
	while(1){
		while( pc.readable() > 0 ){
			ser.putc( pc.getc() );
		}
	}
}


6 comments on AsyncSerial ‐ リングバッファ付きシリアル通信:

23 Jun 2017

wait出来ていませんでした。

void AsyncSerial::wait(void){ while( fifo_rx.available() > 0 ){} return; }

void AsyncSerial::wait(void){ while( fifo_tx.available() > 0 ){} return; } に変更したら出来ました。

23 Jun 2017

hasegawa men wrote:

wait出来ていませんでした。

void AsyncSerial::wait(void){ while( fifo_rx.available() > 0 ){} return; }

void AsyncSerial::wait(void){ while( fifo_tx.available() > 0 ){} return; } に変更したら出来ました。

ご指摘ありがとうございます。

AVRから移植した際のミスだと思われます。 ライブラリをアップデートしておきました。

18 Jan 2019

バイト列の受信を行う場合どのようにしたらよいでしょうか

08 Jul 2019

koki ito wrote:

バイト列の受信を行う場合どのようにしたらよいでしょうか

簡単に行うのなら,readable()で確認した分だけをgetc()で読み込むことになります.(Arduinoでも同様)

しかし,その場合には1回の通信データがどこまでなのかがわからない上に,正しくデータが届いているかは保証できません.ですから,送信したいバイト列(ペイロードと呼びます)をSTX/ETXの役割をする文字で包み,さらにペイロード長やチェックサムなどを付加したパケットを作る必要があります.AsyncSerialを使った例は以下にあります.

/users/babylonica/code/SerialConnect/

パケット受信側の状態遷移図 /media/uploads/babylonica/screenshot_2019-07-08_at_22.27.08.png

27 Sep 2019

I am using the same board is the example: Board: NUCLEO_F303_K8. can confirm (update as of 9/2019) the library is not updated. You must roll back Mbed to rev 146. It will work on 147, but stops with rev 148.

05 May 2020

flush関数の実装は今後あるのでしょうか?

Please log in to post comments.