H8CPUのADC・ DACのサンプルプログラム

Copyright(C) 13May2002
coskx

はじめに

この文書はAKI-H8にて,ADC,DACのサンプルプログラムを提示するものである。

DAC
DAC(DAコンバータ,ディジタルアナログ変換)とは,コンピュータの取り扱うことのできる数値を,アナログ量すなわち 電圧に変換する機能をもったデバイスである。より大きな数値を与えるとより高い電圧が出力されるようになっており,与える数値と出力される電 圧は比例関係になる。マイコンの場合は出力電圧は0Vから5Vである場合が多く,0を与えると0Vが出力され,1023を与えると5Vが出力 され,512を与えると2.5Vが出力される。
DACの応用
 1秒間に8000回でDACで音響信号バイト列を出力し,アンプ・スピーカを接続すると,電話音質の音声データを再生す ることができる。

ADC
ADC(ADコンバータ,アナログディジタル変換)とは,アナログ量すなわち電圧を,コンピュータの取り扱うことのできる数値に変換する機能 をもったデバイスである。デジタル電圧計だと思えばよい。ただし,数値で表した時の単位はボルトではなくて,コンピュータに都合のよいように できている。入力電圧と変換結果の値は比例関係にあり,マイコンの場合は入力電圧は0Vから5Vである場合が多く,0Vを入力すると0 に,5Vを入力すると1023に,2.5Vを入力すると512になる。
ADCの応用
 回転式の可変抵抗やポテンショメータと呼ばれる精密可変抵抗は,軸の回転角を電圧に変換できる。これの出力をADCで捉 えると,角度センサが作れる。その他,温度センサや湿度センサ,光度センサ,圧力センサなどは電圧出力のものが多いのでADCを用いるとマイ コンがさまざまな物理量を知ることができる。

【1】 AKI-H8のDAコンバータ出力

H8CPUはDAコンバータ(CPU内のレジスタの値を,値に比例した電圧に変換して出力する機能,Digital Analogue Converter)を2チャンネル持っている。 DAコンバータの分解能は8ビットなので,この比例関係は理論的には表1.1のようになる。H8CPUでは,DAC0チャンネル出力は CN2-18ピンに出力される。図1.1はDACチャンネル0を引き出している回路例である。
プログラムでは,RS232Cに接続されたパソコンのターミナルソフト(例えばハイパーターミナル)を用い,キーボードからDAコンバータへ の出力値を設定するものとし,設定値は0から255までの値とする。

表1.1 8ビットDAコンバータの入力値と出力電圧の関係

入力値

出力電圧

0

0.00V

64

1.25V

128

2.50V

192

3.75V

255

4.98V


H8_DAC.GIF - 1,581BYTES

図1.1 DAコンバータチャンネル0の出力回路例

DACへの出力

/**********************************************************
DACへの出力 
**********************************************************/
#include <3048fone.h>
#include "h8_3048fone.h"

/* DACは2チャンネル存在する*/
void initDAC()
{
    DA.DACR.BYTE |= 0xc0;
}

/* -------------------------------------------------
DA CONVERT
data    出力電圧
  0  →   0V
255  →   5V
------------------------------------------------- */
void outputDAC(unsigned char ch, unsigned char data)
{
    if(ch==0)
        DA.DADR0 = data;
    else if(ch==1)
        DA.DADR1 = data;
}

main()
{
    int x;
    initSCI1();
    initDAC();
    while(1) {
        x=
SCI1_getInt("DA value(0..255) =");
        outputDAC(0,x&0xff);
    }
}

/*
実行時の測定結果
入力値 出力値
   0     0.08V
  64     1.27V
 128     2.53V
 192     3.78V
 255     5.02V
*/

課題
実際にこのプログラムを動作させて,出力ピン(CN2-18)の電圧を測定して確かめなさい。


 

【2】 AKI-H8のADコンバータ入力(単一モード)

H8CPUはADコンバータ(入力された電圧を,その電圧に比例した値としてCPU内のレジスタに取り込む機能,Analogue Digital Converter)を8チャンネル持ってい る。ADコンバータの分解能は10ビットなので,この比例関係は理論的には表2.1のようになる。図2.1はH8CPUのAD0チャンネ ルのピンはCN2-12であることを示している。

H8_ADCDAC.GIF - 1,867BYTES

図2.1 DAコンバータチャンネル0の出力

表2.1 10ビットADコンバータの入力電圧と出力値の関係

入力電圧

出力値

0.00V

0

1.25V

256

2.50V

512

3.75V

768

4.99V

1023

次のプログラムはCN2-12に電圧を与えて,ADCの結果を表示するプログラムである。

ADCの入力のテスト

/**********************************************************
ADCの入力のテスト
**********************************************************/
#include <3048fone.h>
#include "h8_3048fone.h"

/* ------------------------------------------------- */
/* AD CONVERT */
/* ------------------------------------------------- */
unsigned int inputADC(unsigned char ch)
{
    AD.ADCSR.BYTE = ch;     /* AD設定単一モード、AN(ch)のみ使用 chの値は0,1,2,3のみ*/
    AD.ADCSR.BIT.ADST = 1;  /* start */
    while(AD.ADCSR.BIT.ADF == 0); /* AD変換終了待機 */
    AD.ADCSR.BIT.ADF = 0;
    return (*( (volatile unsigned int *) (&AD.ADDRA+(ch<<1)) ))>>6;
}

main()
{
    unsigned int y;
    initSCI1();
    while(1) {
        y=inputADC(0);
        SCI1_printf("%5d\r",y);
    }
}

課題
実際にこのプログラムを動作させて,入力ピン(CN2-12)に電圧を与えて読み取りなさい。
注意 ADCは破壊しやすい。 絶対に5Vを超えた電圧は与えない
こと。最初は2.5Vから始 めるとよい。


図2.2はテストのためにADCチャンネル0を引き出して,再びDACチャンネル0に戻している回路例である。
プログラムでは,RS232Cに接続されたパソコンのターミナルソフト(例えばハイパーターミナル)を用い,キーボードからDAコンバー タへの出力値を設定するものとし,設定値は0から255までの値とする。DAコンバータチャンネル0から出力された電圧は外部で直結され たADコンバータチャンネル0へ再入力され,得られたAD変換値をパソコンのターミナルソフト上に表示する。
このプログラムで使用している関数inputADC()はADコンバータのチャンネル0から3のみを扱うものである。


H8_ADCDAC.GIF - 1,867BYTES

図2.2 DAコンバータチャンネル0の出力をADコンバータチャンネル0に直結した 回路例
緑色の結線を取り除けば独立したADコンバータ,DAコンバータとして使用可能

DACからの出力をADCの入力へつなげてのテスト

/**********************************************************
DACからの出力をADCの入力へつなげてのテスト
**********************************************************/
#include <3048fone.h>
#include "h8_3048fone.h"

/* ------------------------------------------------- */
/* AD CONVERT */
/* ------------------------------------------------- */
unsigned int inputADC(unsigned char ch)
{
    AD.ADCSR.BYTE = ch;     /* AD設定単一モード、AN(ch)のみ使用 chの値は0,1,2,3のみ*/
    AD.ADCSR.BIT.ADST = 1;  /* start */
    while(AD.ADCSR.BIT.ADF == 0); /* AD変換終了待機 */
    AD.ADCSR.BIT.ADF = 0;
    return (*( (volatile unsigned int *) (&AD.ADDRA+(ch<<1)) ))>>6;
}

void initDAC()
{
    DA.DACR.BYTE |= 0xc0;
}

void outputDAC(unsigned char ch, unsigned char data)
{
    if(ch==0)
        DA.DADR0 = data;
    else if(ch==1)
        DA.DADR1 = data;
}

main()
{
    int x;
    unsigned int y;
    initSCI1();
    initDAC();
    while(1) {
        x=SCI1_getInt("DA value(0..255) =");
        outputDAC(0,x&0xff);
        y=inputADC(0);
        SCI1_printf("%d\n",y);
    }
}

/*
実行結果
入力値                  出力値
   0     0.08V  →         4
  64     1.27V  →       256
 128     2.53V  →       508
 192     3.78V  →       765
 255     5.02V  →      1017
*/

課題
実際にこのプログラムを動作させて,確かめなさい。

 


【3】 AKI-H8のADコンバータ入力(スキャンモード

H8-CPUは全部で8チャンネルのADコンバータ(Analogue Digital Converter)があるが,そのうち4個を 利用し,タイマー割り込み(一定時間ごとの割り込み)を利用し,4つの時系列データを取り込むプログラム例の一部を提示する。
4つの時系列データは
unsigned char ad_result0[SIZE];
unsigned char ad_result1[SIZE];
unsigned char ad_result2[SIZE];
unsigned char ad_result3[SIZE];
に保存されることとし,変数counterは0からSIZE-1の範囲になるようにうまく制御されているものとする。

タイマー割り込みを利用した4つの時系列データの取込

#include <3048fone.h>
#include "h8_3048fone.h"
#define clearTimer1Flag() (ITU1.TSR.BIT.IMFA=0)

#define SIZE 256

unsigned char ad_result0[SIZE];
unsigned char ad_result1[SIZE];
unsigned char ad_result2[SIZE];
unsigned char ad_result3[SIZE];

/* ADC INITIALIZATION  */
void initADC_L4()
{
    AD.ADCSR.BIT.ADF=0;   /*エンドフラグをクリア*/
    AD.ADCSR.BIT.ADIE=0;  /*インタラプト禁止*/
    AD.ADCSR.BIT.ADST=0;  /*スタート停止*/
    AD.ADCSR.BIT.SCAN=1;  /*スキャンモード*/
    AD.ADCSR.BIT.CKS=1;   /*変換時間=134ステート*/
    AD.ADCSR.BIT.CH=3;    /*AN0〜AN3(スキャンモード)*/
}

/*   GET ADC RESULT    */
void getADC_L4(unsigned char adc[]) /*ad*/
{
    AD.ADCSR.BIT.ADST = 1;         /* AD設定SCANモード 4チャンネル同時使用 ADスタート */
    while(AD.ADCSR.BIT.ADF == 0);  /*変換終了まで待つ*/
    AD.ADCSR.BYTE &= 0x5f ;        /*ADFとADSTクリア*/
    adc[0]=(AD.ADDRA>>8);   /*AD.DRAは unsigned int */
    adc[1]=(AD.ADDRB>>8);
    adc[2]=(AD.ADDRC>>8);
    adc[3]=(AD.ADDRD>>8);
}

volatile int counter=SIZE;

/*      割り込み関数   */
#pragma asm
    .SECTION    MYVEC, DATA, LOCATE=H'000070
    .ORG        H'000070  ;IMIA1
    .DATA.L     _TimerIntFunc
    .SECTION    P,CODE,ALIGN=2 ;これを忘れてはいけない
#pragma endasm

#pragma interrupt (TimerIntFunc)
void TimerIntFunc() /*タイマ割り込みルーチン*/
{
    static unsigned char adc[4];

    clearTimer1Flag();  /*タイマステータスフラグのクリア 忘れないこと*/
   if (counter<=SIZE) {
        getADC_L4(adc);
        ad_result0[counter]=adc[0];
        ad_result1[counter]=adc[1];
        ad_result2[counter]=adc[2];
        ad_result3[counter]=adc[3];
        counter++;
    }
}

main()
{
    /*関連部分のみ抜粋*/

    initADC_L4();
    initTimer01Int(500); /*時間割り込み500msec ch0,ch1使用*/
    E_INT();        /*CPU割り込み許可*/
    startTimer01();  /*時間割り込みタイマスタートch0,ch1*/
    while (1) {

        /*ここで何かの作業*/

        counter=0; /*counterに0を代入することでADC変換要求*/
        while (counter<SIZE); /*counter=SIZEになることでSIZE個のデータ取得完了*/

        /*ここで何かの作業*/

    }

}