【PICマイコン入門6】AD変換を使ったRCサーボ制御 | アナデジ太郎の回路設計

【PICマイコン入門6】AD変換を使ったRCサーボ制御

RCサーボ ソフト設計

この記事でわかること

・PICマイコンのAD変換入力の使い方
・タイマ割込みを使った時間制御
・RCサーボの制御プログラム

RC(Radio Control)サーボは、マイクロサーボとも呼ばれ、
入力するパルス幅に応じた角度に回転するモータで、
ラジコンなどの制御用に使用されます。

本記事では、PICマイコンのAD変換入力とタイマ割込みを使用し、
可変抵抗器のツマミの角度に応じて、RCサーボの回転位置制御を行う
プログラムの設計方法について解説します。

本記事で使用する新居浜高専PICマイコン学習キットについては下記記事で解説しています。

キットの回路図やプログラムはキットを販売している秋月電子のHPからダウンロードできます。
秋月電子 新居浜高専PICマイコン学習キットVer.3 ACアダプタ付

また、参考書も販売されています。

※本記事はPICマイコン学習方法の一例を紹介するものであり、
 ここで紹介するキットやソフトの動作を保証するものではありません。
 キット等の購入については自己責任でお願いします。
 (不明点等の質問にはお答えできません)

<本ソフトの利用環境と設定について>
本記事におけるMPLAB(プログラム開発ソフト)の開発環境は以下の通りです。
 ・MPLAB X IDE v.15
 ・XC8 v2.46
 ・Device Family Pack PIC16F1xxxx_DFP(1.24.387)

※ダウンロードしたプロジェクトファイル(NNCTkit_v3.X)は、
 そのままビルドするとエラーになるため、以下の変更を実施しました。

・helpstr.h 9行目
 変更前:const __section(“title”) unsigned char title[224]={
 変更後:const __section(“help_title“) unsigned char help_title[224]={

セクション名が「title」だとエラーになるので、別の名前にします。
ここでは「help_title」にしましたが、何でも良いです。

この時、配列名は「title」のままでも問題ありませんが、
他のデータ同様、配列名をセクション名と同じにする場合は、
この配列を使用しているソースファイルの方も直します。

・monitor.c 2093行目
 変更前:TX1REG = title[i];
 変更後:TX1REG = help_title[i];

MPLABの使い方については下記で解説しています。

RCサーボ回路

キットの回路は下図のような構成となっています。

RCサーボ回路

PICマイコンのRA0ピンをアナログ入力に設定し、
可変抵抗VR1により、入力電圧を0~5Vまで変化させます。

RC0ピンをデジタル出力に設定し、PWM信号をRCサーボに入力します。

RCサーボと学習キットの接続

本記事で使用するRCサーボはTOWER PRO(タワープロ)製のSG90で、
入力するPWM信号のパルス幅に応じて、約 180 度回転します。

SG90仕様



PICマイコンの初期設定

プログラムでは、PICマイコンの初期設定として、
アナログ値である入力電圧をデジタル値に変換するAD変換機能の各種設定や、
PWM周期を制御するため、タイマー機能を使った割込み処理の定義を行います。

プログラムコードの詳細は、ソースファイル(nnct_kit_v3.c)を参照下さい。

コンフィグレーション設定(※1)は以下の通りです。
 ※1:クロックなどの動作環境設定

#pragma config FEXTOSC = HS
 外部発振器モード選択:HS(水晶振動子 4MHz以上)

#pragma config RSTOSC = EXT4X
 発振器の動作モード:PLL(※2)の4逓倍回路を使用
 ※2:Phase Locked Loop(位相同期ループ):クロック周波数を増加させる回路

PIC16F18857ではPLLにより、外部からのクロック信号の周波数を4倍に増やすことができ、
本キットでは、8MHzの水晶振動子から32MHzのシステムクロック周波数Foscを生成してます。

コンフィグレーション設定については、下記記事で解説しています。

AD変換機能

初期設定関数SetConfigで、以下のレジスタの設定を行います。

初期設定関数コード(AD変換部分)

ANSELA(ポートAアナログ選択)レジスタ
 ポートA(RA0~RA7)をアナログ入力にするか指定します。
 レジスタ値0x03(0000 0011)により、RA0,RA1をアナログ入力に設定します。
 (RCサーボプログラムではRA1は未使用)

ANSELAレジスタ

ADCON0(ADC制御0)レジスタ
 このレジスタの各ビットには、
 AD変換の各種設定が割付けられています。 

ADCON0レジスタ

  ADON(ADC有効化)ビット=1(ADC有効)
  ADCS(ADCクロック選択)ビット=0(ADCLKを使用)
  ADFRM0(ADC結果形式)ビット=1(右寄せモード(※3)

3:AD変換値は10bitデータ(0~1023)ですが、
  これを上下各8bitのAD変換結果レジスタ(ADRESH、ADRESL)
  にセットするときのモードを指定します。

AD変換結果のセット方法

  ADFRM0 = 1の場合、右寄せモードとなり、
  ADRESHは、10bit変換結果の上位2bit、ADRESLは下位8ビットを格納します。

ADCLK(ADCクロック選択)レジスタ
  AD変換を行うクロックの設定を行います。

ADCLKレジスタ

  本プログラムでは最も低速となるシステム周波数Foscの1/128にしています。
   0x3F(63)=Fosc/128=32MHz/128 =250kHz
  
  この設定だと、AD変換1 ビットあたりの処理時間TADは、
   TAD=1/250kHz=4us
   10bitデータの変換に要する時間はデータシートより11.5×TADとあるので、
   4us×11.5=46usとなります。

ADREF(ADCリファレンス選択)レジスタ
 このレジスタの各ビット(ADPREF、ADNREF)で、
 AD変換の基準電圧を入力するピンを指定します。 

ADREFレジスタ

  ADPREF(VREF+入力ピン選択)ビット= 0x00(VDDピン)
  ADNREF(VREF-入力ピン選択)ビット= 0(VSSピン)

 
 基準電圧を電源ピンの5Vと、GNDピンにすることで、
 アナログ電圧0~5Vを10bitのデジタル値(0~1023)に変換します。

AD変換の関係図

ADPCH(ADC チャンネル選択)レジスタ
 AD変換入力ピンを指定します。
  0x00にすることで、RA0(ANA0)ピンとなります。



タイマ2割込み処理

タイマ2割込みを使うことで、タイマーや時計などの正確な時間処理を行っており、
RCサーボ制御プログラムでは、PWM周期の設定に利用されています。

タイマ2割込みは、タイマ2レジスタ(T2TMR)の値がカウントアップし、
T2PR(タイマ2周期レジスタ)の値に到達したらゼロに戻った時に発生します。

タイマ2の設定についても、初期設定関数SetConfigで行っています。

タイマ2のカウント速度を1MHz(1us)、T2PRを199にセットしているので、
199+1=200カウント目に割込みが発生し、割込み処理は1us×200=200us毎に行われます。

初期設定関数(タイマ2割込み)

タイマ2割込みで行う処理内容は割込み処理関数 isrで定義しています。

割込み関数

このisr関数では、タイマ1割込み処理も定義されており、
ブザー音の階調(周波数)制御に用いられています。

タイマ1の詳細については、下記記事で解説しています。

タイマ2割込み処理では、次の2つの変数を制御しています。

・タイマ2割込回数カウンタ(t2_icnt)
 割込み発生(200us)毎にカウントアップする

・1秒経過フラグ(sec_flag)
 t2_icntの値が設定した定数TIMECONSTを超えたら、1にセットする
 この時、t2_icntはゼロにクリアされる

TIMECONSTはソースファイル(nnct_kit_v3.c)の初めにある
define命令によって、固定値(4999)に定義されています。

 #define  TIMECONST  4999

これによって、200us×5000=1s経過後にsec_flagが1になることで、
1秒間の計測に利用されています。
(RCサーボ制御プログラムでは、本フラグは未使用)

この2つの変数はグローバル変数(※4)として定義されており、
RCサーボ制御以外の、他のプログラムでもこの変数を使用することで、
時間を計測しています。

※4:関数の外で宣言した変数で、同じソースファイル内の関数で共用できる。
   
グローバル変数については下記記事で解説してます。



RCサーボ制御プログラム

AD変換機能とタイマ2割込み処理を使用した
RCサーボ制御プログラム(RCservo)は以下となります。

RCサーボ制御コード

※5:wait関数はソースファイル内で定義された待機処理を行う関数で、
   約2us×(引数の値) だけ待機時間を作ります。

   詳細は下記記事で解説してます。

このプログラムでは、パルス幅が0.4ms~1.5msの変化になるので、
RCサーボ(SG90)の回転角がー90°~0°と半分程度しか動作できない為、
以下のコード変更を実施しました。

① while(t2_icnt < 100);
  PWM周期をSG90の仕様に合わせ、20msに変更(200us×100=20ms)

② wait(230);
  パルス幅の最小値を0.5msに変更(約2us×230≒0.5ms)

③ wait(a); の数を4個にする
  パルス幅の最大値を2.4ms確保できるようにするために、
  待機処理を行うwait関数を2個追加しました。
  
  この変更により、入力電圧が最大5V(a=255)時、 
  wait関数4個で、約2us×255×4≒2ms
  パルス幅は最大0.5+2ms=2.5msになります。



RCサーボ動作波形

ソフト変更前のPWM波形は以下になります。

動作波形

可変抵抗VR1を左側一杯に回した時、RA0の入力電圧が0Vになるので、
パルス幅は最小の0.4ms(RCサーボの角度ー90°)となり、
右側一杯に回して、入力電圧を5Vにした時、パルス幅は1.5ms(角度0°)になりました。

次に、ソフト変更により、PWM周期は15→20msとなりました。

周期波形

入力電圧を変化させた時のパルス幅は以下の結果となりました。

ソフト変更後の動作波形

入力電圧が4.7Vでパルス幅2.5msとなり、この時の角度が約90°です。

5Vまで上昇させると、パルス幅は2.65msまで増えますが、
角度は2.5ms時と同じままで、それ以上回転しません。

RCサーボの回転角度