質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.32%

割り込みとvolatile修飾子について

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 913

Alyn

score 43

質問内容

割り込みを使う際には変数に"volatile"を付けるとネットに記載されていましたが、どこまでが"volatile"を付けるべきかわかりません。
下記ソースコードには6種類の変数が使われて、そのどれに"volatile"を付ければよいのでしょうか?
serialEvent()はシリアル受信があった際に割り込まれる関数で、printFx()は割り込みピン(3)にLOW信号を受信した際に割り込まれる関数です。

①int recv
②static uint32_t before
③uint32_t current
④uint32_t a
⑤uint32_t b
⑥uint32_t gettime

ソースコード

#define INT_PIN     3

void setup()
{
    Serial.begin(9600);
    pinMode(INT_PIN, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(INT_PIN), printFx, FALLING);
}

void loop()
{
    //何もしない
}

void serialEvent()
{
    int recv = 0;

    //シリアル受信判定
    if(Serial.available() > 0)
    {
        while(1)
        {
            recv = Serial.read();   //1byteずつ吐き出し
            if(recv != -1)
            {
                if(recv == '1')
                {
                    printFx();
                }
            }
            else
            {
                //シリアルデータなし
                break;
            }
        }
    }
}

void printFx()
{
    static uint32_t before = 0;
    uint32_t current = millis();    //ミリ秒時間取得

    //2000ミリ秒経過判定
    if(getTime(current, before) >= 2000)
    {
        Serial.println("Print!");
        before = current;
    }
}

uint32_t getTime(uint32_t a, uint32_t b)
{
    uint32_t gettime = 0;

    if(a >= b)
    {
        gettime = a - b;
    }
    else
    {
        //オーバーフロー時
        gettime = a + (0xFFFFFFFF - b);
    }

    return gettime;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • ozwk

    2020/06/24 13:46

    > 割り込みを使う際には変数に"volatile"を付けるとネットに記載されていましたが

    引用元のURLください

    キャンセル

  • YufanLou

    2020/06/24 14:08

    変数に`volatile`をつけるのは変数を複数の関数で使う場合、変数の数値を共有するためです。このコードに変数を共有してる関数がないと見れますが、したいことをもっと詳しく説明してください。ちなみに、Arduinoのメモリーが8-bitのため、`byte`より大きい変数(例えば`int`)に`volatile`をつけたら、乱数を読んでしまう可能性があります。

    キャンセル

  • Alyn

    2020/06/24 14:09

    http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=3069
    ・割り当てた関数のなかで値が変化する変数にはvolatileをつけて宣言すべきです

    キャンセル

  • Alyn

    2020/06/24 14:15

    したいとはこのソースコードに問題があるかないかを知りたいことです。volatileを付けなくても動いていたので、volatileは必要なのか必要でないのか、volatileを付けないとどうなるのか、そもそもvolatileがわかりません。volatileが必要なソースコードはどういうソースコードか、このソースコードになぜvolatileが必要か、もしくは必要ないのかです。

    キャンセル

回答 3

checkベストアンサー

+3

変数にvolatileをつけるのは変数を複数の関数で使う場合、変数の数値を共有するためです。このコードに変数を共有してる関数がないため、volatileの必要がありません。

Arduino公式サイトよりvolatileの例:

// toggles LED when interrupt pin changes state

int pin = 13;
volatile byte state = LOW;

void setup() {
  pinMode(pin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(2), blink, CHANGE);
}

void loop() {
  digitalWrite(pin, state);
}

void blink() {
  state = !state;
}

ご覧の通り、loop()blink()stateを共有しています。volatileをつけないと、blink()stateを反転しても、loop()が見えません。なぜなら、byteは小さい型であり、速さのため、Arduinoのメモリーから読むことがなく、一度レジスタにコピーして、後でずっとそこから読むことです。volatileの意味は「変わりやすい」です。変わりやすいから、必ず毎回メモリーから新しい数値を読んでくださいと、コンパイラに伝えるのです。そうしたら、stateの変化がどこでも反映されます。

こういった依存関係がなければ、volatileの必要がありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/24 16:17

    ありがとうございます。仮にloop関数でgetTime関数を使うことになった場合でも共通として使ってる変数(引数)ではないため、何も問題はないという認識で合っていますでしょうか?

    キャンセル

  • 2020/06/24 16:24

    はい、その通りです。

    キャンセル

  • 2020/06/24 17:19

    ありがとうございます!

    キャンセル

+3

volatileはプログラムコードの管理外で値が変わってしまうことを明記するキーワードです。

このキーワードがない変数はメモリアクセスをせずにレジスタキャッシュアクセスや文脈等で最適化をする場合があります。

volatileをつけるべき変数は、
1.ハードウェア的に値が変わってしまうもの(タイマーやIOポート等のレジスタ)
2.メイン処理と割り込み処理で共用している変数

が主なものだと思います。

Arduinoの場合は、割り込み関数かそうでないかで判断すると良いと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/24 17:19

    ありがとうございます。割り込み関数内で使用されてる関数は当てはまるのでしょうか?引数のようなコピーは問題ないでしょうか?

    キャンセル

  • 2020/06/25 09:12

    変数のスコープ(直訳:見える範囲、意訳:生存期間、有効期限)について考えてみましょう。
    関数の入り口から出口までより、変数の有効期限が長いものに対してvolatileをつける。

    割り込み関数内で使用される関数は
    その関数内でstatic変数を利用している場合その変数にはvolatileをつけるべきです。
    引数のようなコピーは一時変数です。関数の寿命と同じか短いはずです。
    問題ありません。

    C++だと色んな所にvolatileをつけることができますが、基本的に
    volatileをつけるべき変数は、
    1.ハードウェアレジスタを指したポインタ変数
    2.グローバル変数(割り込み関数とメイン関数で共用する)
    です。

    キャンセル

0

volatile ってのは最適化をしないように指定するキーワードです
結論から言うと、提示の変数はどれもVolatileを付ける必要はありません

「組み込み」ならではの基礎知識 ――スタートアップ・ルーチンからハードウェアまで|Tech Village (テックビレッジ) / CQ出版株式会社

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る