そろそろAD変換に挑戦.
まあマイコンがやってくれるので簡単簡単.
サンプルにはRX220 CubeSuite+ 用ルネサススタータキットのサンプルコードを使いました.
環境
- マイコン:R5F52206BDFM(AKI-RX220ボード)
- 開発環境:e2studio
- 書き込みソフト:RenesasFlashProgrammer(RFP)
AD変換設定
ピンの調査,設定
AD変換を行えるピンを調べる.
表32.2 12ビットA/Dコンバータの機能概要を見るとアナログ入力チャネルはAN000~AN015であることがわかる.
機能別端子一覧(64ピンLQFP) をみると
46:PE5:IRQ5/AN013
47:PE4:AN012/CMPA2
48:PE3:AN011/CMPA1
49:PE2:IRQ7/AN010
50:PE1:AN009
51:PE0:AN008
53:P46:AN006
55:P44:AN004
56:P43:AN003
57:P42:AN002
58:P41:AN001
60:P40:AN000
であることがわかる.またAKI-RX220ボードではCH1-1~CH1-12まで並べて配置されているのでどれでも使える.
どれでもいいのでひとまずAN000でやってみる.
というわけで設定をする.サンプルコードを見るとポートモードレジスタを弄るだけでよいらしい.一応PDRも0にしておく(初期値で0なのでしなくてもいい)
注意点としては,32.7.12 12 ビット A/D コンバータ入力を使用する場合のポートの設定によると1pinでもAD変換をするのなら同じポートの出力を使わないようにとのこと.読むの辛い.
なのでPMR等はBYTEで指定した方が安全なようです,別にスイッチのインプットに割り当ててもいいんですけどね.
//Port設定
PORT4.PMR.BYTE = 0x01; //Port40を周辺機能とする
PORT4.PDR.BYTE = 0x00; //入力端子
AD変換初期化
当然最初にS12ADモジュールを有効化する.忘れたわけがない.その後
A/Dコントロールレジスタ(ADCSR)を設定するにあたり,まず3種類あるスキャンモードから選択しなくてはならない.
- シングルスキャン:
指定したチャネルを1度スキャンして終わる.具体的にはAD変換が終わると後に設定するADSTが0になる. - 連続スキャン:
シングルスキャンとほぼ同じで,能動的にADSTを0にするまでAD変換を続ける. - グループスキャン:
ADANSA/ADANSBで設定したチャネルを1つのトリガでシングルスキャンするモード
今回は連続スキャンにする.
続いてA/D変換のチャネルを選択するADANSAを設定する.ADANSBはグループスキャンの時のみ設定する.
その後AD変換のサンプリングレートを設定するためにADSSTR0を設定する.値の妥当性はやってみるしかない(はず)なのでサンプルのままにしておく.
最後にAD変換をスタートする.
//S12ADモジュールを有効化
SYSTEM.PRCR.WORD = 0x0A503; //クロックソース選択の保護解除
MSTP(S12AD) = 0; //S12ADを有効化
SYSTEM.PRCR.WORD = 0x0A500; //クロックソース選択の保護
//AD変換設定
S12AD.ADCSR.BIT.ADCS = 0x2; //連続スキャンモード
S12AD.ADANSA.WORD = 0x0001; //AN000を有効にする
S12AD.ADSSTR0 = 0xFF; //255ADCLKクロック(=10us,多分)
S12AD.ADCSR.BIT.ADST = 0x1; //AD変換スタート
AD変換値の取得,数字の送信
AD変換したはいいが値を取らねば意味がない.
A/Dデータレジスタy(ADDRy)を参照すると,初期状態では右詰めで12bit分変換値が中に入っている.
ということで1行で終わる.
int adcVal = S12AD.ADDR0;
ついでに数字の送信もやる.行ったのはintからcharに変換するところだけ.
ASCII文字コード的に48(0x30)足すと数字がcharに変換できるので変換をし,そのまま送ると逆順に出てきて焦るので戻しておく.もうちょっと楽に書けるのだが,面倒なのでいつかやる.
しかし64bit分確保してもマクロをかませていないので意味がないことに終わってから気が付いた.
/**
* int型をSCI1で送る関数
* @param msg_int
*/
static void put_int_SCI1 (int msg_int)
{
int cnt=0, revCnt=0;
char tmp[64];
char num[64];
//charからintに変換
do{
tmp[cnt++] = (unsigned char)(msg_int%10 + 0x30);
msg_int /=10; //次の桁に移動させる
}while(msg_int);
//逆に入っているので戻す
for(revCnt=0; revCnt < cnt; revCnt++){
num[revCnt] = tmp[cnt - revCnt - 1];
}
num[revCnt] = '\0'; //null文字を末尾に入れておく
//変換したcharを送信
text_write(num);
}
成果物
シリアル通信の初期化などは以前の記事を参照されたし.
void init_adc(){
//Port設定
PORT4.PMR.BYTE = 0x01; //Port40を周辺機能とする
PORT4.PDR.BYTE = 0x00; //入力端子
//S12ADモジュールを有効化
SYSTEM.PRCR.WORD = 0x0A503; //クロックソース選択の保護解除
MSTP(S12AD) = 0; //S12ADを有効化
SYSTEM.PRCR.WORD = 0x0A500; //クロックソース選択の保護
//AD変換設定
S12AD.ADCSR.BIT.ADCS = 0x2; //連続スキャンモード
S12AD.ADANSA.WORD = 0x0001; //AN000を有効にする
S12AD.ADSSTR0 = 0xFF; //255ADCLKクロック(=10us,多分)
S12AD.ADCSR.BIT.ADST = 0x1; //AD変換スタート
}
/**
* int型をSCI1で送る関数
* @param msg_int
*/
static void put_int_SCI1 (int msg_int)
{
int cnt=0, revCnt=0;
char tmp[64];
char num[64];
//charからintに変換
do{
tmp[cnt++] = (unsigned char)(msg_int%10 + 0x30);
msg_int /=10; //次の桁に移動させる
}while(msg_int);
//逆に入っているので戻す
for(revCnt=0; revCnt < cnt; revCnt++){
num[revCnt] = tmp[cnt - revCnt - 1];
}
num[revCnt] = '\0'; //null文字を末尾に入れておく
//変換したcharを送信
text_write(num);
}
void main(void)
{
PORT0.PDR.BIT.B3 = 1;
init_adc();
init_SCI1();
while(1){
PORT0.PODR.BIT.B3 = 1;
for(int k=0; k<100000;k++);
int adcVal = S12AD.ADDR0;
put_int_SCI1(adcVal);
text_write("\r\n");
PORT0.PODR.BIT.B3 = 0;
for(int k=0; k<100000;k++);
}
}