ATmega128のタイマ比較機能を使ってサーボPWM出力・実践編
すいません m(_ _)m、本記事はブログ引越時に書式が崩れました。順次修正中です。
というわけで、さっそくプログラムを組んでみました。いろいろと小さな落とし穴はありましたが、なんだかうまくいった感じです。引き続き、いろいろとテストをしてみようと思います。
ハードウェア初期化
今回はタイマ1を使用します。比較出力を使用するためには、まず該当のI/Oポートを出力にします。
DDRB = _BV( DDB7 ) // PB7出力
| _BV( DDB6 ) // PB6出力
| _BV( DDB5 ); // PB5出力
次に、タイマ1の設定をします。まずは何かあった時でも信号がHIGHにならないように、一致したらLOWにしておきます。
// 比較A一致LOW出力
TCCR1A = _BV( COM1A1 ) // タイマ標準動作モード
| _BV( COM1B1 ) // 比較B一致LOW出力
| _BV( COM1C1 ); // 比較C一致LOW出力
続いて、タイマの速度を設定します。ジャイロ捕獲入力と同じ設定で、1カウントが0.5usになるよう、8分周にします。
TCCR1B = _BV( CS11 ); // クロック選択(8分周)カウント0.5us
あとは適当にだだだっとクリアします。
TCNT1 = 0; // タイマクリア
OCR1A = 0; // 比較Aレジスタクリア
OCR1B = 0; // 比較Bレジスタクリア
OCR1C = 0; // 比較Cレジスタクリア
最後に、タイマ1比較A割り込みの許可をして…
TIMSK = _BV( OCIE1A ); // タイマ1比較A割り込み許可
お決まりの
sei();
をいれて、全体の割り込みを許可します。
タイマ1比較Aによる割り込み処理
この処理が、本プログラムの一番のキモです。 まず、タイマ1比較Aによる割り込みをするには、ISR( SIG_OUTPUT_COMPARE1A )という関数を宣言してやれば良いようです。関数の中身ですが、大まかには以下のようにしました。
if( 制御フェイズが0? ){
if( 制御サイクルは0? ){
サイクル0割り込み(比較一致によって信号LOW)
サーボ制御値を自関数内に取り込む。
次のONするタイミングを比較レジスタへセット。
比較一致動作をHIGH出力に変更。
}
if( 制御サイクルは1? ){
サイクル1割り込み(比較A一致によって信号HIGH)
比較一致Aレジスタに500us手前までの時間を設定する。
}
if( 制御サイクルは2? ){
サイクル2割り込み(比較A一致によって500us前)
LOWにするタイミングをセットし、比較一致によってLOW出力に設定する。
}
}
else{
制御信号を発生していないフェイズでは単に2500us間隔で割り込みを
発生させる。
}
制御フェイズというは、信号を出す2.5ms区間とそうでない区間をコントロールします。PWM制御そのものは2.5ms単位になりますが、全体で「20msに一度」という制御をしなくていけません。そのため、「8回に1度PWM処理をする」という目的で使っています。
また制御サイクルというのは、先に説明した、「割り込み3回」を制御するものです。
詳しくはソースコードを見ていただければわかるかと思いますが、先に、このような構造を理解しておくと、よりわかりやすいかと思います。
というわけで、プログラムは下記のリンクよりダウンロードしてください。
実験風景
こんな感じです。ここでも汎用I/Oテストボード活躍中。電源供給端子とサーボ用端子を増設しました。
画像クリックで動画再生します。WMVファイル208kByte
なんか、動画にしたらカクカクしてますけど、本物はスムーズです。
アップしたプログラムは、上記の動画を撮ったときのもので、PWMは1000us~2000usで変化させています。600us~2400usは、GWSのサーボに変えてテストしてみましたが、結果は良好っぽいです。
※ 「っぽい」とは…こういうのはやっぱ、いろいろやってみないと、本当にうまくいっているかどうかがわからないものですので…。
BTC068は…相変わらずコネクタ直付けです。ジャンキーでかっこいい!(流行らないかな…流行らないでしょうね…)。
2006/09/22 00:04追記:わーい、ONO-ONEだ!
Your Message