(1)割り込みの中でのdelay()
そもそも割り込みの中で時間待ちするという発想が
おかしいが、delay()の動きの解説を。
delay()のソースはwiring.cの中。
millis()やmicros()もこの中。
delayMicroseconds()もそばにある。
delay()内では割込許可フラグを
操作していない。
Arduino UNOのdelayはタイマー0のオーバーフロー割り
込みでカウントされる値を使って処理されている。
その周波数は16MHz÷64÷256で約976Hzで周期1.024ms。
delayの単位は1msだが、micros()でμ秒単位のスタート
時間を得て、そこからの経過ミリ秒をチェックして
時間待ちを行っている。
そのmicros()もタイマー0のオーバーフロー割り込みで
カウントされるtimer0_overflow_countの値をベースと
して、8bitのタイマー0カウンタの値(1カウント4usで
255が最大)を加算して経過時間を得ている。
割り込み禁止状態(割り込み処理の中)ではmicros()の
カウントが進まないため、delay(10)としても、実際に
遅延するのは1~2msとなる。
※delay()は割込禁止でも抜けるように
なっているのがエライ。
delay(1)だとは1msほどは待ってくれるが、時間設定を
長くしても1~2msしかならない。
割り込み内での時間待ちは、割り込みの有効・禁止に
左右されないdelayMicroseconds()が使える。
ただし設定できる時間の最大は16383μ秒まで。
65535は設定できない。
(2)割り込みの中でのSerila.print()
Arduino UNO R3でのシリアル出力は割り込みで
処理される。
送出文字列は64文字のFIFOバッファに入れられて、
送信完了割り込みで順次出力される。
割り込みの中でSerial.printを使った時、割り込みの
頻度が大きくなって(周期が短い割り込み要因が入力
されるなどして)FIFOがいっぱいになったら、送信が
終わるまで割り込みの中で待たされることになって
しまい、割り込み処理から抜けるのが遅れてしまう。
そのため、割り込みだけでなく、メイン側の流れも
滞ってしまう。
※9600BPSなら1文字の送出に約1msかかる。
FIFOに空きがあれば一瞬で抜けてくるが、
いっぱいだと空くのを待つ。
シリアル受信を処理していたら、割り込みが遅れると
受信文字を落とすかもしれない。
タイマーへも影響する。
(3)割り込みの中でのlcd.print() 液晶表示
カーソル位置を指定して文字を表示するだけですぐに
数ミリ秒かかってしまうので、Serila.print()より
たちが悪い。
※Serila.print()はFIFOに空きがあればすぐの
処理が終わる。
液晶モジュール制御のEパルスを出すだけで0.1msほど。
画面クリアで2ms待ち。
※busy読みしたら早くなるかとR/W線をつない
でも、液晶ライブラリLiquidCrystaはlR/W=L
にして無視してしまっているので、つなぐのは
無意味。
割り込みで液晶をアクセスしてしまったら、メイン側での
表示と衝突してうまく表示できなくなってしまうし。
間違っても割り込みの中で使う関数じゃない。
(4)float計算
16MHzで走っているArduinoのATmega328、floatの加減算
だとそんなに重くならない。
float(4バイト)とlong(4バイト)で実測してみると、単純な
加減算だと10倍も違わない。
乗算も思いのほか早い。(乗算命令が活躍)
しかし、整数でも除算が遅い。
割り込み内での除算はしたくない。
割り込みの中では、時間がかかる(かもしれない)処理は
避けるのが基本。
もたもたしない!
どうしてもというときは、他に影響が無いことを
確認して。
※実際に検証
2024年3月14日:割り込みの中でSerial.printを使うと・・・
最近のコメント