« 割り切れない分周比でインターバル動作 | トップページ | 長周期かつ高時間分解能なインプットキャプチャ »

2021年5月18日 (火)

インプットキャプチャ

今度はインプットキャプチャネタ。

入力信号の周波数を計測するのに、
実際のパルスの数をカウントして、
1秒ごとに集計する、ってのは、まあ
原理に沿っているのだけれど、
一秒間待たないとデータが更新できない
とか、1Hz以下の信号が計測できないとか、
数百Hz以上のオーダーにならないと、
あんまり使い勝手の良いものではない。

------

なので、現実的な実装は、
外部からの入力パルスのエッジで
イベントを起こして、パルスの間隔を計測。

これをもとに信号の周波数を計測するって
方法を使うんだけど。

これをやるときに必要な技が存在する。


計測値が更新されるのは、
パルスが入力された時なので、
逆にパルスの入力が途絶えると
値の更新が止まる。

つまり、そのままでは
0Hzが計測できない


まあ、0Hz見なくてよければ
そのままでいいけど、たいていの場合、
ある程度の時間監視して
パルスが止まっているのも検出したい。

あと、入力パルス間隔が広くなって、
タイマーがオーバーフローすると
正しい時間間隔が計測できないので、
これも対策しないとマズい。


ただ、これを実装するのに、
当該のタイマー自身のオーバーフロー
イベントを使うと、
前述のコンペアマッチと
同じような理由で、作動が怪しく
なるタイミングが出来てしまう。


なので、ちょっと煩雑だけど
別のインターバル割り込みをを使って、
インプットキャプチャで計測できる
(カウンターが前回の値に到達しない)
時間の範囲を大まかに測って
タイムアウト処理をする。


よくやるのは、16ビットインプット
キャプチャを、1MHzでカウント。

別途1msec毎割り込みを使い、
入力の間隔が64msecを超えたら、
(65.535msecがデッドライン)
計測オーバーフローにする。
なんて組み合わせとか。



全体としてはこんな感じ


unsigned short interval;   //  計測した時間間隔
int timeout;       // タイムアウトカウンタ


void SysTick_Handler(void){ //  1msecインターバル

  if (timeout > 0 ){
    timeout--;
    if (timeout == 0){
      interval = 0xffff;  // タイムアウト
      }
    }
  }
}


void TIM2_IRQHandler(void) {  // ch1でインプットキャプチャ

  static unsigned short last;
  unsigned short us;


  if (TIM2->SR & (1 << 1)) {  //インプットキャプチャ

    us = TIM2->CCR1;

    if (timeout > 0){
      interval = us - last;  // 前回との差を時間間隔とする
    }
    last = us;     // 今回の値を保存
    timeout = 64;   // タイムアウト初期化

  }
}



今回もARRは0xffffとして、
カウンター自体は0~0xffffの
フリーランカウンタとする。

こうしておけば、ch0~3で別々の
パルスを計測できるし、
なんなら、別のチャンネルは
コンペアマッチでパルス生成に
使ってもいい

これを使うと、入力パルスに
位相を合わせた、パルスが出力できたり、
簡単な逓倍波形を出力できたりする。



つづく

| |

« 割り切れない分周比でインターバル動作 | トップページ | 長周期かつ高時間分解能なインプットキャプチャ »

コメント

コメントを書く



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




« 割り切れない分周比でインターバル動作 | トップページ | 長周期かつ高時間分解能なインプットキャプチャ »