macです。 Heatman さん<heatman@xxxxxxxxxxxxx> wrote: > >16bit以上に拡張したいときは、 > : > >unsinged intとして、TCNT2を読み、 > >32767以上なら、アンダーフロー、 > >32767未満なら、オーバフロー、 > >として、適当な変数extを、 > >アンダーフローならext-- > >オーバフローなら、ext++ > > 通常時は、カウンタ値を適当な変数に移し > オーバフロー、アンダーフローの場合は、 > 状態に応じて変数の値を増減すれば良いと > いうことでよろしいのでしょうか? カウンターはあくまでフリーランニングさせ、 カウンタにTCNT2にWriteはしません。 TIER2のOVIEを立てておき、 Interruptがかかったら、TSRを読み OVF = 0にした後、 TCNT2を読み、もし、TCNT2が、0x0002だったら、 w = (++ext << 16) | TCNT2; もし、リセット後最初なら、 0x00010002が、その時点のカウンター値だと、 読めばよいということです。 しかし、この方法は、重大な欠陥を持っています。 TCNT2を読んだあと、 w = (++ext << 16) | TCNT2; している間も、カウンターは動作し、 TCNT2は別の値になっている可能性があります。 そこで、割り込み直後、 t = TCNT2; としてから、TSRを処理し、 w = (++ext << 16) | t; if ( t < 0x8000) w = (++ext << 16) | t; else w = (--ext << 16) | t; としたらどうでしょう。 一見うまくいきそうですね。 でも、まだ抜け穴があるんです。 割り込みが起こり、この処理が行われる前に、 もう一度、オーバーフロー/アンダーフローが、 起きている可能性があるのです。 TCNT2が、0xffffから、0x0000になったので、 OVI割り込みが発生したが、さまざまな理由で、 割り込み処理開始が遅れ、 その間にエンコーダーが逆転し、 TCNT2が、0x0000から、0xffffに なってしまったらどうでしょう。 処理プログラムは、アンダーフローが起こったと判断し、 w = (--ext << 16) | t; と処理します。 でも、本当はその前に、 w = (++ext << 16) | t; を実行した後、 w = (--ext << 16) | t; が実行されるべきなのですが、その遷移を見落とされ、 実際の値から2^16もの誤差を生じることになります。 この現象は、もはやソフトウエアーで処理できません。 そこで、TCNT2に、 オーバーフロー/アンダーフローが起きた回数を、 別のハードウエアーで勘定し、 処理しなければならないわけです。 具体的には、TCNT2が0x0000,0xffffを通過した回数を、 勘定し、--extか、++extのどちらを行うべきか判断するのに、 外部カウンターを使います。 それが先の解答の内容です。 さらに付け加えると、0x0000,0xffffを往復したのではなく、 本当に軸が、2^16カウント分回った可能性が理屈の上ではありますが、 それは、このシステムの処理限界を超えています。 ITUではなく、外部に高速のUp/Downカウンターをつけ、 処理しなければできません。 -- mac