| 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の入力速度を調べた
 
 
 
 | 
	
この記事がきっかけで、下記の記事を書かせていただいたのでご報告。
http://radiopench.blog96.fc2.com/blog-entry-643.html