TOPPERS/EV3RTでEV3のタッチセンサーを使ってみる

TOPPERS/EV3RT環境でC言語を使って、タッチセンサーを使ってみます。
[環境開発の記事はこちら](http://qiita.com/tkzw102/items/93dd959cccf2efc8d4a6)
#タッチセンサーを本体につなぐ

![touch_sensor.png](https://qiita-image-store.s3.amazonaws.com/0/152243/a09a5774-9bd8-861e-2a74-29578404e8fe.png)


上の画像のように接続しました。ポート1にタッチセンサーを、ポートAにLモーターを接続しました。

#アプリケーションを作成する

タッチセンサーの動きが確認できればいいので、押している間モーターが回転するものを作ります。名前はtouch-testにするとして、[前回](http://qiita.com/tkzw102/private/e05ef4266fbddbc4b56d)のプログラムから、本体のエンターボタンの代わりにタッチセンサーを用いるだけで出来上がってしまうので、`cp -r motor-test touch-test`で、motor-testの中身を丸ごとコピーします。

<img width="237" alt="cpapp.png" src="https://qiita-image-store.s3.amazonaws.com/0/152243/d5e16012-54e7-0c33-9713-38d9cd32e0e1.png">

さて、今度は中身の編集です。main.cの中身を、以下のように書き換えます。

```C:main.c

/**
 ******************************************************************************
 ** ファイル名   : app.c
 ** 説明       : タッチセンサーを押してる間モーターが回る 
 ******************************************************************************
 **/

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

#if defined(BUILD_MODULE)
#include "module_cfg.h"
#else
#include "kernel_cfg.h"
#endif

#define DEBUG

#ifdef DEBUG
#define _debug(x) (x)
#else
#define _debug(x)
#endif

/* モーターポートの設定 */
static const motor_port_t
    L_motor      = EV3_PORT_A;

/* センサーの設定 */
static const sensor_port_t
    touch_sensor = EV3_PORT_1;

/* メインタスク */
void main_task(intptr_t unused)
{
	/* ループに入ってしまう前にモーターとモーターポートを接続する */
	ev3_motor_config (L_motor, LARGE_MOTOR);
    /* 同じくセンサーとセンサーポートを接続する */
    ev3_sensor_config (touch_sensor, TOUCH_SENSOR);
    ev3_led_set_color(LED_ORANGE); 
    /* ループの中に入る */
    while(1)
    {   /* タッチセンサーが押されている間とそうでないときで処理を分ける */
    	if(ev3_touch_sensor_is_pressed(touch_sensor) == true){
    		/* Lモーターを最大パワーで回す */
			ev3_motor_set_power(L_motor,100);
		}else{
            /* Lモーターを止める */
			ev3_motor_stop(L_motor, false);
		}
    }
    ev3_motor_stop(L_motor, false);
    ext_tsk();
}

```
タッチセンサーが押されている間モーターが回転し、離すと止まるという内容です。

この他にも、書き方次第でトグル操作に切り替えたりすることも可能です。

#タッチセンサーを使ったトグル操作

トグル操作とは:
家電製品の電源ボタンをイメージしてください。
ボタンを押すと起動し、次に押すと動作が終了します。
このように、**同一の操作により内部の状態を切り替える操作**をトグル操作といいます。
On/Offの切り替えが最も多いですね。先ほどのプログラムを改良し、トグル操作を実装します。

```C:main.c

/**
 ******************************************************************************
 ** ファイル名   : app.c
 ** 説明       : タッチセンサーを使いトグル操作でモーターが回る 
 ******************************************************************************
 **/

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

#if defined(BUILD_MODULE)
#include "module_cfg.h"
#else
#include "kernel_cfg.h"
#endif

#define DEBUG

#ifdef DEBUG
#define _debug(x) (x)
#else
#define _debug(x)
#endif
/* フラグONとOFFのマクロ定義 */
#define ON 1
#define OFF 0
/* モーターポートの設定 */
static const motor_port_t
    L_motor      = EV3_PORT_A;

/* センサーの設定 */
static const sensor_port_t
    touch_sensor = EV3_PORT_1;

/* 関数のプロトタイプ宣言 */
void toggle_control(void);

/* 大域変数でフラグを定義 */
static int flag = 0;
/* メインタスク */
void main_task(intptr_t unused)
{
	/* ループに入ってしまう前にモーターとモーターポートを接続する */
	ev3_motor_config (L_motor, LARGE_MOTOR);
    /* 同じくセンサーとセンサーポートを接続する */
    ev3_sensor_config (touch_sensor, TOUCH_SENSOR);
    ev3_led_set_color(LED_ORANGE); 
    /* ループの中に入る */
    while(1)
    {   /* トグル関数を呼び出す */
    	toggle_control();
        /* タッチセンサーが押されている間とそうでないときで処理を分ける */
        /* フラグONでモーター駆動、OFFで動作停止 */
        if(flag == OFF){
            ev3_motor_set_power(L_motor, 0);
        }else{
            ev3_motor_set_power(L_motor, 100);
        }
    }
    ev3_motor_stop(L_motor, false);
    ext_tsk();
}

/* トグル操作の関数 */
void toggle_control()
{
    /* ボタンの現在と直前の状態を保持する変数 */
    static int now = 0;
    static int before = 0;

    /* ボタンの現在値を記録する */
    now = ev3_touch_sensor_is_pressed(touch_sensor);
    /* 直前のボタンの状態と現在のボタンの状態を比較し、ボタンが押された瞬間に条件のなかに入る */
    if(now == 1 && before == 0){ /*前回のタスク周期でボタンが押されておらず、今回のタスク周期でボタンが押されたとき(立ち上がり判定) */
        /* フラグ変数の状態に応じてフラグ変数のONとOFFを切り替える */
        if(flag == OFF){
            flag = ON;
        }else{
            flag = OFF;
        }
    }
    /* 関数の終わりに現在値を過去値変数に代入する */
    before = now;
}

```
これでトグル操作が実装されました。タッチセンサーを押すと動作と停止の切り替えができます。

toggle_control()のif文のあたりがミソです。EV3は、定められたタスク周期に従って繰り返し処理をしています。1周期あたりは人間にとっては一瞬ですが、EV3の中ではしっかりとその時間の中で処理を行えます。(LCD表示などの重い処理を繰り返させる場合は例外ですが)その超高速な周期で動いている間で、人間にとっての感覚で一瞬だけ、タッチボタンを押したとしましょう。周期回数を横軸、タッチセンサの返り値を縦軸とすると、以下のグラフのようになります。

<img width="490" alt="toggle-graph.png" src="https://qiita-image-store.s3.amazonaws.com/0/152243/3ee355ee-0612-dbbb-8fc2-8703ecb02a02.png">


タッチセンサーが押されてから離されるまでの間にも周期は何周かするため、グラフは0が続く区間、0から1になる瞬間、1が続く区間、1から0になる瞬間に分けられます。if文の条件では、赤い丸で囲った、"0から1に変わる瞬間"をとらえて、モーターのON/OFFを切り替えています。この0から1になった瞬間を判定することを**立ち上がり判定**といい、逆に1から0になった瞬間を判定することは**立下り判定**といいます。if文の条件を、`now == 0 && before == 1`にするだけで立下り判定にもできるので、試してみてください。