C言語

温度センサから温度を取得する

前回、A/Dコンバータ機能のレジスタについて説明しました。
今回は、このA/Dコンバータ機能を使用して、温度センサからアナログ入力される温度データを温度に変換してグローバル変数に格納するまでを行います。
また、温度の取得は、タイマ機能を使用して、1秒毎に取得することを想定したプログラムを作成します。

前準備

IOポートの設定」と「スイッチのON/OFFによりLEDを点灯・消灯させる」で作成した「RL78G14_init.c」ファイルとプロジェクトファイルを使用します。
また、今回は、「インターバル・タイマを使ってLEDを点滅させる」で設定した内容でタイマ機能を使用しますので、こちらをベースにプログラムを追加、変更していきたいと思います。

A/Dコンバータの設定

「RL78G14_init.c」ファイルに、A/Dコンバータの初期化処理の関数を用意します。関数名は、戻り値も引数もない「static void RL78G14_init_AD( void )」です。
この関数に、「A/Dコンバータで使用するレジスタの説明」で説明したA/Dコンバータのレジスタを設定します。

最初は、「RL78G14_init.c」ファイルに、「static void RL78G14_init_AD( void ) ;」のプロトタイプ宣言を追加します。

#include "iodefine.h"

static void RL78G14_init_IO_Port( void );
static void RL78G14_init_Timer( void );
static void RL78G14_init_AD( void ) ;    /* ←ここに追加 */

次に、A/Dコンバータの各レジスタの設定値の定数定義を追加します。
void hdwinit( void )関数の上あたりに記述します。
そして、 hdwinit関数では、今回追加するRL78G14_init_AD関数の呼び出しを追加します。これで、main関数を実行する前に初期化が行われるようになります。
最後に、 static void RL78G14_init_AD( void )の関数定義を追加します。ここでは、定数定義の初期値をレジスタに設定する処理のみとなります。

/**********************/
/* A/Dコンバータ初期値 */
/**********************/
#define RL78G14_INIT_ADCEN      (1U)
#define RL78G14_INIT_ADM0       (0x00U)
#define RL78G14_INIT_ADM1       (0x20U)
#define RL78G14_INIT_ADM2       (0x00U)
#define RL78G14_INIT_ADS        (0x13U)
#define RL78G14_INIT_ADUL       (0xFFU)
#define RL78G14_INIT_ADLL       (0x00U)
#define RL78G14_INIT_ADTES      (0x00U)
#define RL78G14_INIT_ADPC       (0x08U)
#define RL78G14_INIT_ADCE_START (1U)

void hdwinit( void )
{
    PIOR0 = RL78G14_INIT_PIOR0;
    PIOR1 = RL78G14_INIT_PIOR1;
    RL78G14_init_IO_Port();
    RL78G14_init_Timer();
    RL78G14_init_AD();          /* ←追加 */
}

static void RL78G14_init_IO_Port( void )    /* ←既存コード */
{
省略
}

static void RL78G14_init_Timer( void )    /* ←既存コード */
{
省略
}

static void RL78G14_init_AD( void )      /* ←今回追加関数 */
{
    ADCEN = RL78G14_INIT_ADCEN;
    ADM0 = RL78G14_INIT_ADM0;
    ADM1 = RL78G14_INIT_ADM1;
    ADM2 = RL78G14_INIT_ADM2;
    ADS = RL78G14_INIT_ADS;
    ADUL = RL78G14_INIT_ADUL;
    ADLL = RL78G14_INIT_ADLL;
    ADTES = RL78G14_INIT_ADTES;
    ADPC = RL78G14_INIT_ADPC;
    ADCE = RL78G14_INIT_ADCE_START;
}

ADCEレジスタを 1 にセットした後、ADCSを1にするまでに1μ秒以上必要なので、ADCEを1にセットした後は、待ち時間を入れるほうがよいと思いますが、今回は割愛しています。
理由は、ADCEに 1 をセットした後、ADCSに 1 をセットするまでに、1秒タイマ待ちがあるため、ここで待たせる必要がないためです。

A/Dコンバータの初期値の説明をします。

ADCENは、PER0レジスタのビット5に該当するレジスタです。A/Dコンバータの入力クロックを供給する設定にします。これで、A/Dコンバータで使用するレジスタへのリード/ライトが可能になります。
この後、各A/Dコンバータのレジスタの設定値について説明します。

A/Dコンバータ・モード・レジスタ0(ADM0)

ADM0のビット7(ADCSレジスタ)のA/D変換動作制御は、0 の変換動作停止にしておきます。これは、A/D変換を開始する直前で使用するため、初期化時は、停止状態としました。
ADM0のビット6(ADMDレジスタ)のA/D変換チャネル選択モード設定は、0 のセレクト・モードを設定します。今回、アナログ入力(ANI19)を1つ選択してA/D変換するのみのため、セレクト・モードとします。
ADM0のビット0(ADCEレジスタ)のA/D電圧コンパレータの動作制御ですが、0 の動作停止にしておきます。これは、A/Dコンバータ機能のすべての設定が完了した後に、動作開始とするため、この時点では、0としておきます。
これにより、ADM0の設定は、0x00が初期値となります。

A/Dコンバータ・モード・レジスタ1(ADM1)

ADM1のビット6(ADTMD0レジスタ)、ビット7(ADTMD1レジスタ)のA/D変換トリガ・モードの選択は、ソフトウェアでA/D変換を開始するので、ソフトウェア・トリガ・モードを選択します。
ADM1のビット5(ADSCMレジスタ)のA/D変換動作モードの設定は、定周期に1回のみA/D変換を行うため、ワンショット変換モードを選択します。
ADM1のビット1(ADTRS1レジスタ)とビット0(ADTRS0レジスタ)のハードウエア・トリガ信号の選択は、ソフトウェア・トリガ・モードのため、初期値のままとします。
これにより、ADM1の設定は、0x20が初期値となります。

A/Dコンバータ・モード・レジスタ2(ADM2)

ADM2のビット7(ADREFP1レジスタ)とビット6(ADREFP0レジスタ)のA/Dコンバータの + 側の基準電圧源の選択は、VDDから供給されるので、VDDを選択します。
ADM2のビット5(ADREFMレジスタ)のA/Dコンバータの - 側の基準電圧源の選択は、VSSから供給されるので、VSSを選択します。
ADM2のビット3(ADRCKレジスタ)の変換結果上限/下限値チェックは、今回、割り込みは使用しないので、初期値のままとします。
ADM2のビット2(AWCレジスタ)のSNOOZEモードの設定は、ハードウェア・トリガ信号も、SNOOZEモードも使用しないので、初期値のままとします。
ADM2のビット0(ADTYPレジスタ)のA/D変換分解能の選択は、精度の高い10ビットで行います。
これにより、ADM2の設定は、0x00が初期値となります。

アナログ入力チャネル指定レジスタ(ADS)

今回、温度センサは、ANI19に接続されているため、ANI19の設定にします。
これにより、ADSの設定は、0x13が初期値となります。

変換結果比較上限値設定レジスタ(ADUL)

特に上限チェックは行わないため、初期値のままとします。
これにより、ADULの設定は、0xFFのままとなります。

変換結果比較下限値設定レジスタ(ADLL)

こちらも特に下限チェックは行わないため、初期値のままとします。
これにより、ADLLの設定は、0x00のままとなります。

A/Dテスト・レジスタ(ADTES)

A/D変換は、アナログ入力チャネル指定で行います。
これにより、ADTESの設定は、0x00となります。

A/Dポート・コンフィギュレーション・レジスタ(ADPC)

A/D変換には、ANI19を使用するため、それ以外のANI0~ANI7は、すべてデジタル入出力でも問題ありませんが、この後学習する照度センサがANI6に接続されているため、こちらを考慮して設定しておいても問題ありません。今回は、照度センサを考慮した設定を行っています。
照度センサを使う予定がない場合は、0x01を設定します。
照度センサを使用する予定がある場合は、0x08を設定します。

A/Dコンバータの初期値については以上です。

初期化が一通り終わったら、最後、ADCEレジスタに 1 をセットしてA/D変換待機待ちとします。

次は、main.cにて、タイマを開始して、1秒毎にA/D変換を行うプログラムを作成します。

1秒毎にA/D変換を行い、温度センサから温度を取得するプログラムを作成

インターバル・タイマを使ってLEDを点滅させる」 で作成したmain.cファイルを使用します。
最初に、main関数ですが、タイマを開始するのみでよいため、変更ありません。
タイマのところで作成したmain.cファイルのTimerCtrl関数を作り直します。
main.cファイルのプログラムを次に示します。

#include "iodefine.h"

#pragma interrupt TimerCtrl(vect=INTTM00)

unsigned long work;  /* 温度(算出用) */
unsigned long temp;  /* 温度 */

void main(void);

void main(void)
{
    TMMK00 = 0;  /* INTTM00の割り込みを許可にする */
    TS0 = 0x0001; /* ユニット0のチャネル0のタイマを開始する */
    __EI();      /* RL78マイコンは割り込み禁止状態で開始されるので、ここで割り込みを許可にします */

    while( 1 )
    {
        /* 処理が終わってしまうため、無限ループにて割り込みを待っている状態にする */
    }
}

static void TimerCtrl(void)
{
    int i;

    ADCS = 1U;   /* A/D変換開始 */

    for(i = 0; i < 13; i++)
    {
        /* 変換起動時間待ち */
    }

    while(ADCS != 0)
    {
        /* A/D変換完了待ち */
    }

    work = (ADCR - 32) * 5000L >> 16;  /* 入力電圧を算出 */
    temp = 30000L - (work - 1300) * 10000 / 82; /* 入力電圧から温度を算出 */
}

5行目でグローバル変数定義しているwork変数は、A/D変換値から温度を求める過程で使用する変数です。ローカル変数でもよいのですが、どこでも値が参照できるので、グローバル変数にしました。
6行目のグローバル変数定義しているtemp変数は、温度が格納されます。温度は、小数点があるのですが、1000倍して、整数で格納するようにしています。不動点小数だと値がわかりにくいので、このようにしました。

main関数は、 「インターバル・タイマを使ってLEDを点滅させる」 から変更していませんが、TimerCtrl関数は中身は作り直しています。

TimerCtrl関数の始めにA/D変換を開始します。
その後、A/D変換クロックに対応した変換起動待ちが必要なので、for文にて、変換起動時間待ちを行います。
今回の変換クロックは、fCLK/64のため、63クロックの待ち時間が必要です。
今回の環境では、for文をアセンブラコードにしたときに、for文の開始で9クロックほどかかり、for文の実行中は5クロックほどかかるようなアセンブラコードになっていたため、12回のループにして、63クロック以上待つようにしました。特に、12回ループさせなければいけないわけではないです。11回ループさせれば大丈夫だとは思いますし、NOP命令を63回行ってもよいと思います。
63クロック以上の待ちが行えれば、for文でなくても、どんな処理をしても大丈夫です。

次に、while文では、ADCSが0になるのを待ちます。ADCSが0になるとA/D変換完了を示すことになるので、A/D変換完了待ちをします。

A/D変換完了したら、A/D変換値がADCRレジスタに格納されるので、その値を取り出します。

A/D変換値は、0~1023の範囲で電圧を表現しています。この値を電圧に変換します。
計算式は、マイコンのハードウェアから、38行目のようになります。ただし、少し変更しているところがあります。それは、V単位をmVに変更しているところが異なっています。
ADCRレジスタは、下位のビット0~ビット5までは0が入っていて、ビット6~ビット15にA/D変換結果が格納されています。このため、6ビット右シフトすることにより、本来のデータになります。
マイコンのハードウェアの計算式では、6ビット右シフトした値から-0.5をしていますが、シフトする前に減算をするため、6ビット左シフトされているADCRレジスタの値に桁を合わせるため、0.5を6ビット左シフトしています。これにより、-32をすることになります。それから、VDD端子電圧の5000mVを乗算します。ADCRレジスタの最大値は、65472で5000を乗算してもオーバーフローしないため、このまま乗算しました。その後、1024で除算するのと、6ビット右シフトしてADCRレジスタの本来の位置に戻すことを合わせて、16ビット右シフトしています。これで、入力電圧を求めることができました。

次に、温度センサICのデータシートから、30℃のときに、1.3Vとなっていて、温度感度が-8.2mV/℃であることから、求めた入力電圧(mV単位)では、何℃になるかが、39行目の式になります。
この39行目では、温度を1/1000℃の単位に変換して計算しています。

温度センサから温度を取得するプログラムについては、以上となります。

-C言語