ニックネーム: 居酒屋ガレージ店主
★ZAQのBlogari停止のため、あれこれ「データ吸い出し」対策しています。 新規記事はとりあえず停止。 コメント書き込みはまだ有効です。 (JH3DBO 下間憲行)
2016年02月19日(金)
Arduinoのタイマー処理
Arduinoの内部で勝手に実行されているタイマー割り込み、
(タイマー0のオーバーフローが使われている)
その実行時間を調べておきました。

いわゆるシステム割り込みで、ユーザープログラムが走り
始める時、その裏でこれが勝手に走り始めます。
これが、millis()関数などのタイマーを管理しています。

メイン側で、タイミングにクリチカルな処理を行う時は、
この割り込みが裏で動いていることを自覚しておかなくて
はなりません。

これがいやなら、処理の前に割り込み禁止命令を入れてお
きます。
ただし、1ミリ秒以内に割り込みを有効に戻しておかないと
タイマーが遅れます。


●確認方法1

「loop」内で出力ポートにパルスを出し、そのパルスの
変動をオシロスコープで観察します。
スケッチはこんな具合。
void setup() {
  pinMode(8, OUTPUT);
}
void loop() {
 digitalWrite(8, HIGH);  // pin8にH/Lパルス
 digitalWrite(8, LOW);
}
これの観察結果(クリックで拡大↓)


割り込み処理が入ると、パルス出力の間隔が変わり
ます。

●確認方法2

digitalWriteを使うと、パルス幅が長くなるので、
「SBI CBI」命令を使います。
#include "wiring_private.h"   // sbi,cbi命令用
#define D8_H  (sbi(PORTB,PORTB0)) // digital pin8
#define D8_L  (cbi(PORTB,PORTB0))
void setup() {
  pinMode(8, OUTPUT);
}
void loop() {
  while(1){  // 永久実行で
   D8_H;   // pin8にH/Lパルス
   D8_L;
  }
}
すると、こうなります。(クリックで拡大↓)


むちゃ出力パルスが早くなりました。
この処理時間(6.5マイクロ秒ほど)が約1msに1回、
入るのです。

●割り込み周期を見る

約1msに1回と記しましたが、割り込み周期は正確な1msでは
ありません。
  (タイマー0のオーバーフローということで、ハードでは
    微調整できないのです)
それを確認してみます。

こんなスケッチです。
#include "wiring_private.h"   // sbi,cbi命令用
#define D8_H  (sbi(PORTB,PORTB0)) // digital pin8
#define D8_L  (cbi(PORTB,PORTB0))
#define D9_H  (sbi(PORTB,PORTB1)) // digital pin9
#define D9_L  (cbi(PORTB,PORTB1))
unsigned long tm1;   // ミリ秒タイマー
void setup() {
  pinMode(8, OUTPUT);  // pin8はサイクル実行
  pinMode(9, OUTPUT);  // pin9は1ms経過で
}
void loop() {
  while(1){
   D8_H;      // pin 8 H,Lパルス出力
   D8_L;
   if(tm1 != millis()){  // タイマー変化あり
    D9_H;        // pin 9 H,Lパルス出力
    D9_L;
    tm1 = millis();
   }
  }
}
こんな波形が出てきます。

まずこれ。 1msの変化検出したところ。
(クリックで拡大↓)



このpin9パルスの周期をオシロで読むと1msを超えて
いることがわかります。
(クリックで拡大↓)


タイマー値の変化を検出して出しているパルスが1ms
ちょいの間隔で見えています。


正確には、システムクロック周波数16MHzの1/64の1/256で
「1.024ms」。
  (タイマー割り込み内では端数をうまく処理して
   millis関数での誤差が出ないようにしています)



※追記
せっかくなんで、このタイマー割り込み処理の機械語命令
を拾っておきました。(avr-objdumpを使ってで出てくる)
まずこれがwiring.c内のCで記述されたタイマー割り込み
プログラム。

volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
#if defined(__AVR_ATtiny24__) ||
  defined(__AVR_ATtiny44__) ||
  defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;
  m += MILLIS_INC;
  f += FRACT_INC;
  if (f >= FRACT_MAX) {
    f -= FRACT_MAX;
    m += 1;
  }
  timer0_fract = f;
  timer0_millis = m;
  timer0_overflow_count++;
}


コンパイルされて出てきた機械語がこれ。
00000174 <__vector_16>:
174:  1f 92      push  r1
176:  0f 92      push  r0
178:  0f b6      in r0, 0x3f  ; 63
17a:  0f 92      push  r0
17c:  11 24      eor r1, r1
17e:  2f 93      push  r18
180:  3f 93      push  r19
182:  8f 93      push  r24
184:  9f 93      push  r25
186:  af 93      push  r26
188:  bf 93      push  r27
18a:  80 91 01 01   lds r24, 0x0101
18e:  90 91 02 01   lds r25, 0x0102
192:  a0 91 03 01   lds r26, 0x0103
196:  b0 91 04 01   lds r27, 0x0104
19a:  30 91 00 01   lds r19, 0x0100
19e:  23 e0      ldi r18, 0x03  ; 3
1a0:  23 0f      add r18, r19
1a2:  2d 37      cpi r18, 0x7D  ; 125
1a4:  20 f4      brcc  .+8     ; 0x1ae
1a6:  01 96      adiw  r24, 0x01  ; 1
1a8:  a1 1d      adc r26, r1
1aa:  b1 1d      adc r27, r1
1ac:  05 c0      rjmp  .+10    ; 0x1b8
1ae:  26 e8      ldi r18, 0x86  ; 134
1b0:  23 0f      add r18, r19
1b2:  02 96      adiw  r24, 0x02  ; 2
1b4:  a1 1d      adc r26, r1
1b6:  b1 1d      adc r27, r1
1b8:  20 93 00 01   sts 0x0100, r18
1bc:  80 93 01 01   sts 0x0101, r24
1c0:  90 93 02 01   sts 0x0102, r25
1c4:  a0 93 03 01   sts 0x0103, r26
1c8:  b0 93 04 01   sts 0x0104, r27
1cc:  80 91 05 01   lds r24, 0x0105
1d0:  90 91 06 01   lds r25, 0x0106
1d4:  a0 91 07 01   lds r26, 0x0107
1d8:  b0 91 08 01   lds r27, 0x0108
1dc:  01 96      adiw  r24, 0x01  ; 1
1de:  a1 1d      adc r26, r1
1e0:  b1 1d      adc r27, r1
1e2:  80 93 05 01   sts 0x0105, r24
1e6:  90 93 06 01   sts 0x0106, r25
1ea:  a0 93 07 01   sts 0x0107, r26
1ee:  b0 93 08 01   sts 0x0108, r27
1f2:  bf 91      pop r27
1f4:  af 91      pop r26
1f6:  9f 91      pop r25
1f8:  8f 91      pop r24
1fa:  3f 91      pop r19
1fc:  2f 91      pop r18
1fe:  0f 90      pop r0
200:  0f be      out 0x3f, r0  ; 63
202:  0f 90      pop r0
204:  1f 90      pop r1
206:  18 95      reti

「unsigned long」の加算や比較処理の実態が見えています。


※関連
ラジオペンチ ArduinoのMStimer2の精度の改善
Arduinoでの時間管理:放課後マイコンクラブ
Arduinoの入力速度を調べた


2016年2月19日 12時01分 | 記事へ | コメント(1) | トラックバック(0) |
| ・電子回路工作 |
トラックバックURL:http://blog.zaq.ne.jp/igarage/trackback/4365/
※ブログ管理者が承認するまで表示されません
リンクを貼っていただいてありがとうございます。

この記事がきっかけで、下記の記事を書かせていただいたのでご報告。

http://radiopench.blog96.fc2.com/blog-entry-643.html
コメントを記入  
お名前(必須)
 
パスワード:
 
メール:
 
URL:
 
非公開:  クッキーに保存: 
※非公開にチェックを入れると、管理者のみにコメントが届きます。
ブログの画面には表示されません。
captcha


※画像に表示されている文字を入力してください(半角・大文字/小文字の区別なし)。
文字が読みづらい場合はこちらをクリックしてください。
小文字 太字 斜体 下線 取り消し線 左寄せ 中央揃え 右寄せ テキストカラー リンク