はじめに
こんにちは、槇原です。前回はマウスの大会の話をしたのですが、その前はマイコンのペリフェラルの話をしていました。今回はこちらの続きでRX631でエンコーダを読むための説明をしていきます。
エンコーダを読むためのピンと位相計数モード
今回は直角位相出力形式のエンコーダのパルス数を読みます。この出力形式のエンコーダはA相B相という出力ポートがあります。回転方向によって下の図のようにA相B相のピンの挙動が変わるので、ピンの状態と立ち上がり立ち下がりを見ることで向きとパルス数を見ることができます。
マイコンのタイマはクロックによってカウンタをカウントアップ/ダウンさせるのが基本的な動作です。このクロックの代わりにエンコーダのA相B相の入力を使うことで、エンコーダの回転に応じてカウンタを変化させることができます。
RX631でエンコーダを読むためには、MTU1かMTU2の位相計数モードが必要です。ユーザーマニュアルの位相計数モードの説明によれば、A相B相のパターンと信号の立ち上がり/立ち下がりによってタイマのカウントのアップ/ダウンを行ってくれます。
入力端子となるMTCLKxのA相B相とMTUの対応関係は以下のようにすでに決まっています。
一方でどのピンをMTCLKxに割り当てるかはある程度自由度があります。マウスの左右のモータのために2つエンコーダを読む必要があるので、MTU1とMTU2それぞれでエンコーダを読みます。今回はPA4(MTCLKA), PA6(MTCLKB)のペアとPA1(MTCLKC), PA3(MTCLKD)のペアを使います。
エンコーダを読むためのレジスタの設定
ピンの機能の設定 (PAnPFS PSEL)
実際指定したピンをMTCLKxとして利用するためにはPAnPFSレジスタのPSELビットを以下の表に従って0b00010にする必要があります。PAnPFSは使うピンに合わせて適宜読み替えてください。
MPC.PWPR.BIT.B0WI=0; //プロテクト解除
MPC.PWPR.BIT.PFSWE=1;
MPC.PA1PFS.BIT.PSEL=2; //MTCLKC
MPC.PA3PFS.BIT.PSEL=2; //MTCLKD
MPC.PWPR.BYTE=0x80; //プロテクト
またこのレジスタを変更する前にプロテクト解除をして、PAnPFSレジスタの変更を許可する必要があります。
GPIOの設定 (PMR)
PWMの設定時と同様に、GPIOはデフォルトではIOポートとして利用する設定になっています。エンコーダなどの周辺機器として利用するためにはPMRレジスタの利用する端子のポートモードを1にする必要があります。今回のPA1の場合であれば
PORTA.PMR.BIT.B1=1;
とします。
MTUの位相計数モード (TMDR MD)
MTUのモードを位相計数モードにするためには、TMDRレジスタのMDビットを0b0100にする必要があります。
MTU2.TMDR.BIT.MD=4; //位相計数モード1
タイマスタート (TSTR CSTn)
タイマのカウンタ(TCNT)を0にリセットしてタイマーをスタートさせます。すると以降は外部入力に合わせてTCNTの値が変わります。
MTU2.TCNT=0;
MTU.TSTR.BIT.CST2 = 1; //タイマスタート
設定後はTCNTの値を読むことでパルス数を読むことができます。
パルス数読み取り用関数
ここでは制御割り込みごとに一度呼び出すUpdateEncorders()
関数を作成しました。TCNTレジスタは16ビットなので符号付short形にキャストして-32768から32768の値に変換します。回転方向を指定するdirR, dirLをかけてpulseR, pulseLに保存しておき後から必要に応じてパルス数を呼び出せるようにします。
なおここで読み取ったパルス数はエンコーダの仕様に書かれているパルス数の4逓倍になっています。今回利用しているエンコーダのパルス数が1回転あたり4096という仕様なので、回転角度に変換するときは1パルスあたり4096*4パルスだと考える必要があります。これはA相B相の立ち上がり立ち下がりの両方でカウンタを進めているためこのようになっています。
その後TCNTを0にリセットします。
int pulseR=0;
int pulseL=0;
int dirR=-1;
int dirL=1;
void UpdateEncorders(){
pulseR=dirR*(short)MTU1.TCNT;
pulseL=dirL*(short)MTU2.TCNT;
MTU1.TCNT=0;
MTU2.TCNT=0;
}
int GetPulseL(){
return pulseL;
}
int GetPulseR(){
return pulseR;
}
4逓倍で読み取る部分についてはこちらの記事が分かりやすいです。
https://www.sk-solution.co.jp/blog/c7
エンコーダ読み取り用のコード
エンコーダ読み取り用の初期化とパルス数の読み取り用のコード全体は以下の通りです。
コード内ではデフォルトで書き換えができないレジスタを書き換えるために、プロテクトを解除するためのコードが含まれています。
int pulseR=0;
int pulseL=0;
int dirR=-1;
int dirL=1;
void InitEncorderL(){
PORTA.PMR.BIT.B1=1; //Uses the pin as an I/O port for peripheral functions.
PORTA.PMR.BIT.B3=1; // Uses the pin as an I/O port for peripheral functions.
SYSTEM.PRCR.WORD = 0xA502;//プロテクト解除
MSTP(MTU) = 0; //MTUモジュールON
SYSTEM.PRCR.WORD = 0xA500;//プロテクト
MTU.TSTR.BIT.CST1 = 0; //タイマストップ
MPC.PWPR.BIT.B0WI=0; //プロテクト解除
MPC.PWPR.BIT.PFSWE=1;
MPC.PA1PFS.BIT.PSEL=2; //MTCLKC
MPC.PA3PFS.BIT.PSEL=2; //MTCLKD
MPC.PWPR.BYTE=0x80; //プロテクト
MTU2.TMDR.BIT.MD=4; //位相計数モード1
MTU2.TCNT=0;
MTU.TSTR.BIT.CST2 = 1; //タイマスタート
}
void InitEncorderR(){
PORTA.PMR.BIT.B4=1; //Uses the pin as an I/O port for peripheral functions.
PORTA.PMR.BIT.B6=1; // Uses the pin as an I/O port for peripheral functions.
SYSTEM.PRCR.WORD = 0xA502;//プロテクト解除
MSTP(MTU) = 0; //MTUモジュールON
SYSTEM.PRCR.WORD = 0xA500;//プロテクト
MTU.TSTR.BIT.CST1 = 0; //タイマストップ
MPC.PWPR.BIT.B0WI=0; //プロテクト解除
MPC.PWPR.BIT.PFSWE=1;
MPC.PA4PFS.BIT.PSEL=2; //MTCLKA
MPC.PA6PFS.BIT.PSEL=2; //MTCLKB
MPC.PWPR.BYTE=0x80; //プロテクト
MTU1.TMDR.BIT.MD=4; //位相計数モード1
MTU1.TCNT=0;
MTU.TSTR.BIT.CST1 = 1; //タイマスタート
}
void UpdateEncorders(){
pulseR=dirR*(short)MTU1.TCNT;
pulseL=dirL*(short)MTU2.TCNT;
MTU1.TCNT=0;
MTU2.TCNT=0;
}
int GetPulseL(){
return pulseL;
}
int GetPulseR(){
return pulseR;
}
次回は壁センサや電圧監視用のAD変換部分について説明します。