割り込みの注意点(変数の操作)
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つ複製して生成して問題を解決するようですが、
潜在的にバグを抱える可能性のあるコードは、できるだけ避けたほうが賢明です。