« 温湿度センサーDHT11、ライブラリを使うと氷点下の温度がおかしくなるぞ! | トップページ | Arduino-UNO 割り込み処理のミスあれこれ:ロータリーエンコーダー »

2022年3月10日 (木)

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」を取り上げる(ユーザーが使う)



※体言止めを書き直しました。

|

« 温湿度センサーDHT11、ライブラリを使うと氷点下の温度がおかしくなるぞ! | トップページ | Arduino-UNO 割り込み処理のミスあれこれ:ロータリーエンコーダー »

Arduino」カテゴリの記事

重箱の隅」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« 温湿度センサーDHT11、ライブラリを使うと氷点下の温度がおかしくなるぞ! | トップページ | Arduino-UNO 割り込み処理のミスあれこれ:ロータリーエンコーダー »