マイコン制御によるSWR計のリモート化その42015年05月25日 19:52

はじめにお読みください。→当サイトのリンクと免責事項

R8Cの開発はWEBに沢山あるのでそれを見ればほとんど出来上がります。またメーカサイトにはほとんどのサンプルがあります。
ADコンバータとシリアル通信はここを参考にしました。ADコンバータとシリアル通信の送信は割り込みを使っていません。下のコードはADCとUARTの初期化ルーチンです。
///=================================================================*
//  Function Init_ADC ADCの初期化 割り込み未使用
///=================================================================*
void Init_ADC(void)
{
// ====================================
// ADCON0の設定
// ====================================
    md = 0;  //単発モード
    ch2 = 0;    //
    ch1 = 0;    //
    ch0 = 0;    // AN0指定
    adgsel0 = 0;  //AN8-AN11使用不可
    adst = 0;  //A/D変換停止
    cks0 = 0;  //
    cks1 = 0;  // f4指定
 bits = 0;  // 8bit mode
    vcut = 1; //VREF接続
// ====================================
// ADCON2の設定
// ====================================
//    adcon2 = 0;
    smp = 0; //サンプル&ホールドなし
}
///========================================================================================*
//   Function Init_UART UART初期化 割り込み受信使用
///========================================================================================*
void Init_UART(void)
{
    u0brg = 0x81;    //ビットレート(9600bps)
    smd0_u0mr = 1;  //
    smd1_u0mr = 0;  //
    smd2_u0mr = 1;  //8ビット長
 ckdir_u0mr = 0; //  外部クロック未使用
    stps_u0mr = 0;  //1ストップビット
    prye_u0mr = 0;  //パリティなし
    clk0_u0c0 = 0;  //
    clk1_u0c0 = 0;  //  f1
    nch_u0c0 = 0;
    ckpol_u0c0 = 0;
    uform_u0c0 = 0;
    te_u0c1 = 1;  //  送信可
    re_u0c1 = 1;  //  受信可
// ************************************
//    UART受信割り込みの設定
// ************************************
 s0ric = 0x0d;   // 割り込み有りレベル6
}

AD変換、DDSの周波数更新、シリアルデータ送出はタイマー割り込みを使い0.5秒ごとに処理にしています。シリアル通信の受信(PC->SWR計)はこの0.5秒ごとにポーリングしても良いのですが、ほとんど来ないので受信だけ割り込みで処理しています。下のコードはUART受信割り込みのルーチンです。
//========================================================================
//UART0 RCV 割り込み処理             
//========================================================================
#pragma interrupt UART0_RCV(vect=18)
void UART0_RCV( void )
{
    char error;
    error = u0rbh & 0xf0; // エラーデータ
 if (error == 0x00 ){
  UART_DATA = u0rbl;
  }
 re_u0c1 = 1;  //  受信可
}
I2Cもメーカーにサンプルがあるのですが今回と同じ秋月電子のI2Cの液晶モジュールの例がここにあり参考にしました。この中にI2C接続小型LCDモジュールの制御プログラムの解説があります。
I2C液晶は1文字表示に10msはかかるので8文字2行で160msはかかります。割り込みで待つほうが賢いでしょう。この例は1msごとにタイマー割り込みで処理しています。
例はR8C/38A用なのでSFRレジスタの宣言ファイルを"sfr_r838a.h"から"sfr_r825.h"に変更します。またポートの入出力設定のピンを変更します。R8C/38AのSDAはP3_7ですがR8C/25はP3_4です。 
DDSですが割り込みは使わずSPIのインターフェースをポートの入出力で書きます。
発振周波数が数百Hzから5kHz ですので28BitのFREQREG値の最大は
 5kHz =  fMCLK /2^28 * FREQREG  =  0.074505806 * FREQREG  ∴ FREQREG = 67109  = 0x10625
この値は14ビットを超えます。ですからMSB14bitとLSB14bitの両方を毎回書き込む必要があります、
DDSは2つありますのでP2ポートの0,1,2と3,4,5を使っています。 
//******************************************************************************************
//   Function Name : INIT DDS
//******************************************************************************************
void INIT_DDS(void)
{
       DDS_DATA = 0x2100;   //コントロールレジスタ B28=1 RESET=1
       DDS_WRITE(0);
       DDS_WRITE(1);
       DDS_DATA = 0x4625;   //FRE =( 20MHz /  684,354,560 )* 0x10625 = 5KHz
       DDS_WRITE(0);
       DDS_WRITE(1);
       DDS_DATA = 0x4004;   //
       DDS_WRITE(0)
      DDS_WRITE(1);
       DDS_DATA = 0xC000;   //PHASE0 <= 0000
       DDS_WRITE(0);
        DDS_WRITE(1);
       DDS_DATA = 0x2000;   //コントロールレジスタ B28=1 RESET=0
       DDS_WRITE(0);
        DDS_WRITE(1);
       DDS_DATA = 0x4625;   //FRE =( 20MHz /  684,354,560 )* 0x10625 = 5KHz
       DDS_WRITE(0);
        DDS_WRITE(1);
       DDS_DATA = 0x4004;  
       DDS_WRITE(0);
        DDS_WRITE(1);
       DDS_DATA = 0xC000;   //PHASE0 <= 0000
       DDS_WRITE(0);
        DDS_WRITE(1);
}
//******************************************************************************************
//   Function Name : DDS_WRITE
//******************************************************************************************
void DDS_WRITE(unsigned int DDS_SEL)
{
       unsigned int i,d;
       d = DDS_DATA;
       if (DDS_SEL == 0){
           FSYNC0 = 0;
           for( i=1; i<=16; i++){
                if (d & 0x8000) SDATA0 = 1;
              else SDATA0 = 0;
                d <<=1;
                SCLK0 = 0;
                SCLK0 = 1;
               }
           FSYNC0 = 1;    
       }else if (DDS_SEL == 1){
           FSYNC1 = 0;
               for( i=1; i<=16; i++){
                if (d & 0x8000) SDATA1 = 1;
                else SDATA1 = 0;
                d <<=1;
                SCLK1 = 0;
                SCLK1 = 1;  
                }
           FSYNC0 = 1; 
       }
}
周波数を変えるにはマニュアルに従って次のようにデータを送ります。
//DDS
       DDS_DATA = 0x2000;   //コントロールレジスタ B28=1 RESET=0       // DDS send
       DDS_WRITE(0);
       DDS_DATA = dds_LSB;   //14LSB send
       DDS_WRITE(0);
       DDS_DATA = dds_MSB;   //14MSB send
       DDS_WRITE(0);
dds_LSBとdds_MSBの計算はソースを見てください。
液晶に浮動小数点を表示したいと思いSPRINTFで%fを使いましたがうまく動きません。メーカーサイトをみると浮動小数点はメモリを食うので標準ではサポートしていないようなことが書かれています。
そこで小数点以下1桁のルーチンを作りました。
//=============================================================
//       sprintf_
//       入力 float
//       出力 char xx.x
//=============================================================
void sprintf_(char *str,float mVolt_ )
{
     int i;
     int k;
     int l;
     i = mVolt_ * 10;
     k = i/10;              // 整数部
     l = i- ( 10 * k );     // 小数部
     sprintf(str,"%d%s%d",k,".",l);
}
またdBmからWに変換、RLのdBからSWRに変換するのに <mathf.h>のpowf関数を使っていますがこれを使うと一挙にメモリが増えます。表示はほとんど見ないのでdBのままでもよいのですが一応使ってみました。sprintfもかなりメモリを食います。stdioでなく自作のsprintfを作って使ったほうが良いと思います。
//SWR & POWER
      POWER_dBm =(0.011723329 *  cnv_data_f_PO ) + 4.49; //電圧からdBmに変換、係数は実測
          POWER_W =(powf(10,POWER_dBm / 10)) / 1000;       //mathf.powf     ex: 50dBm = 100 W

      sprintf_(msg_line,POWER_W);
      RL_dB =(0.009025 *  cnv_data_f_RL )-1.59;         //電圧からdBに変換、係数は実測
      LGP_ = -(RL_dB /20);
      P_ = powf(10,LGP_);                                  //mathf.powf
      VSWR = (1+P_) / (1-P_);                                               //                           ex:  9.54db = 2.0 SWR
      sprintf_(msg_line_1,VSWR);
//LCD
      lcdPosition( 0, 0 );
      lcdPrintf( "%s","        ");
      lcdPosition( 0, 0 );   
      lcdPrintf( "P=%5sW",msg_line);
      lcdPosition( 0, 1 );
      lcdPrintf( "%s","        ");
      lcdPosition( 0, 1 );   
      lcdPrintf( "SWR=%3s",msg_line_1);

シリアル通信を使ってPCからのコマンドで送出されるデータを選択できるようにしました。数字の0から9までの10個のコマンドです。起動時は9です。これらの処理は0.5秒ごとのルーチンで処理しています。

パソコンとの通信は10msのインターバルで行いました。パソコンからの受信完了信号を受けてデータを送信する簡単なプロトコルを作りやり取りします。ボーレートはICの最高の115.2kにしています。
これくらいの早さだとパソコン側でメーターの針をあたかもリアルタイムであるように振らせられます。
パソコンの画面です。


当初の目的は下記4点でした。ほぼ達成できました。
1、現在XR2206で作成しているサイン波をマイコンで作る。
2、進行波の電圧からパワー値を計算し液晶表示させる。
3、反射波の電圧からSWR値を計算し液晶表示させる。
4、パワー値およびSWR値をUSBを介してパソコンに送る。

ソースはここ。パソコンとのやり取りのソースはここ


コメント

トラックバック