« 割り込み処理の中でのdelayやSerila.print,lcd.print | トップページ | 「充電しない!」K水道店君の現場用LEDランプ »

2024年3月14日 (木)

割り込みの中でSerial.printを使うと・・・

割り込み処理の中でのdelayやSerila.print,lcd.print
  ↑この続き

割り込み処理の中でSerial.printを使ったら
どうなるのか、
具体的に見てもらいましょう。

こんなスケッチで確認

//   割り込みの中でSerial.printを使うと・・・
//  割込元はINT1 (D3)の↓エッジ
// テストパルス
#define D12_H (PORTB |= (1 << PB4)) // PB4 D12 H/L
#define D12_L (PORTB &= ~(1 << PB4)) // テストパルス
#define D13_X (PINB |= (1 << PB5)) // PB5(LED)トグル出力

/***** INT1↓エッジ *****/
void ISRint1(void)
{
char s[80]; // sprintf用文字バッファ
static uint32_t t, t0, t1, cnt;
D12_H;
t1 = micros(); // us時間
t = t1 - t0; // 経過時間
t0 = t1;
cnt++; // 割り込み回数
if(cnt > 99999999) cnt = 0L; // 8桁max
sprintf(s, "%08ld %8ldus", // 20文字
cnt, t);
Serial.println(s); // CR,LF付加で22文字(約23ms)
D12_L;
}

/***** SETUP *****/
void setup()
{
pinMode(3, INPUT_PULLUP); // INT1
pinMode(12, OUTPUT); // テストパルス
pinMode(13, OUTPUT); // LED
Serial.begin(9600); // シリアル
delay(100);
Serial.println("Test Serial Print");
attachInterrupt(1, ISRint1, FALLING); // INT1 ↓エッジ
}

/***** LOOP *****/
void loop()
{
while(1){
delay(5); // 5msでH/L
D13_X; // LEDをトグル
}
}

・INT1入力の↓エッジで割り込み。
・割り込み内では、
  割り込み回数をカウント。
  micros()を使って、パルス間隔を取得。
  回数と間隔をシリアル出力。
  CRとLFを入れて22文字。 22.92ms
  D12ポートをH/L。 割り込み処理時間が分かる。
・loopでは
  delayで5ms待ち。
  LEDポート(D13)をトグル出力。
  割り込み処理が長引くとこのパルスが止まる。
  正常なら100Hzのパルス。

出力文字数22文字で9600BPSだから約23ms。
この周期以上のINT1パルス入力なら、Serial.printでの
待ちは発生しません。

INT1の周期が23msを切ると、徐々にFIFOが詰まり出し、
割り込みの応答がおかしくなってきます。
割り込み処理にかかる時間が長くなると、他の割り込み、
(今回は計時用のタイマー0のオーバーフロー割り込み)
も影響を受け、正しい計時ができなくなってしまいます。

INT1の周期を22.8msにすると、パルス間隔はこんな具合に
変化します。

~~~~~~~~~~~~~~~~~~~~~
◆22.8ms周期のINT1パルス
 22文字なので文字列は約23msの長さ
Test Serial Print
割り込み回数 間隔
00000001 100172us (初回は不定)
00000002 22788us
00000003 22800us 最初は正常
00000004 22800us
 :
00000335 22800us
00000336 21776us FIFOが詰まり出して
00000337 22804us microsが正常に
00000338 22800us カウントできなくなる
00000339 21776us
00000340 21780us
 :
00000609 1296us
00000610 1324us
00000611 352us 割り込みが間に合わず
00000612 -672us 完璧にアウト
00000613 352us
00000614 348us
00000615 -668us
~~~~~~~~~~~~~~~~~~~~~

最初は22.8msを計測していますが、それが徐々に
詰まってきて(タイマー0が動かないので)、
612回目を過ぎるとアウトになっている様子
が捉えられました。

とうぜん、メインループ側も動かないのでD13パルス
(正常なら100Hz)も出てきません。

オシロでの観察波形です。
 上から(ch1→ch4)
  ch1:INT1入力 ↓エッジで割り込み
  ch2:LEDポート D13出力
  ch3:テスト用D12出力 割り込みでパルス
  ch4:TXD出力 アイドル中はHレベル

・シリアル出力が間に合って正常な時 
I000

・INT1にチャタリングを与えると・・・
I003

・その拡大
I004

Serial.printの処理がエライというのか、FIFOがちゃんと
働いて、文字の抜けはありません。
しかし、メインの処理が止まるのはやはり致命的。

割り込みの中でのSerial.print、いかがでしょうか。
「間に合えばエエやん」というのもご意見。
しかし、基本は書いたらアカんプログラムです。

※チャタリングの発生はこの回路で
「チャタリング除去回路」じゃなくって「チャタリング発生回路」をどうぞ

|

« 割り込み処理の中でのdelayやSerila.print,lcd.print | トップページ | 「充電しない!」K水道店君の現場用LEDランプ »

Arduino」カテゴリの記事

割り込み処理」カテゴリの記事

コメント

コメントを書く



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




« 割り込み処理の中でのdelayやSerila.print,lcd.print | トップページ | 「充電しない!」K水道店君の現場用LEDランプ »