制御文法を使う(反復)条件により処理を繰り返す(Arduino)

分岐にも書きましが、記述されたプログラムは、
何も制御しない場合は、
上から下へ左から右へと順に実行されます。

今回は、反復(繰り返し)処理です。
繰り返しといえば、
loop( )関数も繰り返し処理の関数でした。
loop( )関数{  }ブロック内に記述された内容は、
電源を切るまで、永久的に繰り返されます。

マイコンを使い、何かを制御する事を考えてみると、
void loop( ) {
 センサーからの情報取得
 この情報を使って機器を制御
}
これで、あとは、loop( )関数が勝手に繰り返し
処理を続けてくれることになります。

ここで、センサーの情報精度を上げるため、
センサーからの情報取得を5回繰り返して、
その平均で機器の制御を行うことを一組とすると、
センサーからの情報取得に必要となる
プログラム記述を5回書かなければならなりません。
しかも同じ内容を書くことになるますね。
こんな時、
このセンサーからの情報取得を5回繰り返す
などと記述できたら便利です。
これが、反復(繰り返し)文の必要な理由の一つです。

全体の大きな反復(繰り返し)処理は、loop( )関数に
任せるとして、その中の反復が必要となる処理は、
自分で書くことになります。

反復(繰り返し)処理のイメージは、

反復(繰り返し)処理のイメージ1
反復(繰り返し)処理のイメージ1

こんな、感じでしょうか。

反復(繰り返し)処理は、
while( )、for( )、do while( )文を使います。
各書式は、
 while( )文
  while( 継続条件式 ) {  }

 for( )文
  for( 初期化式; 継続条件式; 繰り返し毎の式) {  }

 do while( )文
  do {  } while( 継続条件式 )
となります。

各文の継続条件式ですが、
継続条件式は、if ( )文と同じく、比較演算子を使用して記述します。
( )内の条件式が成り立っている(真、true)間、
{ } ブロック内の処理が繰り返し行われます。
while( i < 5 ) {  }
と書けば、iが5より小さい間、繰り返しが行われます。
このiが更新されず、5以上にならなければ、
この{ }のブロックから抜け出ることが出来ず、
永久(無限)ループとなってしまいます。

for( )文の( )内の式は、3つで、各式は、セミコロン(;)で区切って
記述します。
初期化式は、この繰り返しに入る前に行いたいことを記述します。
継続条件式は、他の繰り返し文と同じく、継続条件を記述します。
繰り返し毎の式は、{ }ブロック内を1回繰り返し、戻ってきたときに
行いたい事を記述します。
int i;
for ( i = 0; i < 5; i = i + 1 ){繰り返したい処理}
のような記述の場合、
このfor( )文の繰り返しに入る前に、変数iが0で初期化されます。
続いて、1回繰り返すごとに、i = i + 1が実行され、
繰り返すごとに、変数iは1ずつ加算されます。
1回繰り返すごとに、継続条件が判定されるため、
i → 0、1、2、3、4、5
となり、継続条件が崩れ(偽、falseとなり)、繰り返しが
終了することになります。

do while( ) 文は、while( ) 文と同様ですが、
継続条件式の判定位置が違います。
そのため、
while( )文では、
  int i = 5;
  while( i < 1 ) { 繰り返したい処理 }
繰り返しより前に継続条件式の判定を行うため、
この繰り返したい処理は実行されません。
・・・前判定型繰り返しとよびます。

前判定繰り返し
前判定繰り返し


do while( )文では、
  int i = 1;
  do { 繰り返したい処理 } while( i < 1 )
判定が、繰り返し後に行われるため、
繰り返したい処理内容が、必ず一度は実行されてしまいます。
・・・後判定型繰り返しとよびます。

後判定繰り返し
後判定繰り返し

最低1度は繰り返す処理であれば、
どちらの記述を使っても同じ結果になります。
また、3文のどれを使うかも、
自分が分かりやすいものを使うべきです。
for( )文については、数をカウントしながら繰り返すような
使い方には分かりやすく向いていると思います。

さて、整数1から10までの加算結果を求めるには、
(1+2+3+4+5+6+7+8+9+10 を行うには)

1~10までの加算
1~10までの加算

for ( )文で記述してみます。

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);   // シリアルポートを初期化(9600 bpsで通信)
   // 変数宣言
   int i;
   int total = 0;
   // 1から10の加算
   for ( i = 1;  i <= 10; i++ ) {
     total += i;
   }
   Serial.println( total );
}
void loop() {
   // put your main code here, to run repeatedly:
}
for( )文の実行例
for( )文の実行例

while ( )文で記述してみます。

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);   // シリアルポートを初期化(9600 bpsで通信)
   // 変数宣言
   int i = 1;
   int total = 0;
   // 1から10の加算
   while ( i<= 10 ) {
     total = total + i;
     i = i + 1;
   }
   Serial.println( total );
}
void loop() {
   // put your main code here, to run repeatedly:
}
while( )文の実行例
while( )文の実行例

do while ( )文で記述してみます。

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);   // シリアルポートを初期化(9600 bpsで通信)
   // 変数宣言
   int i = 1;
   int total = 0;
   // 1から10の加算
   do {
     total = total + i;
     i = i + 1;
   } while ( i<= 10 );
   Serial.println( total );
}
void loop() {
   // put your main code here, to run repeatedly:
}
do while( )文の実行例
do while( )文の実行例

継続条件式とは別に、他の条件で繰り返しを中断したい
場合もあります。
この場合は、break文を使います。
このbreak文を発行すると、
その時点で、繰り返しから抜け出し、
繰り返し{  }ブロックの、次の処理へ移行します。

break文の利用
break文の利用

ここで、中断と書いていますが、
これは、継続条件式ではまだ繰り返す予定なのに、
途中で中止するという意味で中断と書いていますが、
再開するなどということは出来ません。

整数1から10までの加算結果を求めるプログラムを、
while( )文で記述し、その継続条件を、trueとして無限ループにします。
 while( true ) { }
このままでは、継続条件は崩れません(falseにならない)から、
ループが終了することはありません。
そこで、 break文を発行して、ループから抜け出す方法で、
if ( i > 10 ){
 break;
}

のような記述になりますね。
記述してみます。

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);   // シリアルポートを初期化(9600 bpsで通信)
   // 変数宣言
   int i = 1;
   int total = 0;
   // 1から10の加算
   while ( true ) {  // 繰り返しの継続条件を無限に
     total += i;
     i++;
     if( i > 10 ){
       break;      // 10まで加算したので繰り返し中断
     }
   }
   Serial.println( total );
}
void loop() {
   // put your main code here, to run repeatedly:
}
break利用の実行例
break利用の実行例

ネスト(入れ子)処理とよばれる記述もあります。
これは、文法ブロック内に同文法ブロックを記述することで、
繰り返し処理の中に繰り返し処理を書くことをいい、
二重ループ(多重ループ)などと呼ばれる処理です。
while( ){
 while( ){

  }
}
こんな記述のことになりますね。

ネスト(入れ子)処理
ネスト(入れ子)処理

のような感じでしょうか。
※ここでは、ループ記号(台形記号)を使わずに記載しています。
・・・・私はこの記述の方が分かりやすいので。

また、
loop( )関数の中に、
while( )、for( )、do while( )文を使って記述すれば、
これもある意味入れ子処理ってことになりますね?

ネスト処理を利用して、
*を数値分だけ表示するスケッチを記述してみます。

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);   // シリアルポートを初期化(9600 bpsで通信)
   // 変数宣言
   int i, j;
   int total = 0;
   // 5×5マスに*の数を変えながら表示する
   for ( i = 0;  i < 5; i++ ) {    // *を増やしながら表示(5×5)
     for ( j = 0;  j <= i; j++ ) {
       Serial.print( "*" );
     }
     Serial.println( );
   }
   for ( i = 0;  i < 5; i++ ) {  // *を減らしながら表示(5×5)
     for ( j = 0;  j < 5 - i; j++ ) {
       Serial.print( "*" );
     }
     Serial.println( );
   }
}
void loop() {
   // put your main code here, to run repeatedly:
}
ネスト処理を利用した実行例1
ネスト処理を利用した実行例1(*表示)

ネスト処理を利用して、
九九の表を表示するスケッチを記述してみます。

void setup() {
   // put your setup code here, to run once:
   Serial.begin(9600);   // シリアルポートを初期化(9600 bpsで通信)
   // 変数宣言
   int i, j;
   // 九九の表示
   for ( i = 1;  i <= 9; i++ ) {
     for ( j = 1;  j <= 9; j++ ) {
       Serial.print( j );
       Serial.print( "×" );
       Serial.print( i );
       Serial.print( "=" );
       Serial.print( i * j );
       Serial.print( "\t" );
     }
     Serial.println( );
   }
}
void loop() {
   // put your main code here, to run repeatedly:
}
ネスト処理を利用した実行例2( 九九表示)
ネスト処理を利用した実行例2( 九九表示)