リングバッファ

  c328(scam)からのデータ取得には、受信割込みを利用します。

  ホストからのコマンド受取りも、受信割込みを利用しているので
  データを取りこぼさない工夫が必要になります。リングバッファ
  を用意して取りこぼしを防ぎます。

  教科書や参考文献にあるリングバッファは、リードポインタと
  ライトポインタの絶対値差分が1になるように制御します。

  今回のようなケースでは、絶対値差分が1となっていることを
  やっていては、2つの受信割込みが重なったときに、データを
  ロストする場合もあります。タイマー割込みも使っているため
  最大3つの割込みが一度に発生することも考えられます。

  リングバッファを、次の4パラメータで構成します。



リングバッファ用構造体

C言語では、リングバッファを構造体で定義できます。 リングバッファの4パラメータがあれば、次のように定義します。 typedef unsigned char UBYTE ; typedef unsigned short UWORD ; typedef struct { UWORD cap ; /* 格納データ数カウンタ */ UWORD wp ; /* ライトポインタ */ UWORD rp ; /* リードポインタ */ UBYTE dat[256] ; /* データ用配列 */ } RINGP ; 構造体を定義したので、リングバッファを変数で宣言できます。 RINGP sring ;

アクセス関数

構造体でリングバッファを定義したので、リングバッファに 関連する情報を取得する関数、データを出し入れする関数を 定義します。 格納データ数取得 格納しているデータ数は、変数capの値を返すだけです。 UWORD get_capacity(void) { return sring.cap; } 1バイトデータ取得 リードポインタが指しているデータを返します。 内部配列からデータを取り出すので、リードポインタ の操作とデータ数のデクリメントが必要です。 UBYTE get_ring(void) { UBYTE result ; /* load data */ result = sring.dat[sring.rp] ; /* update pointer */ sring.rp += 1 ; if ( sring.rp == 256 ) { sring.rp = 0 ; } /* capacity decrement */ sring.cap -= 1 ; return result ; } 1バイトデータ格納 ライトポインタが指している領域にデータを格納します。 内部配列にデータを保存するので、ライトポインタ操作 とデータ数のインクリメントが必要です。 void put_ring(UBYTE x) { /* store data */ sring.dat[sring.wp] = x ; /* update pointer */ sring.wp += 1 ; if ( sring.wp == 256 ) { sring.wp = 0 ; } /* capacity increment */ sring.cap += 1 ; } 初期化 格納データ数カウンタ、リードポインタ、ライトポインタ を0にします。 void init_ring(void) { sring.cap = 0 ; sring.wp = 0 ; sring.rp = 0 ; }

コーリングシーケンス

リングバッファとアクセス関数を定義したので、実際に 利用する場合のシーケンスを決めておきます。 c328(scam)から、データを受信するのはSCI0モジュールとします。 SCI0モジュールが利用する受信割込みで、リングバッファへデータ を格納する関数put_ringを使います。 SCI0モジュールの受信割込み処理は、以下とします。 void int_rxi0(void) { UBYTE ch0,dummy ; /* clear flag */ dummy = SCI0.SSR.BYTE ; SCI0.SSR.BIT.RDRF = OFF ; /* get a character */ ch0 = SCI0.RDR ; /* store */ put_ring( ch0 ) ; } リングバッファからデータを取出すときは、次の手順とします。
  1. 関数get_capacityで格納しているデータ数確認
  2. 関数get_ringで、必要数分データを取得

目次

inserted by FC2 system