A/D変換プログラム

     T.単発モード
     U.繰り返し掃引モード


T.単発モード
 R8C/M12Aにはデータ有効長10ビットのAD変換が内蔵されています。使える端子は、P1_0、P1_1,P1_2、P1_3、P1_4、P1_7の6チャンネルあり、取り込みチャネルは3グループに分かれていますが、実際に変換結果が格納されるA/Dレジスタは2つしかありません。AD入力選択レジスタを使い、端子を切り替えて使う仕様になっています。それぞれの端子の呼び名は、AN0、AN1、AN2、AN3、AN4、AN7となっています。AD変換を使う際に関係するレジスタは次の6つです。

(1)ポート1機能マッピングレジスタ0、1(PML1、PMH1)
 A/D変換に使える端子は、p1_0、p1_1、p1_2、p1_3、p1_4、p1_7です。A/D変換として使える機能を与える設定レジスタがポート1機能マッピングレジスタ0、1です。A/D変換以外にも、RJ2端子やRB2端子などに設定する場合も必要になってくるレジスタです。

 1)ポート1機能マッピングレジスタ0(PML1)
ビット 設定値
   7  00:AN3 入力
   6
   5  00:AN2 入力
   4
   3  00:AN1 入力
   2
   1  00:AN0 入力
   0
    ポートp1_0をA/D変換入力端子AN0として使う場合は、
    p10sel0 = 0;
    p10sel1 = 0;

    または、pml1 = 0x00;

    ポートp1_1をA/D変換入力端子AN1として使う場合は、
    p11sel0 = 0;
    p11sel1 = 0;

    または、pml1 = 0x00;

    ポートp1_3をA/D変換入力端子AN3として使う場合は、
    p13sel0 = 0;
    p13sel1 = 0;

    または、pml1 = 0x00;


 2)ポート1機能マッピングレジスタ1(PMH1)
ビット 設定値
   7  00:AN7 入力
   6
   5
   4
   3
   2 PMH1Eの
p14esel2ビット0
 000:AN4 入力
   1
   0


    ポートp1_4をA/D変換入力端子AN7として使う場合は、
    p14sel0 = 0;
    p14sel1 = 0;
    p14sel2 = 0;

    または、pmh1 = 0x00;

    ポートp1_7をA/D変換入力端子AN4として使う場合は、
    p17sel0 = 0;
    p17sel1 = 0;

    または、pmh1 = 0x00;



(2) ADMOD(A/Dモードレジスタ)

ビット 設定値
   7 00:タイマRC、外部トリガによるAD変換禁止
01:設定禁止
10:タイマRCからの変換トリガによるAD変換開始
11:外部トリガによるAD変換開始
   0
   6    0
   5    0
   4          00:単発モード
AD動作モード  01:繰り返しモード
選択ビット    10:単掃引モード
         11:繰り返し単掃引モード
   0
   3    1
   2          000:f8(2.5MHz)
          001:f4(5MHz)
AD変換クロック 010:f2(10MHz)
選択ビット     011:f1(20MHz)
         100:fAD(20MHz)
   0
   1    1
   0    1

 単発モードとは、1つのチャネル分のA/D変換を1回実行する方法です。今回は、この単発モード、f1(20MHz)で行っています。

      admod = 0x03;

(3) ADINSEL(A/D入力選択レジスタ)
  単発モード、繰り返しモードの時には下の設定になります。
ビット AN7 AN4 AN3 AN2 AN1 AN0
   7    1    1    0    0    0    0
   6    0    0    1    1    0    0
   5    0    0    0    0    0    0
   4    0    0    0    0    0    0
   3    0    0    0    0    0    0
   2    0    0    0    0    0    0
   1    0    0    0    0    0    0
   0    1    0    1    0    1    0
      掃引モードの時には

  ADINSEL:0x00 ・・・ AN0,AN1が掃引モードで交互に入力端子になる
        :0x40 ・・・ AN2,AN3        〃
        :0x80 ・・・ AN4,AN7       
 〃

 今回は、単発モードで、AN7端子を使うので
    adinsel = 0x81;


(4)ADCON0(A/D制御レジスタ)

 AD変換を開始と停止を制御します。

    adcon0=0x01; ・・・ AD変換開始
    adcon0=0x00; ・・・ AD変換停止

 ADCON0のADSTビット(A/D変換開始ビット)は、単発モード、単掃引モードのとき、A/D変換終了で0になります。A/D変換終了の判定に使います。

(5)A/Dレジスタ(AD0、AD1)
 ADi(i=0,1)レジスタは、A/D変換された値が保存される16ビットの専用レジスタです。ADiL下位8ビット、ADiH上位8ビットに分かれますが、値が入力されるのは、ADiレジスタの下から10ビットまでです。
 
 A/D入力選択レジスタ(ADINSEL)のb7とb6でチャネルグループを選択しています。AD0レジスタにはAN0、AN2、AN4が、AD1レジスタにはAN1、AN3、AN7の値が保存されます。掃引モードのときには、同じチャネルグループに属する2つの端子で交互に掃引入力する。
チャネルグループ0 チャネルグループ1 チャネルグループ2
  AD0レジスタ      AN0      AN2      AN4
  AD1レジスタ      AN1      AN3      AN7



(6)ADISCR(A/D割り込み制御ステータスレジスタ)

 割り込みを使ってA/D変換をするとき使うレジスタです。割り込みでA/D変換を使うときには、割り込み優先レベルレジスタ ILVL7を設定する必要があります。

ビット 設定値
  7    ADF AD変換割り込み要求ビット
   0:割り込み要求なし
   1:割り込み要求あり
  
  6    ADIE A/D変換割り込み許可ビット
   0:割り込み禁止
   1:割り込み許可
  5    0
  4    0
  3    0
  2    0
  1    0
  0    0

 ADICSRのADFビット(A/D変換割り込み要求ビット)は、単発モード、単掃引モードでA/D変換が終了したとき、繰り返しモード、繰り返し掃引モードで、選択されたすべてのチャネルのA/D変換が終了したとき1になります。





(7)モジュールスタンバイ制御レジスタ(MSTCR)

 項目3(タイマRB2)でも述べていますが、A/D変換機能を有効にするためには、モジュールスタンバイ制御レジスタの関係するビットをあらかじめアクテイィブにしておかないと使用できません。

    mstad = 0;
    (または、mstcr = 0x00; でも良い)
    

(8)AD変換プログラムの作成
 可変抵抗器による電圧の変化をA/D変換し、0〜255の値でLCDに表示します。入力端子をAN7、単発モードで行っています。メインファイル AD_LCD.cとlcd_ctrl.hを入力します。lcd_ctrl.cは前回と同じものをコピーして同じフォルダに保存しておきます。
1)メインプログラム AD_LCD.c

  #include "sfr_r8m12a.h"
  #include "lcd_ctrl.h"

  void main(void)
  {
    unsigned int ad;
    unsigned int i;
    unsigned char rd[3];
    unsigned char str1[16];
    unsigned char str2[16];
    unsigned char d;
    int ret;
    init();
    lcd_init();
    lcd_clear();
    for(i=0;i<16;i++){
      str1[i]=' ';
      str2[i]=' ';
    }
    while(1){
      ad=Get_AD();
      ad=ad>>2;
      for(i=0;i<3;i++){ // 0〜255を各桁に分解する
        rd[i] = ad%10;
        ad = ad/10;
      }
      str1[0]='A';
      str1[1]='D';
      str1[2]='ヘ';
      str1[3]='ン';
      str1[4]='カ';
      str1[5]='ン';
      str1[6]='チ';
      str1[7]='=';
      str1[8]=' ';
      str1[9]=rd[2]+0x30;  // ASCIIコードに変換
      str1[10]=rd[1]+0x30;
      str1[11]=rd[0]+0x30;
      lcd_str(str1,1);
      lcd_str(str2,2);
      wait_us(10000);
    }
  }

  /* I/O初期化関数 */
  void init(void)
  {
    int i;
    /**** 高速オンチップオシレータで動作する場合 ****/
    prc0=1;// プロテクトレジスタ解除
    hocoe=1;// 高速オンチップオシレータ発振開始
    for(i=0;i<50;i++);//発振安定まで待つ
    hscksel=1;// 高速オンチップオシレータ選択ビットを1にする
    scksel=1;// システム基準クロックを高速にする
    prc0=0;// プロテクトレジスタ禁止
    pd1=0x7f;// ポートディレクションレジスタ p0〜p6出力p7入力設定
    p1=0x00;
  }

  int Get_AD(void)
  {
    int i;
    pmh1&=0x3f;//ポート1機能マッピングレジスタ
    mstcr= 0x00;// モジュールスタンバイ制御レジスタをアクティブ
    admod= 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
    adinsel= 0x81;// A/D入力選択レジスタ AN7
    adcon0 = 0x01; // AD変換スタート
    while( adcon0 & 0x01);// A/D変換終了待ち 単発モードのときのみ
    i=ad1;
    return i;
  }


2)ヘッダーファイル lcd_ctrl.h
 先の「(4)LCDに文字を表示する」で作成したlcd_ctrl.hに、関数int Get_AD(void);を追加したものを作成保存します。

  void lcd_init(void); /* LCD初期化関数 */
  void lcd_clear(void); /* LCD画面クリアー */
  void lcd_cursor_off(void); /* LCDカーソルoff */
  void lcd_out(unsigned char); /* データ出力関数 */
  void lcd_data(unsigned char); /* 一文字出力関数 */
  void lcd_cmd(unsigned char cmd);/* コマンド出力関数 */
  void wait_us(unsigned long usec);/* us単位のウエイト関数 */
  void lcd_str(unsigned char *str,unsigned char); /* 文字列出力関数 */
  void init(void);
  int Get_AD(void);
  #define CLOCK 20000
  #define LCD p1 // LCDのデータポート
  /* LCDのレジスターセレクション */
  #define RS_High (p1_4 = 1)
  #define RS_Low (p1_4 = 0)
  /* LCDのディスプレーイネーブル */
  #define E_High (p1_5 = 1)
  #define E_Low (p1_5 = 0)

◎プログラム実行画面                     ◎回路図(基盤半田面)



プロジェクトファイルのダウンロード



U.繰り返し掃引モード

(1) 繰り返し掃引モード
 A/D変換(T)では、単発モードでA/D変換を行っていました。R8C/M12AのA/D変換には以下のモードがあります。

     単発モード      ・・・指定された1端子の値を1度だけA/D変換実行

     繰り返しモード    ・・・指定された1端子の値を繰り返しA/D変換し続けます  

     掃引モード      ・・・指定された複数端子の値を1度だけA/D変換実行

     繰り返し掃引モード ・・・指定された複数端子の値を繰り返しA/D変換し続けます


Renesas R8C/M12Aアプリケーションノートに繰り返し掃引モードによるA/D変換の例が載っています。 今回は、そのプログラムをそのまま借用してI2C接続LCDに表示するプログラムを作ってみました。A/D変換部分のプログラム説明は上記のドキュメントに詳しく記載されています。


(2) A/D変換プログラムの作成
 繰り返し掃引モードでは、同じチャネルグループ内の2つのチャネルで交互にA/D変換→変換待機を繰り返して行います。ここでは、チャネルグループ0内の2つのチャネルAN0とAN1を使います。AN0(p1_0)、AN1(p1_1)端子に可変抵抗器を繋いでいます。

     チャネルグループ0選択時の繰り返し掃引モードの動作例

チャネル0(AN0) 変換待機 A/D変換1 変換待機 A/D変換3 変換待機  ・・・・・
チャネル1(AN1) 変換待機 変換待機 A/D変換2 変換待機 A/D変換4  ・・・・・

(3)メインプログラム AD_SOUIN.c

  #include "sfr_r8m12a.h"
  #include "ctrl_souin.h"

  unsigned short ad_data[2] = {0,0};/* A/D conversion result */

  unsigned char ad;
  unsigned char rd0[3];
  unsigned char rd1[3];

  unsigned char i;

  void main(void)
  {
    unsigned char i; // Loop counter
    asm("FCLR I"); // Disable interrupt
    init();
    ad_init(); // Initialize A/D converter
    asm("FSET I"); // Enable interrupt

    adst = 1; // Start A/D conversion

    I2C_LCD_init();
    I2C_SDA_OUT; // SDAピン出力に設定

    while(1){
      /************* LCD 表示 ********************/
      ad=ad_data[0]>>2; // AN0
      if(ad ==0 ) p1_7=1;// AN0入力確認
      else p1_7=0;
      for(i=0;i<3;i++){ // 0〜255を各桁に分解する
        rd0[i] = ad%10;
        ad = ad/10;
      }
      ad=ad_data[1]>>2;// AN1
      if(ad==0) p1_6=1;// AN1入力確認
      else p1_6=0;
      for(i=0;i<3;i++){ // 0〜255を各桁に分解する
        rd1[i] = ad%10;
        ad = ad/10;
      }

      I2C_LCD_cursor(1,0); // 1行目0より表示
      I2C_LCD_str("A/D");
      I2C_LCD_cursor(1,4);
      I2C_LCD_data(rd0[2]+0x30);
      I2C_LCD_data(rd0[1]+0x30);
      I2C_LCD_data(rd0[0]+0x30);

      I2C_LCD_cursor(2,4); // 2行目5より表示
      I2C_LCD_data(rd1[2]+0x30);
      I2C_LCD_data(rd1[1]+0x30);
      I2C_LCD_data(rd1[0]+0x30);
    }
  }
  /* I/O初期化関数 */
  void init(void)
  {
    int i;
    /**** 高速オンチップオシレータで動作する場合 ****/
    prc0 = 1;// プロテクトレジスタ解除
    hocoe = 1;// 高速オンチップオシレータ発振開始
    for(i=0;i<50;i++);//発振安定まで待つ
    hscksel =1;// 高速オンチップオシレータ選択ビットを1にする
    scksel =1;// システム基準クロックを高速にする
    prc0 = 0;// プロテクトレジスタ禁止
    pd1=0xfc;// ポートディレクションレジスタ p1_0,p1_1 入力〜p6出力ポート設定
    pd4 =0x24;//p4_2,p4_5出力 0010 0100
    pml3= 0x80;
    mstcr= 0x00;/* モジュールスタンバイ制御レジスタをアクティブ*/
  }

  void ad_init(void)
  {

    /* ==== Set Port ==== */
    pd1_0 = 0; /* AN0 port direction = input */
    pd1_1 = 0; /* AN1 port direction = input */
    pml1 &= 0xf0; /* Select AN0 and AN1 inputs */

    /* ==== Disable A/D converter interrupt ==== */
    adicsr = 0x00; // A/D割り込み制御ステータスレジスタ
    ilvl7 &= 0xfc;

    mstcr &= 0x63;// Activate A/D converter

    adcon0 = 0x00;// Stop A/D conversion

    /* ---- Set A/D mode ---- */
    admod = 0x1c; // Clock source : fAD 0x1c f20:0x1b
    // A/D operating mode : repeat sweep mode
    // A/D conversion starts by software trigger

    /* ---- Set A/D input channel ---- */
    adinsel = 0x00;// Analog input pin : AN0, AN1

    /* ---- Enable A/D converter interrupt ---- */
    adie = 1;// A/D割り込み制御ステータスレジスタ割り込み許可ビット
    ilvl7 |= 0x01; // Enable A/D converter interrupt (level 1)

  }

  #pragma interrupt/B _ad_converter(vect=14)
  void _ad_converter(void)
  {
    adf = 0;// Clear A/D割り込み制御ステータスレジスタ割り込み要求ビット
    /* ---- Write A/D conversion result ---- */
    ad_data[0]=0x03ff & ad0;// Write conversion result of AN0 to buffer
    ad_data[1]=0x03ff & ad1;// Write conversion result of AN1 to buffer
  }
  /* End of File */

(4)ヘッダーファイル ctrl_blm.h

 赤字の部分のI2C端子の割り当てを変更しています。

  /****************************************/
  /* ctrl_blm.h */
  /****************************************/
  /*======================================*/
  /* シンボル定義 */
  /*======================================*/

  #define I2C_S_SCL p4_5=1 // I2Cクロック p4_2を1にする
  #define I2C_C_SCL p4_5=0 // I2Cクロック p4_2を0にする
  #define I2C_S_SDA p4_2=1 // I2Cデータ p4_5を1にする
  #define I2C_C_SDA p4_2=0 // I2Cデータ p4_5を0にする
  #define I2C_SDA_IN pd4_2=0 // p4_5を入力ポートに設定
  #define I2C_SDA_OUT pd4_2=1 // p4_5を出力ポートに設定
  #define I2C_SDA_data p4_2 // データポートをp1_0に設定

  #define ADDR 0x7c // アドレス 0B 0111 110+0(c/w)
  #define CLOCK 20000

  /*======================================*/
  /* プロトタイプ宣言 */
  /*======================================*/
  void init(void);
  void wait_us(unsigned long usec);// us単位のタイマ
  void wait_ms(unsigned long msec);// ms単位のタイマ
  void delay(void);// 6usの遅延関数

  void I2C_start(void);// I2C開始
  void I2C_stop(void);// I2Cストップ
  void ack(void);// ACKNOWLEDGE信号受信
  void I2C_H_CLK(void);// クロックHigh
  void I2C_L_CLK(void);// クロックLow
  void I2C_LCD_init(void);// lcd初期化関数
  int I2C_write(unsigned char data);// 書き込みの基本関数
  static unsigned char I2C_read(void);// 読み込みの基本関数
  void I2C_LCD_cmd(unsigned char cmd);// 液晶へのコマンド出力関数
  void I2C_LCD_data(unsigned char data);// 液晶への1文字出力関数
  void I2C_LCD_str(char* ptr);// 液晶への文字列表示関数
  void I2C_LCD_clear(void);// 液晶のクリャー関数

  // カーソル位置設定関数 line(行数):1 or 2 cursor(左端からの位置):0〜f
  void I2C_LCD_cursor(unsigned char line,unsigned char cursor);

  void timer(unsigned long timer_set);// タイマRB割り込み使用

  void ad_init(void); /* Initial setting of A/D converter */
  void _ad_converter(void); /* A/D converter interrupt processing */


(5)LCD制御プログラム i2clcd_ctrl.c
 
  このプログラムは「I2C接続LCDを制御する」で使用したものと同じものですが、ヘッダーファイルで宣言してあるように、I2Cデータ端子を
 p4_2、I2Cクロック端子をp4_5に変更しています。


◎プログラムの実行画面


プロジェクトファイルのダウンロード


メニューに戻る