EV3RTを使ってみる(6)

Toppers/EV3RTを使ってプログラムを作成したときの記事です。
この記事を書いた時のEV3RTのバージョンはβ3です。
目次はこちら

2015年度の新学期がはじまり、ETロボコンに向けて本格的に活動を開始している人達もいるかと思います。そのような人にとって少しでも役に立てばと思ってこの記事を書いていますが、記事を書くのが遅いので役に立っているか分かりません。さて、今回はイベント機能について書いていきます。あと、近日中に周期処理とBluetooth通信についても書いていく予定です。

イベント機能といっても、「ボタンを押したら○○する」といった処理を行うものではなく、イベントフラグを設定したり、イベントフラグが設定されるのを待機したりというような同期機能のことです。この機能を使うことで「他のタスクの処理が終了するまで待機する」といった同期処理を実装することができます。

では、今回のプログラムですが、下図に描いた流れで動作するプログラムを作成していきます。まず、高優先度タスクtask1と低優先度タスクtask2を作成し、これらを並列で実行します。そして、task2の実行中はtask1は待機し、task2の処理終了後にtask1の処理を実行するようにします。このように動作するプログラムをイベント機能を使って実装していきます。

2015-04-07-1

まずは、イベントフラグを作成するようapp.cfgに記述します。CRE_FLGの部分がイベントフラグを作成している部分で、ここではFLG1というIDのイベントフラグを作成しています。また、TA_TPRIで優先度を考慮したキューイングをするように設定しており、最後の引数0x00でイベントフラグの初期値を設定しています。これで、0x00に設定されたイベントフラグFLG1が作成されます。それ以外の部分(タスク生成など)は今までと同じですね。

INCLUDE("app_common.cfg");

#include "app.h"

DOMAIN(TDOM_APP) {
  CRE_TSK(TASK1, { TA_ACT, 0, task1, TMIN_APP_TPRI + 1, STACK_SIZE, NULL });
  CRE_TSK(TASK2, { TA_ACT, 0, task2, TMIN_APP_TPRI + 2, STACK_SIZE, NULL });
  CRE_FLG(FLG1, { TA_TPRI, 0x00 });
}

ATT_MOD("app.o");

ヘッダファイルapp.hは今までと同じです。

void task1(intptr_t exinf);
void task2(intptr_t exinf);
void display();
ulong_t getTime();

ソースファイルapp.cにtask1とtask2の内容を書いていきます。task2はcount2の値を増やしながら表示処理を時間制限まで行い、制限時間を過ぎるとイベントフラグFLG1の値を0x01に変更して終了します。関数task2の中のset_flgの部分がイベントフラグFLG1の値を0x01に変更している部分です。一方、task1はイベントフラグFLG1の値が0x01に変化するまで待機し、イベントフラグFLG1の値が0x01になるとcount1の値を増加させて表示処理を行います。関数task1の中のwai_flgの部分がイベントフラグFLG1の値が0x01になるまで待機している部分です。また、clr_flgの部分でイベントフラグの値を0x00に戻しています 1

#include "ev3api.h"
#include "app.h"
#include "kernel_cfg.h"

int count1 = 0;
int count2 = 0;

/* 高優先度タスク */
void task1(intptr_t exinf)
{
  FLGPTN flag;

  wai_flg(FLG1, 0x01, TWF_ANDW, &flag);
  clr_flg(FLG1, 0x00);

  count1 += 1;
  display();
}

/* 低優先度タスク */
void task2(intptr_t exinf)
{
  while(getTime() < 10000){
    count2 += 1;
    display();
    tslp_tsk(100);
  }

  set_flg(FLG1, 0x01);
}

/* 状態を表示する。 */
void display()
{
  char message1[32];
  char message2[32];
  char message3[32];
  int time = (int) getTime();

  sprintf(message1, "time = %d", time);
  sprintf(message2, "count1 = %d", count1);
  sprintf(message3, "count2 = %d", count2);
  
  ev3_led_set_color(LED_GREEN);
  ev3_lcd_set_font(EV3_FONT_MEDIUM);
  ev3_lcd_draw_string(message1, 20, 30);
  ev3_lcd_draw_string(message2, 20, 50);
  ev3_lcd_draw_string(message3, 20, 70);
}

/* 経過時間を返す。 */
ulong_t getTime()
{
  static ulong_t start = -1;
  ulong_t time;

  get_tim(&time);

  if(start < 0){
    start = time;
  }

  return time - start;
}

kernelと一緒にコンパイルして実行してみると、task2の処理が行われてからtask1の処理が行われているのを確認できます。

2015-04-07-2

イベント機能は単純な機能ですが、初期化処理が終了するのを待機したり、通信データが到着するのを待機したりと使い勝手のよい機能だと思います。詳しい使い方はToppersのマニュアルに書かれていますので、イベント機能を使い倒したい方はマニュアルを参考にしてください 2

Notes:

  1. このプログラムでは何の意味もありません。
  2. 本気で開発するのであれば、一次資料を参考にするのは当たり前ですけど。