YS電子工作ラボ

<V.3版>
2ch 2ADC
同時高速AD変換

(→プロジェクトファイル(Harmony Ver.3版 MHC v3.6.0) ダウンロード


  PIC32MZには 6個の独立したADCがあります。(→ PIC32MZのADC構成 )お互いに独立なので複数の入力を並列に処理できることから高速処理が可能となっています。 以下に 2個のADCを同時に使う例を紹介します。


<仕様>
 ・PIC32MZの2個の専用ADCを同時に使う、2チャンネル同時ADCを行う。
 ・入力ポートはAN4/RB4(内部ADC: ADC4) とAN45/RB5(内部ADC: ADC0)とする。
 ・入力電圧を以下の要領で液晶に表示する。
    1行目: V_AN4=◯◯◯[V]
    2行目: V_AN45=◯◯◯[V]
 ・AD変換と液晶表示は250msec毎とし、タイマ割り込を使う。
 ・タイマはダイナミックタイマを使うこと。
 ・割り込み検出チェック用として割り込み発生に合わせLEDをON/OFFさせる。
 ・PIC32MZ起動直後液晶に以下を表示する。
   1行目: "From Now"
   2行目: "AD Start !!" 


<回路図> ( → PDFファイル
 

<外観> PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
     汎用モジュール評価ボード(段積みボード)には本テーマと関係ない部品が多々実装されています。また、グラフィック液晶は
     本テーマと関係ないのではずしています。





<動作結果>( → 動画:1080pのHD動画を見ることができます。)

起動直後   1行目:  アナログ入力電圧(AN4/RB4) 
 2行目:  アナログ入力電圧(AN45/RB5)
 入力電圧(AN4/RB4) = 0.01v
 入力電圧(AN45/RB5) = 0.00v
 入力電圧(AN4/RB4) = 1.00v
 入力電圧(AN45/RB5) = 1.00v
入力電圧(AN4/RB4) = 3.04v
入力電圧(AN45/RB5) = 3.30v
     





<解説>  記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います。

  ★プロジェクトをコンパイルして、コンパイラエラー "error: unknown type name 'uintptr_t'"が出た場合( → URL

 ■ MHC設定

項目 1. [Clock Diagram]タブで、クロックの構成を外付け24MHz水晶発振器用、システムクロック200MHzに設定します。
 POSCMOD: → EC
 FPLLICLK: → POSC
 FPLLIDIV: → DIV_3
2. [Pin Settings]タブでの設定
■ピン1のRG15ポート
 Function: → GPIO
 Direction: → OUT
3. [Prpject Graph]タブでの設定
■追加コンポーネント
 TMR9, ADCHS
■ コンポーネント間の接続
 なし
MHC
項目 4. [Prpject Graph]タブ
   TMR9のコンポーネント設定
■プリスケーラ
  Select Prescaler : → 1/256 に変更
5. [Prpject Graph]タブ
   ADCHSのコンポーネント設定1
■出力フォーマット
  Fractional Data Format bit: → Integer に変更

■使用ADCモジュール
 Dedicated ADC Modules: ADC0にチェック追加
■ADC0 Analogue Input Select bit → AN45
■AD変換開始トリガ
 Select Trigger Source: 
  → Global Software edge Triggerに変更
6. [Prpject Graph]タブ
   ADCHSのコンポーネント設定2
■使用ADCモジュール
 Dedicated ADC Modules: ADC4にチェック追加

■AD変換開始トリガ
 Select Trigger Source: 
  → Global Software edge Triggerに変更

■入力ポート、クラス
Analogue Signal configuration: 
 Configure Analogue Input AN0にチェック追加
 AN0 is using signed Data modeにチェック追加
 Configure Analogue Input AN4にチェック追加

 AN4 is using signed Data modeにチェック追加
MHC


  


■ キャラクタ液晶表示のライブラリ 1lcd_lib_XC32.h と 1lcd_lib_XC32.cを main.cと同じフォルダにコピーして、プロジェクトに追加します。
     (詳細→ キャラクタ液晶表示方法 参照






■ main.cに、青字部分を追加します。 他のファイル変更の必要ありません。

  ① 1lcd_lib_XC32.hのインクルード、所要のグローバル変数の定義、宣言をします。
    #include "stdio.h"
    #include "1lcd_lib_XC32.h"
    bool LED = 0;

    ……
    ……


  ② NOPを利用した μsec、msecの遅延関数 delay_us( )、delay_ms( )を定義します。
    void delay_us(volatile unsigned int usec) //1μsec遅延
    {
       volatile int count;

    ……
    ……




  ③ タイマ9のコールバック関数です。 10msec毎に呼び出されます。 25回呼び出されれると(250msec毎に)
      フラグTimer_Triggreのフラグをたてて AD変換を実行しています。
    void TMR9_Callback_Fn(uint32_t status, uintptr_t context) //コールバック関数 //1秒毎に呼び出される
    {
      Count_10msec++;
      if(Count_10msec >= 25) //250msec 経過
      {
        Count_10msec = 0;
        Timer_Trigger = true;
      }
    }




  ④ AdcFunc( ) で 入力のAD変換を行い、液晶に表示します。
   1. ADCHS_ChannelConversionStart(); でグローバルソフトウェアエッジトリガをかけAD変換が開始されるはずですが
     コンパイルエラーがでてしまします。 レジスタ直接操作で動作させています。
   2. while(!ADCHS_ChannelResultIsReady(ADCHS_CH4));でAD変換の終了を待ちます。
   3. AdcValue4 = ADCHS_ChannelResultGet(ADCHS_CH4);で 結果を取り出します。
   4. 続いて 入力ポートは AN45に切り替わっているのでAN0の値を取得する要領で
     while(!ADCHS_ChannelResultIsReady(ADCHS_CH0)); で AD変換の終了を待ちます。
   5. AdcValue45 = ADCHS_ChannelResultGet(ADCHS_CH0) + 0x800; で AN45入力のAD変換値を取得します。
     AdcValue45 = ADCDATA0 + 0x800;
      本来なら + 0x800は不要なはずですが、所要の値が得られないので 実験により 所要の値を得る為に加算しています。 バグ?

  void AdcFunc(void)
  {
    unsigned short int AdcValue4 = 0;
    unsigned short int AdcValue45 = 0;
    double V_AN4;
    double V_AN45;

    //AD変換開始 Trigger a conversion
    //ADCHS_ChannelConversionStart(ADCHS_CH0);//変換開始(グローバルソフトウェアエッジトリガの場合)
    // ADCHS_ChannelConversionStart();//変換開始(グローバルソフトウェアエッジトリガの場合) //コンパイルエラー: too few arguments to function 'ADCHS_ChannelConversionStart'
    ADCCON3bits.GSWTRG = 1; //変換開始(グローバルソフトウェアエッジトリガの場合)
    //Trigger conversion for ADC inputs that have selected the GSWTRG bit as the trigger signal, either
    //through the associated TRGSRC<4:0> bits in the ADCTRGx registers or through the STRGSRC<4:0>
    //bits in the ADCCON1 register
    //Class1 の場合、"ADCCON1bits.STRGSRC = 0; //スキャン開始トリガなし変換が終了する”(default)にすると
    //変換終了後、自動的にサンプリングが実行される。

    //変換完了を待つ Wait the conversions to complete
    //AN4
    // while(!ADCHS_ChannelResultIsReady(ADCHS_CH4));
    while (ADCDSTAT1bits.ARDY4 == 0);
    //結果の取り出し fetch the result
    // AdcValue4 = ADCHS_ChannelResultGet(ADCHS_CH4);
    AdcValue4 = ADCDATA4;




    //AN45 //AN0
    while(!ADCHS_ChannelResultIsReady(ADCHS_CH0));
    // while (ADCDSTAT1bits.ARDY0 == 0);
    //結果の取り出し fetch the result
    AdcValue45 = ADCHS_ChannelResultGet(ADCHS_CH0) + 0x800;
    // AdcValue45 = ADCDATA0 + 0x800; //★ +0x800: 実験による補正 //コンパイラにバグ?
    //AdcValue45 = ADCDATA0; //本来ならこのコードで正常動作するはず。 Harmony v2.04ではこのコードでOKである。

    lcd_cmd(0x80); //1目の先頭へ
    V_AN4 =(double)AdcValue4/4095*3.3;
    sprintf(Buf,"V_AN4=%.2f[V] ",V_AN4); //文字列としてバッファーに収納
    lcd_str(Buf); // 開始メッセージ1行目表示

    lcd_cmd(0xC0); //2行目の先頭へ
    _AN45 =(double)AdcValue45/4095*3.3;
    sprintf(Buf,"V_AN45=%.2f[V] ",V_AN45); //文字列としてバッファーに収納
    lcd_str(Buf); // 開始メッセージ2行目表示
  }






  ⑤ main()の始めで ADC0の入力ポートを AN0からAN45に変更します。 PIC32MZの専用ADCのADC0の構成は
    以下のようになっています。 デフォルトはAN0が入力ポートになっています。ADCTRGMODEbits.SH0ALT = 1; に相当する
    Harmonyタイプの関数が見当たらないのでレジスタ命令を使いました。
    ADCTRGMODEbits.SH0ALT = 1; //入力ポート変更: AN0 --> AN45







   ⑥ AD変換出力のフォーマットを unsigned shortに設定しています。
     //★出力フォーマット: unsigned data format
     ADCIMCON1bits.SIGN4 = 0; //出力フォーマット: unsigned short int //  unsigned data format




   ⑦ 起動時の液晶表示部分です。
     lcd_init(); // LCD初期化
     lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
     lcd_cmd(0x80); //1目の先頭へ

     ……
     ……


    ⑧ インターバルタイマのタイマ9のインターバル時間 及びコールバック関数の設定と有効化です。
     TMR9_PeriodSet(3907); //50 nsec x2 x 3907 x 256 = 1000192μsec = 10.00192msec
     //クロック:100MHz
     TMR9_Start(); //タイマ1 スタート
     //T1CONbits.ON = 1; //レジスタ直接制御
     TMR9_CallbackRegister(TMR9_Callback_Fn, NULL); //コールバック関数設定
     //void TMR1_CallbackRegister(TMR_CALLBACK callback_fn, uintptr_t context);



    
    ⑨ ここに若干の遅れがないと Timer_Triggerが while ( true )内でグローバル関数として認識されません。
      Harmony V2.04ではこのようなことはありませんでした。
     delay_us(1); //必須

    ⑩ AD変換のタイミングのフラグTimer_Triggerが立った場合の処理を記述します。
       すなわち、250msec毎にAD変換を行い、キャラクタ液晶に表示します。
     if(Timer_Trigger == 1) //AD変換、表示のタイミング
     {
      AdcFunc(); //AD変換、表示
      Timer_Trigger = 0;

      ……
      ……

 




以下、 main.c 全文