割り込みの注意点(変数の操作)



1.割り込みが起こるとどうなる?

ループ変数を使いまわすとどうなるでしょう。
今、グローバルな変数iを使って変数にアクセスしています。


char a[16];
char i;

void interrupt intr(){

 //割り込みクリア

 for(i = 0; i < 16; i++){
  a[i] = 1;
 }

}

void main(){

 // 割り込み許可

 while(1){
  for(i = 0; i < 16; i++){
   a[i] = 0;
  }
 }
}

さて、どうなるか。
結果ですが、メイン関数中でa[16](範囲外)にデータを書き込み、正常に動作しません。
要するに、メイン関数のfor文の先頭で割り込みが発生し、割り込みルーチンに入ります。
割り込みルーチンのほうでは、iが16になるまでインクリメントが行われ、
メイン関数に戻ってきてa[16]にアクセスする。ということです。
注意しましょう。



2.割り込みが起こるとどうなる?2

int a;

void interrupt intr(){

 //割り込みクリア

 if((a == 0x100)||(a == 0x1)){
  printf("エラーです");
 }

}

void main(){

 // 割り込み許可

 while(1){
  a = 0;
  a = 0x101;
 }
}

これはどうでしょう。
一見エラーは起こらないように見えますが、実行すると"エラーです"が実行されます。
XC8を使っているということはPICは8bitです。
すべての処理は8bit単位でしか実行できないことになります。
ということで、2バイト以上の処理は2命令に分かれて実行されます。
その命令の間に割り込みが入ると…、エラーになりますよね。

そこで本来は

void main(){

 // 割り込み許可

 while(1){
  GIE = 0;
  a = 0;
  a = 0x101;
  GIE = 1;
 }
}

と、割り込みから保護してやらなければなりません。

3.ローカル変数も、固定アドレス

XC8では、ローカル変数も、固定のアドレスに割り当てられます。
理由は、8ビットのPICには、リソースがとても少なく、
そんな機能を入れると動作に支障をきたすからだと思うのですが、
まあともかく固定です。

ということは、同じ関数を通常ルーチンでも割り込みでも使ったら・・・

メモリの内容は全部上書きされてしまいますね。

最近のXC8では非リエントラントな関数がどうのこうのと出て、
1つの関数を2つ複製して生成して問題を解決するようですが、
潜在的にバグを抱える可能性のあるコードは、できるだけ避けたほうが賢明です。