google-site-verification: google3bd66dd162ef54c7.html
fc2ブログ

ArduinoでTimer1を使ってバーストパルスを発生させる

◆まえがき
前の記事で Arduino を使ってミニグラインダーのコントローラーを作りました。このプログラムで重要な役目を果たしたのが、PWM の波形を正確なタイミングでON/OFFさせるために作った Timer1 の割り込み処理ルーチンです。

いわゆるバーストPWM波を発生させた訳ですが、このルーチンはいろいろなことに使えそうです。ということで、このバーストPWM波形の生成の部分を抜き出して紹介したいと思います。たぶん後で何かの役に立つと思います。なお、プログラムの動作確認は Arduino UNO(互換品) で行いました。

外観

◆簡単にバーストPWM波形を発生させる方法
Arduino でバーストPWM波形を発生させたい場合、この記事で紹介する方法が一番品質の良い波形が生成出来ると思いますが、簡単にやるなら以下のような方法があります。

1)AnalogWriteを使う
AnalogWrite を使えばPWM波を出力出来るので、これをタイマー割り込みでON/OFF(AnalogWrite(0);でOFF)すればバースト波を作ることが出来ます。この方法は判り易くて簡単なので、実は前記したグラインダーの制御ソフトを作る時に最初はこの方法を用いました。

このやり方ではPWMの周波数がやや低く、(480Hzか980Hz) 分解能も1/256刻みにしか出来ないという制約がありますが、それ以外にもっと大きな問題がありました。それはPWM波形とバースト波のタイミングが固定されていないので、1周期のバースト内に含まれるPWMの山の数が変化してしまうことです。変化すると言ってもパルスの数が一つ違うことがあるだけですが、例えばフィードバック制御を行う時には余分な外乱になってしまうので好ましくありません。

2)Timer1とFlexiTimer2を使う
以前私が記事を書いた、Timer1とFlexiTimer2を使ったバーストパルス発生の実験の方法です。これなら前項の方法よりはマシになると思います。ただ失礼を承知で書くと、FlexiTimer2 はクセが強いのであまり使いたくないです。

これ以外にもいろんなやり方がありそうですが、ともかく今回私が作ったプログラムを説明します。

◆プログラム
前項のような問題が無いバーストPWM波の発生プログラムです。

・プログラム
// Timer1を使ってバーストPWM波形を発生させる 20230926_MH380_BurstPulseDeme.ino
// 2023/09/26 ラジオペンチ http://radiopench.blog96.fc2.com/

// パルスの仕様の設定(ミニグラインダーの制御用波形)
#define PULSE_N   10           // 1周期のパルス数
#define SKIP_N     2           // 停止する(歯抜けにする)パルス数
#define PERIOD    50           // パルス周期 (tm1のクロック数で指定、分周比8なら0.5usに対する倍率)
#define WIDTH     10           // パルス幅
#define INDEX_PW  10           // インデック信号のパルス幅(μs単位の値で指定、粒度は4us, 実際には5usくらい長くなる)

#define cbi(addr, bit) addr &= ~(1 << bit)  // addrのbit目を'0'にする
#define sbi(addr, bit) addr |=  (1 << bit)  // addrのbit目を'1'にする

volatile int    flagT0 = false; // バーストPWM先頭フラフ
volatile boolean outOn  = true; // true:出力ON, false:出力OFF,

void setup() {
  pinMode( 9, OUTPUT);           // PWM出力ポート
  pinMode(13, OUTPUT);           // インデックス信号

  // Timer1を fastPWMモード, プリスケーラ=8, Pin9から出力に設定
  TCCR1A  = 0b10000010;         // Timer1設定 (set: COM1A1, WMG11)
  TCCR1B  = 0b00011010;         // Timer1設定 (set: WGM13, WGM12, CS11)
  ICR1 = PERIOD - 1;            // Timer1カウント数上限(TOP値)を設定
  OCR1A = WIDTH - 1;            // パルス幅設定

  sbi(TIMSK1, OCIE1A);          // Timer1 割り込み許可(割り込み開始)
}

void loop() {
  while (flagT0 == false) {     // タイマー割り込みが入るまで待つ(PWMバーストの先頭でフラグON)
  }
  flagT0 = false;

  digitalWrite(13,HIGH);        // 同期信号を出力
  delayMicroseconds(INDEX_PW);
  digitalWrite(13,LOW);
}


ISR (TIMER1_COMPA_vect) {       // タイマー1割り込み処理。バーストPWM出力とメインへのタイミング通知
  static int cycle = 0;
  if (cycle == 0) {             // サイクルの先頭だったら、
    flagT0 = true;              // フラグを立ててメインに通知
  }
  if (cycle < SKIP_N) {         // 先頭のスキップ回数以内だったら、
    cbi(TCCR1A, COM1A1);        // PWM出力停止
  } else {
    if (outOn == true) {        // 出力フラグONなら
      sbi(TCCR1A, COM1A1);      // 先頭以外はPWM出力ON
    }
  }
  cycle++;                      // 次回に備えカウントアップ
  if (cycle >= PULSE_N) {       // 1サイクル分のパルス出したら先頭に戻す
    cycle = 0;
  }
}
設定を順に書くと、
・まずは setup の22,23行目の TCCR1A, TCCR1B で Timer1 を Fast PWMモード、クロックを2MHz(8分周)、Pin9~出力するように設定。
・PWM の周期は PERIOD で指定 (50*0.5us=25us)
・PWM のパルス幅は WIDTH で視程 (10*0.5us=5us)
・バーストの周期は PULSE_N で指定するパルス数で指定 (10*25us=250us)
・バーストパルスを歯抜けにする数は SKIP_N で指定 (2)

Timer1 を使っているので上記の PERIOD と WIDTH の値は16ビットまで指定可能なはずです。なお、当然ですがPERIOD>=WIDTH。

割込み処理ルーチン(ISR (TIMER1_COMPA_vect))で、パルスカウントにもとづき出力の要否を決定してバーストPWMを出力しています。

・実行結果
上記プログラムを実行した時の出力波形は以下のようになります。
テスト波形
上の波形が Index信号(Pin13)、下が PWM出力(pin9)です。
前項で説明した通り、1周期10パルスのうち先頭の2パルスが無い波形、つまりバースト波形が出ています。

◆ミニグラインダーの波形例
ミニグラインダーで使った条件のパルスを発生させてみます。プリスケーラーは8のままで、
PULSE_N=200, SKIP_N=9, PERIOD=400, WIDTH=100 に設定した場合の波形です。

・全体
ミニグラインダー波形全体
周期40msのバースト波が出ています。

・先頭部
グラインダー波形先頭部
先頭の9発がスキップされています。実際のプログラムではこのスキップした期間の間に誘導電圧の測定を行っています。

◆超音波レーダーの波形例
面白そうなので超音波レーダーの探査音を発生させるプログラムを作ってみました。0.1秒周期で周波数40kHzのバースト波を10発発生させています。0.1秒なら音速の往復で約170mまでの範囲の物体の検出が出来るはずです。

プログラムとしては、PULSE_N=4000, SKIP_N=3990, PERIOD=50, WIDTH=25 に設定しています。

・全体波形
超音波センサー
4000パルスのうち3990パルスを止め、残る10パルスだけ出力しています。100ms毎に出力されていることは判りますが、このスケールでは細部までは判りません。

・先頭部拡大
波形説明
オシロは下側のPWM波でトリガしています。40kHzで10発出力した後にインデックス信号が出ています。このタイミングから受信を開始すればレーダーが作れると思います。(簡単では無さそうですが、、)

◆まとめ
こういう設定はCPUのデーターシートをよく読まないと出来ませんが、この記事のように動作確認プログラムとセットでまとめておけば、すぐに使えて便利だと思います。

この記事を書いていて思い付いたのが、Arduinoを使った磁気浮上(吊り下げ)の実験です。この実験ではコイルに通電した状態で外部の磁石の磁界検出をやっていますが、自分で通電して磁界を発生させている状態で外部磁界の検出をやるのは、ちょっと無理がある気がします。そんなことしなくても、このプログラムを使ってコイルの通電を一旦停止し、その間に素早く外部磁化の検出をやってしまえば検出精度が上がって浮上の安定性が高まるかも知れません。時間のある時にやってみたいと思います。

この記事ではTimer1のプリスケーラーの分周比を8にして実験していますが、他の倍率も試すと良いと思います。但し、PWMの周期を極端に短くすると割り込み処理の ISR (TIMER1_COMPA_vect) が追いつかなくなって処理が破綻するかも知れません。ひょっとしたら多重に割り込みが入ってハングアップしてしまい、チップイレースかけて初期化しないとプログラムの書き込みが出来なくなってしまうかも知れませ。このあたりどうなんでしょうね。

関連記事

コメントの投稿

管理者にだけ表示を許可する

割り込みを早くするために

割り込み処理をちょっとでも速くする方法。
「ISR (TIMER1_COMPA_vect) 」を例に。

(1) 変数をint(2バイト)からbyte(1バイト)に。
    static int cycle = 0; これをbyteに
  すると、
    if(cycle == 0)
    if(cycle < SKIP_N)
    cycle++;
    if(cycle >= PULSE_N)
  の4箇所が高速化できます。

  volatile int flagT0 = false; // バーストPWM先頭フラフ
  これもbyteに。(booleanでも)

  AVRマイコン、wordデータの処理、いがいと時間がかかります。

   ※補足:関数内のstatic変数。
   初期値が0でokなら =0;を記す必要はありません。
   略すか =0;と書いておくかは好きずきです。

(2) 直接ビット操作できるI/Oアドレス外のポート操作を直接記述で。
  SBI、CBI命令(2クロック)でビット操作できるアドレスは
  0x00~0x1Fの32ポートだけです。
     入出力ポート、割り込みフラグなどが入る
  これ以外のところは、(例えばCBI命令への展開を期待しても)
    IN R, Port
    AND R, nn    指定ビットをマスク
    OUT Port, R
  と展開されて3クロックになってしまいます。
  レジスタへの即値が固定的なら、
    LDI R, nn
    OUT Port, R
  と2クロックで展開されるように、
    Reg = nn;
  と記すと、1クロックかせげます。

  しかし、AVRマイコンにはまだ落とし穴が。
  IN、OUTできるのはアドレス0x00~0x3Fの64ポートだけ。
  それより上のI/Oアドレスはメモリアクセスの命令を
  使わなくてはなりません。
  読み書きそれぞれ2クロックでIN、OUTよりクロック数が増えます。

  TCCR1AのI/Oアドレスは0x80でメモリアクセスでしか読み書きできません。

割り込みを早くするために

ちょっと長くなりますが、コンパイル結果を。

ISR (TIMER1_COMPA_vect) { // タイマー1割り込み処理。
a6: 1f 92 push r1
a8: 0f 92 push r0
aa: 0f b6 in r0, 0x3f ; 63
ac: 0f 92 push r0
ae: 11 24 eor r1, r1
b0: 2f 93 push r18
b2: 3f 93 push r19
b4: 8f 93 push r24
b6: 9f 93 push r25
static int cycle = 0;
if (cycle == 0) { // サイクルの先頭だったら、
b8: 80 91 05 01 lds r24, 0x0105
bc: 90 91 06 01 lds r25, 0x0106
c0: 00 97 sbiw r24, 0x00 ; 0
c2: 39 f4 brne .+14 ; 0xd2
flagT0 = true; // フラグを立ててメインに通知
c4: 21 e0 ldi r18, 0x01 ; 1
c6: 30 e0 ldi r19, 0x00 ; 0
c8: 30 93 04 01 sts 0x0104, r19
cc: 20 93 03 01 sts 0x0103, r18
d0: 03 c0 rjmp .+6 ; 0xd8
}
if (cycle < SKIP_N) { // 先頭のスキップ回数以内だったら、
d2: 82 30 cpi r24, 0x02 ; 2
d4: 91 05 cpc r25, r1
d6: 24 f4 brge .+8 ; 0xe0
cbi(TCCR1A, COM1A1); // PWM出力停止
d8: 20 91 80 00 lds r18, 0x0080
dc: 2f 77 andi r18, 0x7F ; 127
de: 07 c0 rjmp .+14 ; 0xee
} else {
if (outOn == true) { // 出力フラグONなら
e0: 20 91 00 01 lds r18, 0x0100
e4: 21 30 cpi r18, 0x01 ; 1
e6: 29 f4 brne .+10 ; 0xf2
sbi(TCCR1A, COM1A1); // 先頭以外はPWM出力ON
e8: 20 91 80 00 lds r18, 0x0080
ec: 20 68 ori r18, 0x80 ; 128
ee: 20 93 80 00 sts 0x0080, r18
}
}
cycle++; // 次回に備えカウントアップ
f2: 01 96 adiw r24, 0x01 ; 1
if (cycle >= PULSE_N) { // 1サイクル分のパルス出したら先頭に戻す
f4: 8a 30 cpi r24, 0x0A ; 10
f6: 91 05 cpc r25, r1
f8: 2c f4 brge .+10 ; 0x104
} else {
if (outOn == true) { // 出力フラグONなら
sbi(TCCR1A, COM1A1); // 先頭以外はPWM出力ON
}
}
cycle++; // 次回に備えカウントアップ
fa: 90 93 06 01 sts 0x0106, r25
fe: 80 93 05 01 sts 0x0105, r24
102: 04 c0 rjmp .+8 ; 0x10c
if (cycle >= PULSE_N) { // 1サイクル分のパルス出したら先頭に戻す
cycle = 0;
104: 10 92 06 01 sts 0x0106, r1
108: 10 92 05 01 sts 0x0105, r1
}
}
10c: 9f 91 pop r25
10e: 8f 91 pop r24
110: 3f 91 pop r19
112: 2f 91 pop r18
114: 0f 90 pop r0
116: 0f be out 0x3f, r0 ; 63
118: 0f 90 pop r0
11a: 1f 90 pop r1
11c: 18 95 reti

タブが抜けた!

H-TABが入ってました。
それが抜けちゃいました。

再送

ISR (TIMER1_COMPA_vect) {    // タイマー1割り込み処理。
 a6:  1f 92      push  r1
 a8:  0f 92      push  r0
 aa:  0f b6      in   r0, 0x3f    ; 63
 ac:  0f 92      push  r0
 ae:  11 24      eor   r1, r1
 b0:  2f 93      push  r18
 b2:  3f 93      push  r19
 b4:  8f 93      push  r24
 b6:  9f 93      push  r25
 static int cycle = 0;
 if (cycle == 0) {       // サイクルの先頭だったら、
 b8:  80 91 05 01   lds   r24, 0x0105
 bc:  90 91 06 01   lds   r25, 0x0106
 c0:  00 97      sbiw  r24, 0x00    ; 0
 c2:  39 f4      brne  .+14      ; 0xd2
  flagT0 = true;       // フラグを立ててメインに通知
 c4:  21 e0      ldi   r18, 0x01    ; 1
 c6:  30 e0      ldi   r19, 0x00    ; 0
 c8:  30 93 04 01   sts   0x0104, r19
 cc:  20 93 03 01   sts   0x0103, r18
 d0:  03 c0      rjmp  .+6       ; 0xd8
 }
 if (cycle < SKIP_N) {     // 先頭のスキップ回数以内だったら、
 d2:  82 30      cpi   r24, 0x02    ; 2
 d4:  91 05      cpc   r25, r1
 d6:  24 f4      brge  .+8       ; 0xe0
  cbi(TCCR1A, COM1A1);    // PWM出力停止
 d8:  20 91 80 00   lds   r18, 0x0080
 dc:  2f 77      andi  r18, 0x7F    ; 127
 de:  07 c0      rjmp  .+14      ; 0xee
 } else {
  if (outOn == true) {    // 出力フラグONなら
 e0:  20 91 00 01   lds   r18, 0x0100
 e4:  21 30      cpi   r18, 0x01    ; 1
 e6:  29 f4      brne  .+10      ; 0xf2
   sbi(TCCR1A, COM1A1);   // 先頭以外はPWM出力ON
 e8:  20 91 80 00   lds   r18, 0x0080
 ec:  20 68      ori   r18, 0x80    ; 128
 ee:  20 93 80 00   sts   0x0080, r18
  }
 }
 cycle++;           // 次回に備えカウントアップ
 f2:  01 96      adiw  r24, 0x01    ; 1
 if (cycle >= PULSE_N) {    // 1サイクル分のパルス出したら先頭に戻す
 f4:  8a 30      cpi   r24, 0x0A    ; 10
 f6:  91 05      cpc   r25, r1
 f8:  2c f4      brge  .+10      ; 0x104
 } else {
  if (outOn == true) {    // 出力フラグONなら
   sbi(TCCR1A, COM1A1);   // 先頭以外はPWM出力ON
  }
 }
 cycle++;           // 次回に備えカウントアップ
 fa:  90 93 06 01   sts   0x0106, r25
 fe:  80 93 05 01   sts   0x0105, r24
102:  04 c0      rjmp  .+8       ; 0x10c
 if (cycle >= PULSE_N) {    // 1サイクル分のパルス出したら先頭に戻す
  cycle = 0;
104:  10 92 06 01   sts   0x0106, r1
108:  10 92 05 01   sts   0x0105, r1
 }
}
10c:  9f 91      pop   r25
10e:  8f 91      pop   r24
110:  3f 91      pop   r19
112:  2f 91      pop   r18
114:  0f 90      pop   r0
116:  0f be      out   0x3f, r0    ; 63
118:  0f 90      pop   r0
11a:  1f 90      pop   r1
11c:  18 95      reti

byteに換えると

byteに換えてみると。
  (コンペアB割り込みで記述)
push、popされるレジスタの数まで変わります。

ISR (TIMER1_COMPB_vect) {
11e:  1f 92      push  r1
120:  0f 92      push  r0
122:  0f b6      in   r0, 0x3f    ; 63
124:  0f 92      push  r0
126:  11 24      eor   r1, r1
128:  8f 93      push  r24
 static byte cycle = 0; // ★1
 if (cycle == 0) { // ★1
12a:  80 91 07 01   lds   r24, 0x0107
12e:  81 11      cpse  r24, r1
130:  04 c0      rjmp  .+8       ; 0x13a
  flagT1 = true;
132:  81 e0      ldi   r24, 0x01    ; 1
134:  80 93 02 01   sts   0x0102, r24
138:  02 c0      rjmp  .+4       ; 0x13e
 }
 if (cycle < SKIP_N) { // ★1
13a:  82 30      cpi   r24, 0x02    ; 2
13c:  10 f4      brcc  .+4       ; 0x142
        TCCR1A = 0b00000010; // ★2
13e:  82 e0      ldi   r24, 0x02    ; 2
140:  05 c0      rjmp  .+10      ; 0x14c
 } else {
  if (outOn == true) {
142:  80 91 00 01   lds   r24, 0x0100
146:  81 30      cpi   r24, 0x01    ; 1
148:  19 f4      brne  .+6       ; 0x150
        TCCR1A = 0b10000010; // ★2
14a:  82 e8      ldi   r24, 0x82    ; 130
14c:  80 93 80 00   sts   0x0080, r24
  }
 }
 cycle++; // ★1
150:  80 91 07 01   lds   r24, 0x0107
154:  8f 5f      subi  r24, 0xFF    ; 255
 if (cycle >= PULSE_N) { // ★1
156:  8a 30      cpi   r24, 0x0A    ; 10
158:  18 f4      brcc  .+6       ; 0x160
 } else {
  if (outOn == true) {
        TCCR1A = 0b10000010; // ★2
  }
 }
 cycle++; // ★1
15a:  80 93 07 01   sts   0x0107, r24
15e:  02 c0      rjmp  .+4       ; 0x164
 if (cycle >= PULSE_N) { // ★1
  cycle = 0;
160:  10 92 07 01   sts   0x0107, r1
 }
}
164:  8f 91      pop   r24
166:  0f 90      pop   r0
168:  0f be      out   0x3f, r0    ; 63
16a:  0f 90      pop   r0
16c:  1f 90      pop   r1
16e:  18 95      reti

AVR studioで

アセンブルリストを出したのはちょっと古いAVR studio。
「static int cycle」にvolatileが無いので処理が抜けている?
ありゃ?

cycleにvolatileを入れたら

ISR (TIMER1_COMPA_vect) {    // タイマー1割り込み処理。
 a6:  1f 92      push  r1
 a8:  0f 92      push  r0
 aa:  0f b6      in   r0, 0x3f    ; 63
 ac:  0f 92      push  r0
 ae:  11 24      eor   r1, r1
 b0:  8f 93      push  r24
 b2:  9f 93      push  r25
volatile static int cycle = 0;
 if (cycle == 0) {       // サイクルの先頭だったら、
 b4:  80 91 05 01   lds   r24, 0x0105
 b8:  90 91 06 01   lds   r25, 0x0106
 bc:  89 2b      or   r24, r25
 be:  31 f4      brne  .+12      ; 0xcc
  flagT0 = true;       // フラグを立ててメインに通知
 c0:  81 e0      ldi   r24, 0x01    ; 1
 c2:  90 e0      ldi   r25, 0x00    ; 0
 c4:  90 93 04 01   sts   0x0104, r25
 c8:  80 93 03 01   sts   0x0103, r24
 }
 if (cycle < SKIP_N) {     // 先頭のスキップ回数以内だったら、
 cc:  80 91 05 01   lds   r24, 0x0105
 d0:  90 91 06 01   lds   r25, 0x0106
 d4:  02 97      sbiw  r24, 0x02    ; 2
 d6:  24 f4      brge  .+8       ; 0xe0
  cbi(TCCR1A, COM1A1);    // PWM出力停止
 d8:  80 91 80 00   lds   r24, 0x0080
 dc:  8f 77      andi  r24, 0x7F    ; 127
 de:  07 c0      rjmp  .+14      ; 0xee
 } else {
  if (outOn == true) {    // 出力フラグONなら
 e0:  80 91 00 01   lds   r24, 0x0100
 e4:  81 30      cpi   r24, 0x01    ; 1
 e6:  29 f4      brne  .+10      ; 0xf2
   sbi(TCCR1A, COM1A1);   // 先頭以外はPWM出力ON
 e8:  80 91 80 00   lds   r24, 0x0080
 ec:  80 68      ori   r24, 0x80    ; 128
 ee:  80 93 80 00   sts   0x0080, r24
  }
 }
 cycle++;           // 次回に備えカウントアップ
 f2:  80 91 05 01   lds   r24, 0x0105
 f6:  90 91 06 01   lds   r25, 0x0106
 fa:  01 96      adiw  r24, 0x01    ; 1
 fc:  90 93 06 01   sts   0x0106, r25
100:  80 93 05 01   sts   0x0105, r24
 if (cycle >= PULSE_N) {    // 1サイクル分のパルス出したら先頭に戻す
104:  80 91 05 01   lds   r24, 0x0105
108:  90 91 06 01   lds   r25, 0x0106
10c:  0a 97      sbiw  r24, 0x0a    ; 10
10e:  24 f0      brlt  .+8       ; 0x118
  cycle = 0;
110:  10 92 06 01   sts   0x0106, r1
114:  10 92 05 01   sts   0x0105, r1
 }
}
118:  9f 91      pop   r25
11a:  8f 91      pop   r24
11c:  0f 90      pop   r0
11e:  0f be      out   0x3f, r0    ; 63
120:  0f 90      pop   r0
122:  1f 90      pop   r1
124:  18 95      reti

byteでvolatile

長くなってごめんなさい。 スカタンも。

ISR (TIMER1_COMPB_vect) {
126:  1f 92      push  r1
128:  0f 92      push  r0
12a:  0f b6      in   r0, 0x3f    ; 63
12c:  0f 92      push  r0
12e:  11 24      eor   r1, r1
130:  8f 93      push  r24
volatile static byte cycle = 0; // ★1
 if (cycle == 0) { // ★1
132:  80 91 07 01   lds   r24, 0x0107
136:  81 11      cpse  r24, r1
138:  03 c0      rjmp  .+6       ; 0x140
  flagT1 = true;
13a:  81 e0      ldi   r24, 0x01    ; 1
13c:  80 93 02 01   sts   0x0102, r24
 }
 if (cycle < SKIP_N) { // ★1
140:  80 91 07 01   lds   r24, 0x0107
144:  82 30      cpi   r24, 0x02    ; 2
146:  10 f4      brcc  .+4       ; 0x14c
        TCCR1A = 0b00000010; // ★2
148:  82 e0      ldi   r24, 0x02    ; 2
14a:  05 c0      rjmp  .+10      ; 0x156
 } else {
  if (outOn == true) {
14c:  80 91 00 01   lds   r24, 0x0100
150:  81 30      cpi   r24, 0x01    ; 1
152:  19 f4      brne  .+6       ; 0x15a
        TCCR1A = 0b10000010; // ★2
154:  82 e8      ldi   r24, 0x82    ; 130
156:  80 93 80 00   sts   0x0080, r24
  }
 }
 cycle++; // ★1
15a:  80 91 07 01   lds   r24, 0x0107
15e:  8f 5f      subi  r24, 0xFF    ; 255
160:  80 93 07 01   sts   0x0107, r24
 if (cycle >= PULSE_N) { // ★1
164:  80 91 07 01   lds   r24, 0x0107
168:  8a 30      cpi   r24, 0x0A    ; 10
16a:  10 f0      brcs  .+4       ; 0x170
  cycle = 0;
16c:  10 92 07 01   sts   0x0107, r1
 }
}
170:  8f 91      pop   r24
172:  0f 90      pop   r0
174:  0f be      out   0x3f, r0    ; 63
176:  0f 90      pop   r0
178:  1f 90      pop   r1
17a:  18 95      reti

re:割り込みを早くするために

いろいろやって戴いてありがとうございます。

割込みルーチンの先頭と最後にポートに出力出して(SBIとCBIでポートを直接操作)実行時間を測ると、分岐によって実行時間は変わりますが、最大値だと、
オリジナルでは、2.6μs
cycle を int にすると、2.0μs
outONの処理を無しにすると、1.7μs
でした。

cycleは記事の3番目の例だと4000を設定するのでbyteという訳にはいかないのですが、普通ならこんな大きな値は使わないのでbyteにしといた方が良さそうですね。

あと、pushとpopは上記の測定結果には含まれていないと思うのですが、回数が多いし実行に2クロック必要みたいなので、バカにならないですね。
カレンダー
02 | 2024/03 | 04
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。
記事の内容のご利用は読者の自己責任でお願いします。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード