Arduino-UNO 割り込み処理のミスあれこれ:計時処理
皆さんのスケッチを見ていて、どうしても一言いたくって・・・
「割り込み禁止での排他制御」、重要です。
■誤表示の可能性
タイマー割り込みで時計処理していて、読み出し時に
割り込み禁止していないので、桁上がりタイミングと
表示処理が重なると誤表示の可能性があります。
・Arduinoでタイマー割り込み:Lightning Brains
▲スケッチ
// 経過時刻表示
void loop() {
char buf[18]; // 表示バッファ
sprintf(buf, "%02d:%02d:%02d.%03d", hh, mm, ss, ms);
setCursor(2, 1);
sendText(buf, strlen(buf));
}
※時刻データ「hh, mm, ss, ms」は1msのタイマー割り込みで
カウントアップ。
▲状況
sprintfで4つの時刻データ(int値)を文字列に変換しています。
※「hh, mm, ss, ms」の読み出しはどのタイミングで
行われるか、どの順番でされるのか分かりません。
「hh, mm, ss, ms」の順だと仮定して、
「23:59:59.999」の時に「時と分」まで読み出したとすると、
文字列bufには「23:59」が入ります。
この直後にタイマー割り込みが入って1ms桁がカウントアップ
したら時刻データは「00:00:00.000」になります。
すると、「時分」に続く時刻データ「ss,ms」の読み出しは
「00.000」となってしまい、文字列bufは
「23:59:00.000」となり、ミス表示が出現します。
しかし、loop()処理だからすぐに次の表示が行われるので、
このミスには気が付きにくいでしょう。
表示が「チラ」と変化するだけですから。
▲対策
割り込み禁止状態「cli()実行」にして「hh, mm, ss, ms」を
別の変数にコピーします。
その後、「sei()」で割り込み有効状態に戻します。
そして、sprintfにはコピーした変数を食わせます。
コピーした値は割り込みが入っても変化しません。
面倒でもこうしないと、いつミスが生じるかわかりません。
表示だと実害は無いかもしれませんが、タイマー値を何かの制御
や計算に使っていたら「たまにおかしくなる」が発生します。
見つけにくいバグになってしまいます。
▲補足
これは8bitマイコンの1バイトでしか読み書きできない問題
ではなく、16bit、32bitマイコンでも発生するミスです。
▲補足2
もう一つ気になるのが、アウトプット・コンペアレジスタの
設定値です。
OCR1A = 62500;
OCR1A = 250;
のように、分周値をそのまま入れられてます。
「分周値 - 1」つまり「TOP値」でないと、1クロック余計に
カウントしてしまい、正しい周波数(周期)が得られません。
▲参考に
・『アトミック操作』・・・8bitマイコンに限り何か別の言い方なかったか?
・割り込みで処理させるwordデータの扱い
・Arduinoのタイマー OCRレジスタは「n」じゃなく「n - 1」の値を設定せよ
・Arduinoのタイマー処理
・Arduinoから「タイマー0」を取り上げる(ユーザーが使う)
※体言止めを書き直しました。
| 固定リンク
「Arduino」カテゴリの記事
- 「UART←→IrDA」変換IC、MCP2122のクロック供給(2022.06.20)
- 秋月の赤外光送受信モジュール(AE-RPM851A)を使ってみる(IrDAを試す) #2(2022.06.18)
- 秋月の赤外光送受信モジュール(AE-RPM851A)を使ってみる(IrDAを試す)(2022.06.17)
- 4046・VCO回路の直線性改善方法その2(2022.06.13)
- 「ダイソーの観覧車」を回せ! 回路図(2022.05.08)
「重箱の隅」カテゴリの記事
- AVRマイコンのSUT、BODヒューズ(2022.06.25)
- DC-DCコンバータテスト回路の資料(2022.05.31)
- Arduino IDEでRaspberry Pi Pico:millisをwordで処理した時の異常(2022.04.19)
- Arduino IDEでRaspberry Pi Pico:32bitマイコンがバグを生む(2022.04.14)
- Arduino-UNO 割り込み処理のミスあれこれ:割り込み禁止にして書かないとダメよ (2022.03.21)
コメント