3

ハードウェアタイマーで遅延機能を実装する必要があります。タイマー値はミリ秒ごとに増加します。

通常のアプローチは、タイマーレジスタの幅を使用し、に対応するモジュロ動作を使用することです。

volatile int TimerReg;

void Delay(int amount)
{
    int start = TimerReg;
    int elapsed;

    do
    {
        eleapsed = TimerReg - start;
    } while (elapsed < amount);
}

これは、TimerRegの幅がintの場合に機能します。その場合、差now - startは着実に増加する値です。

しかし、TimerRegの幅がintの幅よりも小さい場合、または(私の場合のように)タイマーが0..1000からしかカウントされない場合、タイマーが999から1000を超えて0にラップするときに問題が発生します。

そのようなタイマーを使用するための良いアプローチは何ですか?これはマイクロコントローラーでは高価なので、モジュロ演算は避けたいと思います。

編集:分割モジュールはまだマイクロコントローラーコードに含まれていません。

4

6 に答える 6

3

このようなものはどうですか:

volatile int TimerReg;

void Delay(int amount)
{
  int start = TimerReg;
  int elapsed;
  int rolled_over = 0;
  int last_time = start;

  do
  {
    int timer_reg = TimerReg;
    // Check for rollover
    if(last_time > timer_reg) {
      // ROLLOVER_INTERVAL is the magic number at which the timer rolls over to 0
      rolled_over += ROLLOVER_INTERVAL - start;
      start = 0;
    }
    last_time = timer_reg;
    if(rolled_over == 0) {
      elapsed = timer_reg - start;
    } else {
      elapsed = timer_reg + rolled_over;
    }
  } while (elapsed < amount);
}

確かに、さらに2つのifテストと2つの変数があるので、おそらくより効率的な解決策があります。

于 2012-04-27T12:39:28.633 に答える
1

誰がそのタイマーのロールオーバーを制御しますか?たとえば、これを999から000ではなく0xFFFロールオーバーに変更できる場合は、単純なマスクを使用できます。

elapsed = (TimerReg - start)&0xFFF;

とても安いです

elapsed = (TimerReg - start)%1000; 

あなたが今いる場所は非常に高価です。

それほど悪くない代替案は、エドヴァルドが投稿したものです。基本的にロールオーバーを確認してください

nowtime = TimerReg;
if(nowtime < start)
{
   elapsed = (1000 - start) + nowtime;
}
else
{
   elapsed = nowtime - start;
}

上記のすべては、アップカウントタイマーを前提としています。

マイクロコントローラーには複数のタイマーが含まれていることがよくあります。最大カウント(0xFFFFまたは0xFFFFFFFFなど)までカウントしてゼロにロールオーバーするタイマーを残しておくと、すぐに使用できるようになります。時間の価値のあるロールオーバー)。

于 2012-04-27T13:49:28.350 に答える
0

あなたが本当のハードウェアタイマーを持っているなら、あなたはこれを好きです:

start_timer();
while ( (timer_flag_register & bitmask)==0 )
{
  do_stuff();
}

ここで、start_timer()は、ハードウェアタイマーカウンターを[メインタイマーカウンター]+[遅延時間]に設定します。時間が経過すると、ハードウェアはフラグを設定します(または割り込みサービスルーチンを呼び出します)。すべてのMCUのほぼすべてのハードウェアタイマーがこのように機能します。

于 2012-04-27T13:54:03.777 に答える
0

タイマーがその値に達したときに割り込みを使用して、グローバルカウンターをインクリメントできます(たとえば、1000ミリ秒ごと)。

于 2012-04-27T14:21:37.260 に答える
0

私はそれを考え出した。タイマーレジスタの幅がintの幅と同じである場合、これは暗黙的に行われます。elapsed有効な範囲に入れることができない場合は、タイマーの数字の円を値に追加するだけで十分です。

volatile int TimerReg; /* value range: 0..999 */
const int TimerMaxValue = 999;

void Delay(int amount) 
{ 
    int start = TimerReg; 
    int elapsed; 

    do 
    { 
        eleapsed = TimerReg - start;
        if (elapsed < 0) eplapsed += (TimerMaxValue + 1);
    } while (elapsed < amount); 
} 
于 2012-04-27T14:29:42.520 に答える
-1

1msタイマー(ナイキスト周波数)は、ポーリングコードよりもはるかに低速です。したがって、単純にuqual演算子'='を使用できます。

volatile int TimerReg;

void Delay(int amount)
{
    int future = TimerReg + amount;

    while (TimerReg != future);
}

私の謙虚な意見では、これはエレガントなソリューションですが、「TimerReg」がその全範囲(たとえば「0xffff」)で自由に実行できる場合にのみ機能します。

于 2012-05-01T07:34:59.493 に答える