第3回

関数

処理を意味のある単位に分割する。

関数の基本

int add(int a, int b) {
    return a + b;
}
戻り値
  ↓
int add(int a, int b)
     ↑       ↑
   関数名   引数

戻り値なし

void ledOn() {
    digitalWrite(LED_BUILTIN, HIGH);
}

voidは「返す値がない」ことを表す。

引数

void setBrightness(int brightness) {
}

引数を付けることで、同じ処理を違う値に対して使い回せる。

コメントの書き方

関数には、何をする関数なのかをコメントで書いておく。この講座では次の形に統一する。

/**
 * @brief 倍化関数
 * @param value 値
 * @param flag 有効化フラグ
 * @return 倍化した値(有効時)
 */
int doubleValue(int value, bool flag) {
    if (flag) {
        return value * 2;
    } else {
        return value;
    }
}
タグ書く内容
@briefその関数が何をするか。1行で書く
@detailsその関数の詳細な説明を書く。複数行にわたっても良い
@param引数ひとつにつき1行。引数名のあとに説明を続ける。[in]は入力、[out]は出力、[in,out]は入力と出力の両方
@return返す値。voidの関数には書かない
@note注意事項。関数の使用方法や注意点を記述する
@todo今後実装する予定の機能や改善点を記述する
@fileファイル名。関数が属するファイルを指定する

先頭が/**で始まるのが目印である。アスタリスクが1つの/*だとこの形式として扱われない。

処理の途中に短い説明を入れるときは//を使う。

void loop() {
    // ボタンが押されている間だけ点灯する
    if (digitalRead(BUTTON_PIN) == LOW) {
        digitalWrite(LED_BUILTIN, HIGH);
    } else {
        digitalWrite(LED_BUILTIN, LOW);
    }
}

ローカル変数

void function() {
    int value = 10;
}

valueは関数外から直接利用できない。これがスコープである。

グローバル変数

int counter = 0;

グローバル変数の便利さと問題点を説明する。

  • どこからでも変更できる
  • 意図しない変更が起こりやすい
  • 後のカプセル化につながる

動かして確かめる

演習に入る前に、まずこのサンプルを動かして結果を見る。追加の部品は要らない。光るのはボードに載っている内蔵LEDで、それ以外はシリアルモニタの出力で確かめられる。code/examples/03-functions/を開き、pio run -t uploadで書き込んでからpio device monitorで出力を見る(手順と、外付けのLEDなどをつなぐ場合は開発環境にまとめてある)。

code/examples/03-functions/src/main.cpp
// 第3回:関数に切り出す
// 同じ処理を関数にまとめ、loop() を読みやすくする。

#include <Arduino.h>

// ボード上の内蔵LED。配線なしで光る(このボードではGPIO27のRGB LED)
const int LED_PIN = LED_BUILTIN;
const int BLINK_MS = 300;

/**
 * @brief LEDを点灯する
 */
void ledOn() {
    digitalWrite(LED_PIN, HIGH);
}

/**
 * @brief LEDを消灯する
 */
void ledOff() {
    digitalWrite(LED_PIN, LOW);
}

/**
 * @brief LEDを指定回数点滅させる
 * @param times 点滅回数
 */
void blink(int times) {
    for (int i = 0; i < times; i++) {
        ledOn();
        delay(BLINK_MS);

        ledOff();
        delay(BLINK_MS);
    }
}

void setup() {
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    blink(3);
    delay(1000);
}

ボード上のRGB LEDが3回続けて白く点滅し、1秒休んでまた3回点滅する。LED_PINはLED_BUILTINにしてあるので配線は要らない。

確かめること。

  • blink(3)の1行で3回点滅する。同じdigitalWriteを書き写していない
  • blink()の中身を直せば、呼んでいるすべての場所に反映される
  • BLINK_MSを変えると点滅の速さが変わる。数値が1か所にまとまっている
  • LED_PINのように名前を付けておくと、外付けのLEDに移すときに(GPIO23)に移すときも直すのは1行だけで済む

演習:次の関数を作成する

void motorStop();
void motorSetSpeed(int speed);
bool isButtonPressed();
int readSensor();
  • それぞれ何を引数に取り、何を返すべきかを先に考える
  • この4つの関数が「どこにまとまっているべきか」は第6回のクラスにつながる