PICでもっと遊ぶその2「高精度割り込みとAD変換でサーボを動かす」夏でも楽しい工作教室(2/2 ページ)

» 2005年07月15日 12時54分 公開
[小林哲雄,ITmedia]
前のページへ 1|2       

アナログ入力で(やっと)サーボを動かす

 これで8/16ビットタイマーと割り込みの使い方はマスターしたが、実際に動作するサーボを目にできないのではつまらない。もちろんシミュレータ上でレジスタを書き換えればパルス幅が変わることを確認できるが、サーボが動くさまをみることができない。ボタンスイッチでパラメータを移動することもできるが、今ひとつ実感がわきそうもないので、アナログ入力を使うことにしよう。

 PIC12F675には4つの10ビットアナログ入力が用意されている。ここでは入力装置として普通のボリュームを使う。

 ボリュームは回転角と抵抗値の変化の度合いが複数規定されているが、ここではBカーブと呼ばれる「回転角と抵抗値が比例関係」のものを使う。両端にGNDと5ボルトを接続し、中間の煽動子をPICのアナログ入力に接続すれば回転角に応じたGNDから5ボルトの連続信号が得られるはずだ。PICのアナログ入力インピーダンスは10Kオームとなっているので、これが無視できる500オームのボリュームを千石電商で購入した(ツマミつきで100円)。

買ってきた抵抗。ブレッドボードに差すために抵抗の足を半田付けしてある

 次はAD変換の使い方を確認しよう。(日本語ドキュメントのある)PIC12CE67XにもAD変換がついているのでこれを参照、と言いたいところだがこちらは8ビット入力。PIC12F675は10ビット入力なので仕様が異なる。

 AD変換は色々と設定項目が多い。まず、アナログ4入力と言っても内部切替式なので、入力を切り替える設定が必要だ。次に基準電圧を内部(Vcc)か外部(Vref)にするか設定する。また出力は10ビットでレジスタ2つに出力されるが、これを右詰めにするか左詰めにするか指定できる。

 これらはADCON0レジスタ($1F)で設定する。今回は8ビットで十分なので左詰めにして、上位のデータのみを読み出すことにする。また、I/Oピンをアナログ入力に設定するレジスタANSEL($9F)も設定が必要だ。ANSELレジスタはほかにAD変換の基準周波数の設定を行う。内部の4MHzクロックで動作させている場合8TOSCの設定にするのが適切だ。

 さらにAD変換は1命令で結果が出ない。まずは内部で基準電圧を作って比較する作業を入力ビットの数だけ繰り返す必要がある。そして測定データを入力する時間も必要だ。具体的にはANSELでアナログ入力を行うピンと測定用周波数設定を行い、ADCON0で桁詰め、基準電圧、入力ピンの選択とAD変換機能のONを行ってから一定時間待ち(約20マイクロ秒)、その後ADCON0の第1ビット(GO)を1にする。

 第1ビットが0になったらAD変換終了で、結果がADRESH($1E)とADRESL($9E)に入る。第1ビットが0になるまでプログラムで待たずに割り込みを使う方法もあるが、今回はプログラムでチェックを入れることにする。

 その辺を加味して作ったのが以下のルーチンだ。AD変換を開始したら終了までループで待っている。本当はエラー処理をしないといけないがいまのところ省略している。また、精密な測定をおこなうためにはノイズ源となるデジタル動作はジャマになる。AD変換を開始したらCPUを休ませる、ということもできるが、今回は8ビット精度で十分ということもあってそのままループ命令で終了チェックすることにした。

 これを2つの入力に対しておこなう。AD変換を頻繁に行っても意味がないのでサーボパルスを作ってからAD変換を行うことにした。データの入力から20ミリ秒遅れるが、気にしなくてよいだろう。

 ;
 ; RCサーボの制御テスト 16bit timer version
 ; AN0とAN1からデータを入力してその位置にサーボ移動
 ;
▼▼  LIST P=PIC12F675
▼▼  INCLUDE "P12F675.INC"
 __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_OFF &_MCLRE_OFF
 ;
 ;
 ;
▼▼ RC1POS EQU 20H
 RC2POSEQU 21H
 
▼▼ COUNT EQU 22H
▼▼ WBUF EQU 23H
 SBUFEQU24H
 
▼▼  ORG 0
▼▼  GOTO MAIN
 ORG4
 INTMAIN
▼▼  MOVWF WBUF ; レジスタ類退避
▼▼  SWAPF STATUS,W
▼▼  BCF STATUS,RP0
 MOVWFSBUF
 ;
▼▼  MOVLW 0EBH ; タイマー再セット
▼▼  MOVWF TMR1L
▼▼  MOVLW 0B1H
▼▼  MOVWF TMR1H
 BCFPIR1,TMR1IF
 ;
 RC1SET
▼▼  MOVF RC1POS,W ; サーボ1のデータを送る
▼▼  BTFSC STATUS,Z ; データが0なら送らない
▼▼  GOTO RC2SET ; 中心値128 1-128-255
▼▼  BSF GPIO,GPIO5
▼▼ ; MOVLW 0F6H ; 01:0991 80:1499 FF:2007 F6 N1 N1
▼▼ ; MOVLW 0D6H ; 01:0864 80:1499 FF:2134 D6 N1 N2
▼▼  MOVLW 0B6H ; 01:0737 80:1499 FF:2261 B6 N1 N3
 MOVWFCOUNT
 INTLP1
▼▼  NOP
▼▼  DECFSZ COUNT,F
▼▼  GOTO INTLP1
▼▼  MOVF RC1POS,W
 MOVWFCOUNT
 INTLP2
▼▼  NOP
▼▼  NOP
▼▼  NOP
▼▼  DECFSZ COUNT,F
▼▼  GOTO INTLP2
 BCFGPIO,GPIO5
 RC2SET
▼▼  MOVF RC2POS,W ; サーボ2のデータを送る
▼▼  BTFSC STATUS,Z ; データが0なら送らない
▼▼  GOTO RCSETE ; 中心値128 1-128-255
▼▼  BSF GPIO,GPIO4
▼▼ ; MOVLW 0F6H ; 01:0991 80:1499 FF:2007 F6 N1 N1
▼▼ ; MOVLW 0D6H ; 01:0864 80:1499 FF:2134 D6 N1 N2
▼▼  MOVLW 0B6H ; 01:0737 80:1499 FF:2261 B6 N1 N3
 MOVWFCOUNT
 INTLP3
▼▼  NOP
▼▼  DECFSZ COUNT,F
▼▼  GOTO INTLP3
▼▼  MOVF RC2POS,W
 MOVWFCOUNT
 INTLP4
▼▼  NOP
▼▼  NOP
▼▼  NOP
▼▼  DECFSZ COUNT,F
▼▼  GOTO INTLP4
 BCFGPIO,GPIO4
 RCSETE
 ;
 ; アナログ入力
▼▼ ; AN0 -> RC1POS
 ;AN1 -> RC2POS
 ; A/Dエラーの場合は前データを引き継ぎ
 ;
▼▼  MOVLW B'00000001' ; AN0設定
▼▼  MOVWF ADCON0
▼▼  MOVLW 6
 MOVWFCOUNT
 LPAN01
▼▼  DECFSZ COUNT,F
▼▼  GOTO LPAN01 ; セットタイム待ち
▼▼  BSF ADCON0,GO
▼▼  MOVLW 20H
 MOVWFCOUNT
 LPAN02
▼▼  BTFSS ADCON0,GO
▼▼  GOTO LPAN03
▼▼  DECFSZ COUNT,F
▼▼  GOTO LPAN02
▼▼  MOVF RC1POS,W
 GOTOLPAN04
 LPAN03
 MOVFADRESH,W
 LPAN04
 MOVWFRC1POS
 ;
▼▼  BSF ADCON0,CHS0 ; AN1設定
▼▼  MOVLW 6
 MOVWFCOUNT
 LPAN11
▼▼  DECFSZ COUNT,F
▼▼  GOTO LPAN11 ; セットタイム待ち
▼▼  BSF ADCON0,GO
▼▼  MOVLW 20H
 MOVWFCOUNT
 LPAN12
▼▼  BTFSS ADCON0,GO
▼▼  GOTO LPAN13
▼▼  DECFSZ COUNT,F
▼▼  GOTO LPAN12
▼▼  MOVF RC2POS,W
 GOTOLPAN14
 LPAN13
 MOVFADRESH,W
 LPAN14
 MOVWFRC2POS
 ;
 BCFADCON0,ADON
 ;
▼▼  SWAPF SBUF,W ; レジスタ類復帰
▼▼  MOVWF STATUS
▼▼  SWAPF WBUF,F
▼▼  SWAPF WBUF,W
▼▼  BSF INTCON,GIE ; 割り込み再許可
 RETFIE
 ;
 ;
 ;
 MAIN
▼▼  CLRWDT ; 割り込み関連初期化
 CALL3FFh; 内蔵オシレーター調整
 
▼▼  MOVWF OSCCAL
▼▼  BCF STATUS,RP0
▼▼  MOVLW B'00000001' ; TMR1 1:1
▼▼  MOVWF T1CON
▼▼  MOVLW B'11000000' ; GIE & PEIE
▼▼  MOVWF INTCON
▼▼  BSF STATUS,RP0
▼▼  MOVLW B'10000001' ; EEIE & TMR1IE
▼▼  MOVWF PIE1
▼▼  BCF STATUS,RP0
▼▼  MOVLW 0F0H ; タイマ初期化 20ms
▼▼  MOVWF TMR1L
▼▼  MOVLW 0B1H
 MOVWFTMR1H
 ;
▼▼  CLRF GPIO
▼▼  MOVLW 07h
▼▼  MOVWF CMCON
▼▼  BSF STATUS,RP0 ; Bank 1 へ切替
▼▼ ; CLRF TRISIO ; 非アナログ初期設定
▼▼ ; CLRF ANSEL
▼▼  MOVLW B'00001011' ; アナログ入力用初期設定
▼▼  MOVWF TRISIO
▼▼  MOVLW B'00010011'
▼▼  MOVWF ANSEL ; ポート0/1はanalog入力
▼▼  CLRF WPU
 BCFSTATUS,RP0 ; Bank 0 へ戻る
 ;
▼▼  MOVLW 080H ; フェイルセーフ
▼▼  MOVWF RC1POS
 MOVWFRC2POS
 MAIN01
 GOTOMAIN01
 
 END

 今回から割り込みルーチンとメインルーチンの順番を変えている。リセット時にはプログラムが0番地から実行され、割り込みは4番地から実行される。割り込みを使わないプログラムの場合は0番地からメインルーチンを書いていたが、割り込みを使う場合は4番地から割り込みルーチンを書き、メインルーチンをその後ろに書いたほうが分かりやすいだろう。

 シミュレーションではAD変換のところまでチェックしきれないので、適当なところで切り上げて実際に回路を組んでみることにした。今回もブレッドボードを使い、電源も外部の5ボルト電源だ。前回シリーズのLEDでは手持ちの電源を使ったと書いたが、秋月電子で小型のスイッチングレギュレーターとDCジャックが安く売っているので、これを使うのもよいだろう。

例によってブレッドボードで実験回路を組んでみる

 ボリュームを回すとサーボが動くだろうか? レスポンスがやや悪いのはサーボそのものの速度が遅い(ハイレスポンスのサーボは高い)のと、入力からサーボ出力まで時間差があるためだ(AD変換とサーボ出力のルーチンを逆にすれば解決する)。ちなみに、ブレッドボードで試しているとボリュームが抜けることがある。そうなると入力が不安定になり、サーボが勝手に動くことが分かる。

 これでサーボは動いたが、ボリュームを使うのはあくまでテスト用だ。本来の野望を実現するためにはシーケンス動作してくれないと困る。

前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

最新トピックスPR

過去記事カレンダー