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) が追いつかなくなって処理が破綻するかも知れません。ひょっとしたら多重に割り込みが入ってハングアップしてしまい、チップイレースかけて初期化しないとプログラムの書き込みが出来なくなってしまうかも知れませ。このあたりどうなんでしょうね。

カレンダー
08 | 2023/09 | 10
- - - - - 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
プロフィール

ラジオペンチ

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

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