リングバッファ
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 ) ;
}
リングバッファからデータを取出すときは、次の手順とします。
- 関数get_capacityで格納しているデータ数確認
- 関数get_ringで、必要数分データを取得
目次
前
次