2016年5月10日火曜日

AD9834 DDS VFO Parameter Ver1.1.1

機能に不十分な所が有ったので、 見直してバージョンアップする事にした。変更追加した内容は、メモリーch、RIT機能 、VFOモード、任意逓倍率、メモリー初期化である。マンマシーンI/Fに変更が伴うのは、任意逓倍率である。
逓倍率は、初期化状態 x1である。
目的周波数 50.6MHzを逓倍して得るには、MUL SWを押し、ロータリーエンコーダを回して発振周波数(逓倍数)を決めればよい。再度MUL SWを押すとメモリーに記憶される。この機能は、チャンネル毎に有効である。

回路図である。RIT SWの割付以外、前のバージョンと同じ。












Program

AD9850 DUALの機能(メモリー初期化、VFOモード)を含めたので、細かな操作方法は省く。


//////////////////////////////////////////////////////////////////////
//  AD9834 DDS VFO program ver.1.1.1
//    Copyright(C)2016.JA2GQP.All rights reserved.
//
//                                    <<<<< Arduino IDE 1.0.6 >>>>>
//                                                2016/5/10
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.STEP(1M,100k,10k,1k,100,10)
//    2.Memory Channel ch0 - ch9(10ch)
//    3.Protection Operation At The Time Of Transmission
//    4.Parameter settings(DDS Clock,IF Frequency,VFO Mode)
//    5.Multiplied x1(min) - x9(max)
//--------------------------------------------------------------------
//  Library
//  http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
//
//////////////////////////////////////////////////////////////////////

#include <LiquidCrystal.h>
#include <rotary.h>
#include <EEPROM.h>

//----------  LCD Pin Assign  ------------------

LiquidCrystal lcd(12,11,10,9,8,7);        // RS,ENABLE,DB4,DB5,DB6,DB7

//----------  Define Constant Value   ----------
                                             
const byte  ENC_A = 2;                     // Encorder A
const byte  ENC_B = 3;                     //          B
const byte  SDATA = 4;                    // AD9834 SDATA
const byte  SCLK = 5;                      //        SCLK
const byte  FSYNC = 6;                    //        FSYNC
const byte  SW_TX = 13;                   // TX SW
const byte  SW_STEP = 14;               // STEP SW
const byte  SW_CH = 15;                   // CH SW
const byte  SW_ENT = 16;                 // ENT SW
const byte  SW_MUL = 17;                 // MUL SW
const byte  SW_RIT = 18;                   // RIT SW

////////////////////////////////
// Limited range
////////////////////////////////
const long  LW_RIT = -50000L;             // RIT Lower Limit
const long  HI_RIT = 50000L;                // RIT Upper Limit

const long  LW_VFO80 = 3500000L;        // 3.5MHz Lower Limit
const long  HI_VFO80 = 3575000L;           //        Upper Limit
const long  LW_VFO40 = 7000000L;          // 7MHz   Lower Limit
const long  HI_VFO40 = 7200000L;           //        Upper Limit
const long  LW_VFO20 = 14000000L;         // 14MHz  Lower Limit
const long  HI_VFO20 = 14350000L;          //        Upper Limit
const long  LW_VFO15 = 21000000L;         // 21MHz  Lower Limit
const long  HI_VFO15 = 21450000L;          //        Upper Limit
const long  LW_VFO10 = 28000000L;         // 28MHz  Lower Limit
const long  HI_VFO10 = 29700000L;          //        Upper Limit
const long  LW_VFO6 = 50000000L;          // 50MHz  Lower Limit
const long  HI_VFO6 = 54000000L;           //        Upper Limit
const long  LW_VFO2 = 144000000L;        // 144MHz Lower Limit
const long  HI_VFO2 = 146000000L;          //        Upper Limit

////////////////////////////////
// default value
////////////////////////////////
const long  DEF_FRQ = 7050000L;            // Default Vfo(7.05MHz)
const long  DEF_STP = 1000L;               // Init STEP(1kHz)
const long  DEF_OSC = 50000000L;           //         OSC(50MHz)
const long  DEF_IF = 10700000L;            //         IF (10.7MHz)
const long  DEF_VFO  = 4;                  // Vfo Mode(TR+IF)
const long  DEF_MUL  = 1;                  // Multiplied(1)

////////////////////////////////
// DDS parameter
////////////////////////////////
const unsigned long  TWO_E28 = 268435456L; // 2^28

////////////////////////////////
// etc
////////////////////////////////
const byte  Max_Chn = 10;                  // Max Channel(10ch)
const byte  Int_End = 73;                   // Initial end code
const char *CALL = "JA2GQP";         // Display Call sign
const byte  LW_MUL = 1;                    // Low Mul(x1)
const byte  HI_MUL = 9;                     // High Mul(x9)

//----------  EEPROM Memory Address   -----------------------

const byte  Frq_Eep = 0x00;                // Frequency(4byte*10)
const byte  Stp_Eep = 0x30;                // STEP(4byte*10)
const byte  Mul_Eep = 0x60;                // Mode(1byte*10)
const byte  Osc_Eep = 0x70;                // OSC(4byte*1)
const byte  If_Eep  = 0x74;                 // IF(4byte*1)
const byte  Chn_Eep = 0x80;                // Channel(1byte*1)
const byte  Vfo_Eep = 0x82;                // Vfo mode(1byte*1)
const byte  Eep_Int = 0x8e;                 // Eep Init(1byte*1)

//----------  Encorder Pin Assign(INT)  --------

Rotary r = Rotary(ENC_A,ENC_B);            // 2 = ENC_A,3 = ENC_B

//----------  Memory Assign  -------------------

long Vfo_Dat = 0;                         // VFO Data
long Rit_Dat = 0;                         // RIT Data
long RX_Dat = 0;                          // RX DDS Out Data
long TX_Dat = 0;                          // TX DDS Out Data
long Enc_Stp = 0;                         // STEP
long Lng_Wk1 = 0;                         // Long Work1
long Lng_Wk2 = 0;                         //      Work2
long DDS_CLK = 0;                         //      DDS Clock
long VFO_IF = 0;                          //      VFO IF

char *Lcd_Dat = "           ";            // Lcd Display Buffer

byte Byt_Chn = 0;                         // Channel SW
byte Byt_Chnb = 0;                        // Channel SW Old
byte Flg_Tx = 0;                          // TX Flag
byte Flg_Mul = 0;                         // Multi Flag
byte Byt_Mul = 0;
byte Flg_Ent = 0;                         // ENT Flag
byte Flg_Rit = 0;                         // RIT Flag
int8_t Flg_Over;                          // Over Flag
byte Byt_Ent = 0;
byte Flg_Osc = 0;                         // OSC Flag
byte Flg_If = 0;                          // IF Flag
byte Flg_Vfo = 0;                         // DDS Flag
byte Byt_Vfo = 0;                         // VFO Mode

//----------  Initialization  Program  ---------------

void setup(){
  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_ENT,INPUT_PULLUP);
  pinMode(SW_MUL,INPUT_PULLUP);
  pinMode(SW_RIT,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH,INPUT_PULLUP);

  lcd.begin(16, 2);                        // LCD 16*2

  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();                                   // INT Enable

  pinMode(FSYNC,OUTPUT);
  pinMode(SCLK,OUTPUT);
  pinMode(SDATA,OUTPUT);

  Flg_Tx = 0;                             // Flag Initialization
  Flg_Ent = 0;                          
  Flg_Mul = 0;                          
  Flg_Osc = 0;                          
  Flg_Vfo = 0;                          
  lcd.clear();

  if(EEPROM.read(Eep_Int) != Int_End){    // Eep initialaz
    delay(10);
    Fnc_Eep_Int();
  }

  DDS_CLK = Fnc_Eep_Lod4(Osc_Eep);        // EEPROM Read DDS OSC
  VFO_IF = Fnc_Eep_Lod4(If_Eep);            //             IF
  Byt_Chn = EEPROM.read(Chn_Eep);         //             Channel
  Byt_Chnb = Byt_Chn;
  Fnc_Eep_Rd();                                 //             VFO & STEP                            
}

//----------  Main program  ---------------

void loop() {
  if(Flg_Tx == 0){                               // TX off?
    if(digitalRead(SW_STEP) == LOW)         // STEP SW On?
      Fnc_Stp();                          
    if(digitalRead(SW_ENT) == LOW)         // ENT SW On?
      Fnc_Ent();                          
    if(digitalRead(SW_MUL) == LOW)         // MUL SW On?
      Fnc_Mul();                          

    if(Flg_Ent == 0){                          // Parameter not chenge?
      if((digitalRead(SW_CH) == LOW))      // SEL SW On?
        Fnc_Chsw();                          
      if(Flg_Mul == 0)
        if((digitalRead(SW_RIT) == LOW))    // RIT SW On?
          Fnc_Rit();
    }

    if(Byt_Chnb != Byt_Chn){                 // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
    }

    if(Flg_Ent == 1)                            // ENT proc.?
      Fnc_Prm();
    else{
      lcd.setCursor(5,1);
      lcd.print("     ");
    }
  }

  if(digitalRead(SW_TX) == LOW)             // Tx On?
    Flg_Tx = 1;                                 //    Yes,Flg_Tx Set
    else                                  
      Flg_Tx = 0;                               //     No,Flg_Tx Reset              

  Fnc_Band();                                  // Band check
  Fnc_If(Byt_Vfo);                             // VFO mode data set

  if(Flg_Tx == 0)                              // RX
    Fnc_Dds(RX_Dat / Byt_Mul);             // AD9834 DDS Out
  else{                                         // TX
    if(Flg_Over == 0)                          // In a range
      Fnc_Dds(TX_Dat / Byt_Mul);           // AD9834 DDS Out
    else
      Fnc_Dds(0);
}
     
  Fnc_Lcd();                               // LCD Display
  delay(100);
}

//----------  Function IF Proc.  ---------------

void Fnc_If(byte if_mode){
  switch(if_mode){
    case 0:                                 // Roff
      RX_Dat = 0L;                        // RX = off
      TX_Dat = Vfo_Dat;                   // TX = VFO
      break;
    case 1:                                 // TR
      RX_Dat = Vfo_Dat;                   // RX = VFO
      TX_Dat = Vfo_Dat;                   // TX = VFO
      break;
    case 2:                                // R+IF
      RX_Dat = Vfo_Dat + VFO_IF;          // RX = VFO + IF
      TX_Dat = Vfo_Dat;                   // TX = VFO
      break;
    case 3:                                 // T+IF
      RX_Dat = Vfo_Dat;                   // RX = VFO
      TX_Dat = Vfo_Dat + VFO_IF;          // TX = VFO + IF
      break;
    case 4:                                  // TR+IF
      RX_Dat = Vfo_Dat + VFO_IF;          // RX = VFO + IF
      TX_Dat = Vfo_Dat + VFO_IF;          // TX = VFO + IF
      break;
    case 5:                                  // TR-IF
      RX_Dat = Vfo_Dat - VFO_IF;          // RX = VFO - IF
      TX_Dat = Vfo_Dat - VFO_IF;          // TX = VFO - IF
      break;
    default:
      RX_Dat = 0L;                        // RX = off
      TX_Dat = Vfo_Dat;                   // TX = VFO
      break;
  }
  if((RX_Dat != 0) && (Flg_Rit == 1))
    RX_Dat = RX_Dat + Rit_Dat;
  if((RX_Dat <= 0) && (TX_Dat <= 0))
    Flg_Over = -1;
}

//----------  Encorder procedure(INT)  ---------------

ISR(PCINT2_vect) {
  unsigned char result = r.process();

  if(Flg_Tx == 0){
    if(result) {  
      if(result == DIR_CW){
        if((Flg_Mul == 0) && (Flg_Rit == 0))
          Vfo_Dat = Vfo_Dat + Enc_Stp;
        if(Flg_Rit == 1)
          Rit_Dat = Rit_Dat + Enc_Stp;
        if(Flg_Mul == 1)
          Byt_Mul++;
      }
      else{
        if((Flg_Mul == 0) && (Flg_Rit == 0))
          Vfo_Dat = Vfo_Dat - Enc_Stp;
        if(Flg_Rit == 1)
          Rit_Dat = Rit_Dat - Enc_Stp;
        if(Flg_Mul == 1)
          Byt_Mul--;
      }
    if(Vfo_Dat < 0)                              // VFO Frequency range check
      Vfo_Dat = 0L;
    Byt_Mul = constrain(Byt_Mul,LW_MUL,HI_MUL);  // MUL range check
    Rit_Dat = constrain(Rit_Dat,LW_RIT,HI_RIT);  // RIT range check
    }
  }
}

//----------  Function DDS set  ---------------

void Fnc_Dds(double frquency){
  unsigned long wrk = frquency * TWO_E28 / DDS_CLK;
  unsigned int wrk1,wrk2,wrk3;

  wrk1 = 0x2000;
  wrk2 = wrk & 0x3fff;
  wrk2 = wrk2 | 0x4000;
  wrk3 = wrk >> 14;
  wrk3 = wrk3 & 0x3fff;
  wrk3 = wrk3 | 0x4000;

  digitalWrite(SCLK,HIGH);                    
  digitalWrite(FSYNC,LOW);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk1 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk1);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk2 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk2);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk3 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk3);

  digitalWrite(FSYNC,HIGH);
}

//----------  Function Encorder STEP  ---------

void Fnc_Stp(){
  if(Enc_Stp == 10)                       // Step = 10Hz ?
    Enc_Stp = 1000000;                    //   Yes,1MHz set
  else
    Enc_Stp = Enc_Stp / 10;               // Step down 1 digit

  Fnc_Step_Disp();
  Fnc_Lcd();
  while(digitalRead(SW_STEP) == LOW)
    ;
}

//----------  Function STEP Display  ----------

void Fnc_Step_Disp(){
  lcd.setCursor(0,1);
  switch(Enc_Stp){
    case 10:
      lcd.print("10  ");
      break;
    case 100:
      lcd.print("100 ");
      break;
    case 1000:
      lcd.print("1k  ");
      break;
    case 10000:
      lcd.print("10k ");
      break;
    case 100000:
      lcd.print("100k");
      break;
    case 1000000:
      lcd.print("1M  ");
      break;
    default:
      lcd.print("1k  ");
      Enc_Stp = 1000;
      break;
  }
}

//----------  Function String Dot Edit  --------
 
char *Fnc_Dot_Edit(char *str,long n){
  int  i = 0;                           // Write the number
  char *p = str;
  unsigned long  u = abs(n);

  do{
    *p++ = "0123456789"[u % 10];
    u = u / 10;
    i++;
    if((0 != u) && (0 == (i % 3)))
      *p++ = ',';
  }
  while( 0 != u )
    ;
  if ( n < 0 )
     *p++ = '-';
   *p = '\0';
   Fnc_Revr( str );
   return str;
}

//----------  Function String Reverse  ---------

void Fnc_Revr(char *str){
  int i,n;
  char c;

  n=strlen(str);
  for(i = 0;i < n / 2;i++){
    c=str[i];
    str[i]=str[n - i - 1];
    str[n - i - 1]=c;
  }
}

//----------  Function Save EEPROM 4byte  ---------

void Fnc_Eep_Sav4(long value,int address){
  address += 3;
  for(int i = 0;i < 4;i++){
    byte toSave = value & 0xFF;
    if(EEPROM.read(address) != toSave){
      EEPROM.write(address,toSave);
      }
    value = value >> 8;
    address--;
  }
}

//----------  Function Load EEPROM 4byte  ---------

long Fnc_Eep_Lod4(int address){
  long value = 0;

  for(int i = 0;i < 4;i++){
    value = value | EEPROM.read(address);
    if( i < 3){
      value = value << 8;
      address++;
    }
  }
  return value;
}

//----------  Function LCD Display  ---------

void Fnc_Lcd(){
  lcd.setCursor(0,0);
  if(Flg_Tx == 1)
    lcd.print("T");
  else if(Flg_Ent == 1)
    lcd.print("P");
  else
    lcd.print(Byt_Chn);

  Fnc_Step_Disp();

  if(Flg_Rit == 1){
    lcd.setCursor(5,1);
    lcd.print("R          ");
    lcd.setCursor(6,1);
    if(Rit_Dat >=0)
      lcd.write('+');
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.print(Lcd_Dat);
    lcd.print("Hz");
  }

  if(Flg_Mul == 1){
    lcd.setCursor(5,1);
    lcd.print("          ");
    lcd.setCursor(5,1);
    lcd.print("x");
    lcd.print(Byt_Mul);
    Lng_Wk1 = Vfo_Dat / Byt_Mul;
    Fnc_Fdsp(Lng_Wk1);  
    }
    else if((Flg_Over == -1) && (Flg_Ent == 0) && (Flg_Rit == 0)){
      Fnc_Fdsp(Vfo_Dat);
      lcd.setCursor(5,1);
      lcd.print("Over");
    }
    else
      Fnc_Fdsp(Vfo_Dat);

  if((Flg_Vfo == 0) && (Flg_Rit == 0)){
    lcd.setCursor(10,1);
    lcd.print(CALL);
  }
}

//----------  Function Frequency Display  ---------

void Fnc_Fdsp(long f_disp){
  Fnc_Dot_Edit(Lcd_Dat,f_disp);
  lcd.setCursor(1,0);
  lcd.print(":              ");
  lcd.setCursor(3,0);
  lcd.print(Lcd_Dat);
  lcd.print("Hz");
}

//----------  Function ENT  ---------

void Fnc_Ent(){
  byte cnt = 0;

  if(Flg_Ent == 0){
    Fnc_Eep_Wt(Byt_Chn);
    while(digitalRead(SW_ENT) == LOW){
      delay(500);
      cnt++;

      if(6 <= cnt){                              // Parameter change mode(3sec)
        lcd.setCursor(0,0);
        lcd.print("P");
        Flg_Ent = 1;

        if(Flg_Osc == 0){
          Lng_Wk2 = Vfo_Dat;
          Vfo_Dat = Fnc_Eep_Lod4(Osc_Eep);
          if(Vfo_Dat <= 0){
            Vfo_Dat = DEF_OSC;
            Fnc_Eep_Sav4(Vfo_Dat,Osc_Eep);
          }
          Flg_Osc = 1;
          Flg_If = 0;
          Flg_Mul = 0;
        }

        Fnc_Fdsp(Vfo_Dat);
         
        lcd.setCursor(5,1);
        lcd.print("OSC ");
      }
    }
   
  }
  else{
    while(digitalRead(SW_ENT) == LOW){
      delay(500);
      cnt++;

      if(6 <= cnt){                            // Return Parameter cahne mode(3sec)
        lcd.setCursor(5,1);
        lcd.print("    ");
        lcd.setCursor(0,0);
        lcd.print(Byt_Chn);
        Flg_Ent = 0;
        Flg_Vfo = 0;
       
        if(Flg_Osc == 1){
          Fnc_Eep_Sav4(Vfo_Dat,Osc_Eep);
          DDS_CLK = Vfo_Dat;
          Vfo_Dat = Lng_Wk2;
          Flg_Osc = 0;
          Fnc_Fdsp(Vfo_Dat);
        }
         
        if(Flg_If == 1){
          Fnc_Eep_Sav4(Vfo_Dat,If_Eep);
          VFO_IF = Vfo_Dat;
          Vfo_Dat = Lng_Wk2;
          Flg_If = 0;
          Fnc_Fdsp(Vfo_Dat);
        }
         
        EEPROM.write(Vfo_Eep,Byt_Vfo);
      }
      else
        Byt_Ent++;
    }
  }
}

//----------  Function Prameter PROC  ---------

void Fnc_Prm(){
    lcd.setCursor(5,1);

  switch(Byt_Ent){
      case 0:                                        // OSC Set
        if(Flg_Osc == 0){
          Vfo_Dat = Fnc_Eep_Lod4(Osc_Eep);
          Flg_Osc = 1;
          }
        break;
      case 1:                                       // IF Set
        if(Flg_Osc == 1){
          Fnc_Eep_Sav4(Vfo_Dat,Osc_Eep);
          Flg_Osc = 0;
          }
     
        if(Flg_If == 0){
          Vfo_Dat = Fnc_Eep_Lod4(If_Eep);
          if(Vfo_Dat < 0)
            Vfo_Dat = DEF_IF;
          Flg_If = 1;
          }
       
        lcd.print("IF  ");
        break;
      case 2:                                      // DDS mode Set
        if(Flg_If == 1){
          Fnc_Eep_Sav4(Vfo_Dat,If_Eep);
          Vfo_Dat = Lng_Wk2;
          Flg_If = 0;
          Flg_Vfo = 0;
          }

        if(Flg_Vfo == 0){
          Byt_Vfo = EEPROM.read(Vfo_Eep);
          if(Byt_Vfo < 0)
            Byt_Vfo = 0;
          Flg_Vfo = 1;
          }

        lcd.setCursor(10,1);
        switch(Byt_Vfo){
          case 0:
            lcd.print("Roff  ");                  // TX=VFO RX=0
            break;
          case 1:
            lcd.print("TR    ");                  // TX=VFO RX=VFO
            break;
          case 2:
            lcd.print("R+IF  ");                  // TX=VFO RX=VFO+IF
            break;
          case 3:
            lcd.print("T+IF  ");                  // TX=VFO+IF RX=VFO
            break;
          case 4:
            lcd.print("TR+IF ");                  // TX=VFO+IF RX=VFO+IF
            break;
          case 5:
            lcd.print("TR-IF ");                  // TX=VFO-IF RX=VFO-IF
            break;
          default:
            Byt_Vfo = 0;
            lcd.print("Roff  ");
            break;
          }

        lcd.setCursor(5,1);
        lcd.print("VFO ");
        break;
      default:
        if(Flg_Vfo == 1){
          EEPROM.write(Vfo_Eep,Byt_Vfo);
          lcd.setCursor(10,1);
          lcd.print(CALL);
          Flg_Vfo = 0;
        }

        lcd.setCursor(5,1);
        lcd.print("OSC ");
        Byt_Ent = 0;
        break;
  }
}

//----------  Function CH SW Check  ---------

void Fnc_Chsw(){
  byte cnt = 0;

  Byt_Chn++;
  while(digitalRead(SW_CH) == LOW){
    delay(500);
    cnt++;
    if(6 <= cnt){                               // Eep Initial start(3sec)?
      Fnc_Eep_Int();                            // Initialization
      Byt_Chn = EEPROM.read(Chn_Eep);           // Channel Read
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();                             // EEPROM Read
      lcd.setCursor(0,0);                       // LCD display
      lcd.print(Byt_Chn);
      Fnc_Fdsp(Vfo_Dat);
      lcd.setCursor(5,1);
      lcd.print("Init End   ");
    }
  }
}

//---------- Function Eeprom Initialization -----------------

void Fnc_Eep_Int(){
  int i;

  for (i=0;i<160;i++)                            // 0 clear(160byte)
    EEPROM.write(i, 0);

  for(i=0;i<Max_Chn;i++){
    Fnc_Eep_Sav4(DEF_FRQ,Frq_Eep+i*4);            // Frequency(7.05MHz)
    Fnc_Eep_Sav4(DEF_STP,Stp_Eep+i*4);            // Step(1kHz)
  }

  Fnc_Eep_Sav4(DEF_OSC,Osc_Eep);                  // OSC(50.0Mhz)
  Fnc_Eep_Sav4(DEF_IF,If_Eep);                    // IF(10.7MHz)
  EEPROM.write(Vfo_Eep,DEF_VFO);                  // Vfo Mode

  for(i=0;i<Max_Chn;i++)                          // Multiplied
    EEPROM.write(Mul_Eep+i,DEF_MUL);              //  (x1)

  EEPROM.write(Eep_Int,Int_End);                  // Init end set(73)
}

//----------  Function EEPROM Read  ---------

void Fnc_Eep_Rd(){
  if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep+Byt_Chn*4);
  else{
    Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep+0*4);
    Byt_Chn = 0;
  }

  if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    Enc_Stp = Fnc_Eep_Lod4(Stp_Eep+Byt_Chn*4);
  else
    Enc_Stp = Fnc_Eep_Lod4(Stp_Eep+0*4);

  Byt_Mul = EEPROM.read(Mul_Eep+Byt_Chn);      
  Byt_Vfo = EEPROM.read(Vfo_Eep);
}

//----------  Function EEPROM Write  ---------

void Fnc_Eep_Wt(byte chn){
  if((0 <= chn) && (chn < Max_Chn)){
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep+chn*4);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep+chn*4);
  }

  EEPROM.write(Chn_Eep,chn);
}

//----------  Function Band  ---------

void Fnc_Band(){
  if((Vfo_Dat >= LW_VFO80) && (Vfo_Dat <= HI_VFO80))
    Flg_Over = 0;
  else if((Vfo_Dat >= LW_VFO40) && (Vfo_Dat <= HI_VFO40))
    Flg_Over = 0;
  else if((Vfo_Dat >= LW_VFO20) && (Vfo_Dat <= HI_VFO20))
    Flg_Over = 0;
  else if((Vfo_Dat >= LW_VFO15) && (Vfo_Dat <= HI_VFO15))
    Flg_Over = 0;
  else if((Vfo_Dat >= LW_VFO10) && (Vfo_Dat <= HI_VFO10))
    Flg_Over = 0;
  else if((Vfo_Dat >= LW_VFO6) && (Vfo_Dat <= HI_VFO6))
    Flg_Over = 0;
  else if((Vfo_Dat >= LW_VFO2) && (Vfo_Dat <= HI_VFO2))
    Flg_Over = 0;
  else
    Flg_Over = -1;
}

//----------  Function Multi  ---------

void Fnc_Mul(){
  if(Flg_Ent == 0){
    if(Flg_Mul == 0){
      Byt_Mul = EEPROM.read(Mul_Eep+Byt_Chn);
      Flg_Mul = 1;
    }
    else
      Flg_Mul = 0;
  }
  else
    Byt_Vfo++;

  EEPROM.write(Mul_Eep+Byt_Chn,Byt_Mul);
  while(digitalRead(SW_MUL) == LOW)
    ;
}

//----------  Function Rit  ---------

void Fnc_Rit(){
  if(Flg_Rit == 0){
    Rit_Dat = 0;
    Flg_Rit = 1;
  }
  else
    Flg_Rit = 0;

  while(digitalRead(SW_RIT) == LOW)
    ;
}



        

2016年5月2日月曜日

Arduino AD9850 DUAL VFO

BFOとSメータが付いたAD9850 VFO。Sメータ付のArduino AD9850 DDS VFOをベースに改造。BFO(LSB、USB、CW、予備のSUB)、IF、VFO動作モードをパラメータ化し、EEPに保存した。固有部分をパラメータ化した事で、プログラムを修正することなく使える様にした。
開発に使用したボードである。LCDは、20x4のI2C。DDSボートは、公開済みのAD9850 DUALシールドである。

回路図である。AD9850 Moduleを2枚使っているが、1枚のみでも動作する。ただ、1枚のみの使用ではキャリア発振(BFO機能)がない事を我慢しなければならない。











パラメータ

EEPにアプリケーション固有部を持たせる事で、汎用性を高めた。パラメータ変更は通常動作時に変更可能。基本的にSW長押しをした後、希望内容を選択し、SW長押しで復帰する様にしてある。

1.EEP初期化
  何らかの理由で初期化が必要な場合、CH SWを3秒程長押しするとEEPの再初期化が出来る。(初めて使う場合は、プログラムで初期化しているので、必要ない。)

2.IFとVFO動作モード設定
  

IF画面。
ENT SWを3秒程長押しすると左画面が現れる。ロータリエンコーダで希望値に変更し、ENT SWを押す。(ENT SWを押すことで、EEPに書き込まれる。)



VFO設定画面。
VFO動作モードの画面が現れる。RIT SWを押しVFO動作モードを選択する。
RIT SWを押すとVFO設定モードが循環。
Roff -> TR -> R+IF -> TR+IF -> Roffと循環。
 Roff   TX=VFO、RX=0(出力停止)
 TR    TX=VFO、RX=VFO
 R+IF   TX=VFO、RX=VFO+IF
 TR+IF  TX=VFO+IF、RX=VFO+IF
ENT SWを押すとIF画面に戻る。ENT SWを3秒程長押し、復帰する。



3.BFO周波数設定


BFO設定画面。
MODE SWを3秒程長押しすると左画面が現れる。ロータリエンコーダで希望値に変更し、MODE SWを押す。(MODE SWを押すことで、EEPに書き込まれる。)
MODE SWを押すとMODE設定モードが循環。
LSB -> USB -> CW -> SUB -> LSBと循環。(予備用SUB。)
MODE SWを操作し、LSBにした後、MODE SWを3秒程長押し、復帰する。




Program

今回、表示のチラツキ、リアル表示など細かな所まで改造した為、冗長な所が有るかも知れない。Arduino IDE 1.6.Xでもコンパイルしたが、表示に関するBug回避が出来なかった。この為、IDE 1.0.6とヘッダーに書き入れた。
RITとSPLIT機能は、双方向動作が出来る様にした。例えば、RIT中周波数をSPLIT SWを押すことで、送信周波数のシフトにできる。当然、その逆も可能。
Sメータは、MARLANUが追加したもので、ピークホールドがあり、優れもの。

/////////////////////////////////////////////////////////////////////
//    Copyright©2014-2016.JA2GQP.All rights reserved.
//                                     Ver 1.01
//            AD9850 DUAL DDS VFO(Arduino IDE 1.0.6)
//  
//                                                  2016/5/2
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.RIT Operation(-50kHZ to 50kHZ)
//    2.STEP(1M,100k,10k,1k,100,10)
//    3.Memory Operation is Push ENT
//    4.Protection Operation At The Time Of Transmission
//    5.Channel Memory Ch0-ch9(10ch)
//    6.Split Operation(-50kHZ to 50kHZ)
//    7.Parameter(BFO,IF,IF mode)
//--------------------------------------------------------------------
//  Library
//    http://www.buxtronix...e-properly.html
//
//--------------------------------------------------------------------
// Additional S-meter function
//   Editat de MARLANU, 08 februarie 2015 - 12:36
//
//--------------------------------------------------------------------
// Bug
//   2016/7/6 IF mode bug fixed.
//////////////////////////////////////////////////////////////////////

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <rotary.h>
#include <EEPROM.h>

//----------  LCD Pin Assign  -------------------------------

LiquidCrystal_I2C lcd(0x27,20,4);          // address 0x27,LCD 20 x 4

//----------  Define Constant Value   -----------------------

////////////////////////////////
// I/O assign
////////////////////////////////
const byte  ENC_A = 2;                     // Encorder A
const byte  ENC_B = 3;                     // Encoeder B
const byte  SW_STEP = 4;                   // STEP SW
const byte  SW_RIT = 5;                    // RIT SW
const byte  SW_SPLIT = 6;                  // SPLIT SW
const byte  C_DATA = 7;                    // DIO7
const byte  C_UD = 8;                      // DIO8
const byte  C_CLK = 9;                     // DIO9
const byte  V_DATA = 10;                   // DIO10
const byte  V_UD = 11;                     // DIO11
const byte  V_CLK = 12;                    // DIO12
const byte  SW_TX = 13;                    // TX SW
const byte  SW_ENT = 15;                   // ENT SW
const byte  SW_MODE = 16;                  // MODE SW
const byte  SW_CH = 17;                    // CH SW
                                             
////////////////////////////////
// default value
////////////////////////////////
const long  DEF_IF = 10700000L;            // IF
const long  DEF_LSB = 10701500L;           // Career LSB
const long  DEF_USB = 10698500L;           //        USB
const long  DEF_CW  = 10699400L;           //        CW
const long  DEF_SUB  = 0L;                 //        SUB
const long  DEF_VFO  = 3;                  // Vfo Mode(TR+IF)
const long  DEF_FRQ = 7050000L;            // Init Frequency
const long  DEF_STP = 1000L;               // Init STEP

////////////////////////////////
// Limited range
////////////////////////////////
const long  LW_FRQ = 0L;                   // Frequency Lower Limit
const long  HI_FRQ = 30000000L;            //           Upper Limit

const long  LW_VFO80 = 3500000L;           // 3.5MHz Lower Limit
const long  HI_VFO80 = 3575000L;           //        Upper Limit
const long  LW_VFO40 = 7000000L;           // 7MHz   Lower Limit
const long  HI_VFO40 = 7200000L;           //        Upper Limit
const long  LW_VFO20 = 14000000L;          // 14MHz  Lower Limit
const long  HI_VFO20 = 14350000L;          //        Upper Limit
const long  LW_VFO15 = 21000000L;          // 21MHz  Lower Limit
const long  HI_VFO15 = 21450000L;          //        Upper Limit
const long  LW_VFO10 = 28000000L;          // 28MHz  Lower Limit
const long  HI_VFO10 = 29700000L;          //        Upper Limit

const long  LW_RIT = -50000L;               // RIT Lower Limit
const long  HI_RIT = 50000L;                // RIT Upper Limit

////////////////////////////////
// DDS parameter
////////////////////////////////
const unsigned long  DDS_CLK = 125000000L; // AD9850 Clock
const unsigned long  TWO_E32 = 4294967295L;// 2^32
const byte  DDS_CMD = B00000000;           // AD9850 Command

////////////////////////////////
// etc
////////////////////////////////
const byte  Max_Chn = 10;                  // Max Channel(10ch)
const byte  Int_End = 73;                  // Initial end code
const char *CALL = "  JA2GQP  ";           // Display Call sign

const byte IN_LEFT = A0;                   // analog input for left channel
const byte T_REFRESH = 100;                // msec bar refresh rate
const byte T_PEAKHOLD = 3*T_REFRESH;       // msec peak hold time before return

//----------  EEPROM Memory Address   -----------------------

const byte  Frq_Eep = 0x00;                // Frequency(4byte*10)
const byte  Stp_Eep = 0x30;                // STEP(4byte*10)
const byte  Mode_Eep = 0x60;               // Mode(1byte*10)
const byte  Care_Eep = 0x70;               // DDS Career(4byte* 4)
const byte  If_Eep = 0x80;                 // IF(4byte*1)
const byte  Chn_Eep = 0x90;                // Channel(1byte*1)
const byte  Vfo_Eep = 0x92;                // Vfo mode(1byte*1)
const byte  Eep_Int = 0x9e;                // Eep Init(1byte*1)

//----------  Encorder Pin Assign(INT)  ---------------------

Rotary r = Rotary(ENC_A,ENC_B);            // 2 = ENC_A,3 = ENC_B

//----------  Memory Assign  --------------------------------

long Vfo_Dat;                             // VFO Data
long Vfo_Datb;                            // VFO Old Data
long Vfo_Save;                            // VFO Backup Data
long RX_Dat;                              // RX DDS Out Data
long TX_Dat;                              // TX DDS Out Data
long Car_Dat;                             // Careea DDS Out Data
long Rit_Dat;                             // RIT Data
long Rit_Datb;                            // RIT Data Old
long Enc_Stp;                             // STEP
long Lng_Wk1;                             // Long Work1
long Lng_Wk2;                             // Long Work2
long Vfo_If;                              // VFO IF

char *Lcd_Dat = "           ";            // Lcd Display Buffer

byte Byt_Chn;                             // Channel SW
byte Byt_Chnb;                            // Channel SW Old
byte Flg_Rit;                             // RIT Flag
byte Flg_Ritb;                            // RIT Flag Old
byte Flg_Tx;                              // TX Flag
byte Flg_Spl;                             // SPLIT Flag
byte Flg_Mode;                            // Mode Flag
byte Byt_Mode;                            // Mode SW
char Byt_Modeb;                           // Mode SW Old
byte Flg_LSB;                             // LSB Flag
byte Flg_USB;                             // USB Flag
byte Flg_CW;                              // CW Flag
byte Flg_SUB;                             // SUB Flag
byte Flg_Over;                            // Over Flag
byte Flg_Ent;                             // ENT Flag
byte Byt_Ent;                             // ENT Mode
byte Flg_If;                              // IF Flag
byte Flg_Vfo;                             // DDS Flag
byte Byt_Vfo;                             // VFO Mode

byte  fill[6]={ 0x20,0x00,0x01,0x02,0x03,0xFF };      // character used to fill (0=empty  5=full)
byte  peak[7]={ 0x20,0x00,0x04,0x05,0x06,0x07,0x20 }; // character used to peak indicator
int   lmax[2];                                        // level max memory
int   dly[2];                                         // delay & speed for peak return

////////////////////////////////
// Special character definition
////////////////////////////////
byte block[8][8]=
{
  { 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 },  // define character for fill the bar
  { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 },
  { 0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C },
  { 0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E },

  { 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08 },  // define character for peak level
  { 0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 },
  { 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 },
  { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },
};

//----------  Initialization  Program  ----------------------

void setup(){
  lcd.init();                                // initialize the lcd
  lcd.backlight();
 
  for( int i=0 ; i<8 ; i++ )
    lcd.createChar( i,block[i] );
 
  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_ENT,INPUT_PULLUP);
  pinMode(SW_RIT,INPUT_PULLUP);
  pinMode(SW_SPLIT,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH,INPUT_PULLUP);
  pinMode(SW_MODE,INPUT_PULLUP);
 
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();                                    // INT Enable

  pinMode(C_UD,OUTPUT);
  pinMode(C_CLK,OUTPUT);
  pinMode(C_DATA,OUTPUT);
  pinMode(V_UD,OUTPUT);
  pinMode(V_CLK,OUTPUT);
  pinMode(V_DATA,OUTPUT);

  Flg_Tx = 0;
  Flg_Rit = 0;
  Flg_Spl = 0;
  lcd.clear();

  if(EEPROM.read(Eep_Int) != Int_End){        // Eep initialaz
    delay(10);
    Fnc_Eep_Int();
  }
  Byt_Chn = EEPROM.read(Chn_Eep);             // Channel
  Byt_Chnb = Byt_Chn;
  Car_Dat = Fnc_Eep_Lod4(Care_Eep+Byt_Mode*4);
  Fnc_Eep_Rd();                              // EEPROM Read
}

//----------  Main program  ---------------------------------

void loop() {
                                              // sqrt to have non linear scale (better was log)
  int anL = map( sqrt( analogRead( IN_LEFT  )*20 ),0,128,0,80 );
  bar( 2,anL );                               // set the cursor 0,2
  lcd.setCursor(0, 3);
  delay(80);
  lcd.print("S1_3_5_7_9_+10_+40db");          // Print a message to the LCD.
 
  if(Flg_Tx == 0){                            // Tx off?
    if(digitalRead(SW_STEP) == LOW)           // STEP Sw On?
      Fnc_Stp();                          
    if(digitalRead(SW_ENT) == LOW)            // ENT SW On?
      Fnc_Ent();                          
    if(Flg_Mode == 0){
      if(digitalRead(SW_RIT) == LOW)          // RIT Sw On?
        Fnc_Rit();                          
      if(Flg_Vfo == 0){
        if(digitalRead(SW_SPLIT) == LOW)      // SPLIT Sw On?
          Fnc_Spl();                        
        if((digitalRead(SW_CH) == LOW))       // CH SW On?
          Fnc_Chsw();                            
      }
    }
    if((digitalRead(SW_MODE) == LOW))        // MODE SW On?
      Fnc_Mode();
    if(Byt_Chnb != Byt_Chn){                 // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
        Flg_Rit = 0;
        Flg_Spl = 0;
    }
    if(Flg_Ent == 1)                         // ENT proc.?
      Fnc_Prm();
  }
  if(digitalRead(SW_TX) == LOW)              // Tx On?
    Flg_Tx = 1;                            
  else                                  
    Flg_Tx = 0;                                          

  if(Flg_Mode == 1)
    Fnc_Care();
  else{
    Fnc_Band(Vfo_Dat+Rit_Dat);              // Range check
    Fnc_If(Byt_Vfo);
    if(Flg_Tx == 0)
      Fnc_Dds(RX_Dat,V_DATA,V_CLK,V_UD);    // AD9850 DDS RX set
    else
      if(Flg_Over == 0)                     // Frequency not range over?
        Fnc_Dds(TX_Dat,V_DATA,V_CLK,V_UD);  // AD9850 DDS TX set
        else                    
          Fnc_Dds(0L,V_DATA,V_CLK,V_UD);    // DDS 0Hz
  }

  Fnc_Dds(Car_Dat,C_DATA,C_CLK,C_UD);      // Career DDS set
  Fnc_Lcd();                               // LCD Display
}

//----------  Encorder procedure(INT)  ----------------------

ISR(PCINT2_vect) {
  unsigned char result = r.process();

  if(Flg_Tx == 0){
    if(result) {  
      if(result == DIR_CW){
        Lng_Wk1 = Vfo_Dat + Enc_Stp;
        Lng_Wk2 = Rit_Dat + Enc_Stp;
      }
      else{
          Lng_Wk1 = Vfo_Dat - Enc_Stp;
          Lng_Wk2 = Rit_Dat - Enc_Stp;
      }    

      if((Flg_Rit == 1) || (Flg_Spl == 1))
        Rit_Dat = Lng_Wk2;
      else{
        Vfo_Dat = Lng_Wk1;
        Rit_Dat = 0;
      }

      Vfo_Dat = constrain(Vfo_Dat,LW_FRQ,HI_FRQ);  // VFO range check
      Rit_Dat = constrain(Rit_Dat,LW_RIT,HI_RIT);  // RIT range check
    }
  }
}

//----------  Function DDS set  -----------------------------

void Fnc_Dds(double frquency,byte dat,byte clk,byte ud){
  unsigned long wrk = frquency * TWO_E32 / DDS_CLK;
 
  digitalWrite(ud,LOW);

  shiftOut(dat,clk,LSBFIRST,wrk);
  shiftOut(dat,clk,LSBFIRST,(wrk >> 8));
  shiftOut(dat,clk,LSBFIRST,(wrk >> 16));
  shiftOut(dat,clk,LSBFIRST,(wrk >> 24));
  shiftOut(dat,clk,LSBFIRST,DDS_CMD);   // AD9850 command

  digitalWrite(ud,HIGH);
}

//----------  LCD Bar Display PROC.  ------------------------

void  bar(int row,int lev){
  lcd.setCursor( 0,row );
  lcd.write( row ? 'R' : 'L' );

  for( int i=1 ; i<20 ; i++ ){
    int f=constrain( lev      -i*5,0,5 );
    int p=constrain( lmax[row]-i*5,0,6 );
    if( f )
      lcd.write( fill[ f ] );
    else
      lcd.write( peak[ p ] );
  }

  if( lev>lmax[row] ){
    lmax[row] = lev;
    dly[row]  = -(T_PEAKHOLD)/T_REFRESH;    // Starting delay value. Negative=peak don't move
  }
  else{
    if( dly[row]>0 )
      lmax[row] -= dly[row];
    if( lmax[row]<0 )
      lmax[row]=0;
    else
      dly[row]++;
  }
}

//----------  Function Encorder STEP  -----------------------

void Fnc_Stp(){
  if(Enc_Stp == 10)                       // Step = 10Hz ?
    Enc_Stp = 1000000;                    //   Yes,1Mhz set
    else
      Enc_Stp = Enc_Stp / 10;             // Step down 1 digit

  Fnc_Step_Disp();
  while(digitalRead(SW_STEP) == LOW)
    ;
}

//----------  Function STEP Display  ------------------------

void Fnc_Step_Disp(){
  lcd.setCursor(0,1);
  switch(Enc_Stp){
    case 10:
      lcd.print("10  ");
      break;
    case 100:
      lcd.print("100 ");
      break;
    case 1000:
      lcd.print("1k  ");
      break;
    case 10000:
      lcd.print("10k ");
      break;
    case 100000:
      lcd.print("100k");
      break;
    case 1000000:
      lcd.print("1M  ");
      break;
    default:
      lcd.print("1k  ");
      Enc_Stp = 1000;
      break;
  }
}

//----------  Function String Dot Edit  ---------------------
 
char *Fnc_Dot_Edit(char *str,long n){
  int  i = 0;                           // Write the number
  char *p = str;
  unsigned long  u = abs(n);

  do{
    *p++ = "0123456789"[u % 10];
    u = u / 10;
    i++;
    if((0 != u) && (0 == (i % 3)))
      *p++ = ',';
  }
  while( 0 != u )
    ;  
  if ( n < 0 )
     *p++ = '-';
   *p = '\0';
   Fnc_Revr( str );
   return str;
}

//----------  Function String Reverse  ----------------------

void Fnc_Revr(char *str){
  int i,n;
  char c;

  n=strlen(str);
  for(i = 0;i < n / 2;i++){
    c=str[i];
    str[i]=str[n - i - 1];
    str[n - i - 1]=c;
  }
}

//----------  Function Save EEPROM 4byte  -------------------

void Fnc_Eep_Sav4(long value,int address){
  address += 3;
  for(int i = 0;i < 4;i++){
    byte toSave = value & 0xFF;
    if(EEPROM.read(address) != toSave){
      EEPROM.write(address,toSave);
    }
    value = value >> 8;
    address--;
  }
}

//----------  Function Load EEPROM 4byte  -------------------

long Fnc_Eep_Lod4(int address){
  long value = 0;

  for(int i = 0;i < 4;i++){
    value = value | EEPROM.read(address);
    if( i < 3){
      value = value << 8;
      address++;
    }
  }
  return value;
}

//----------  Function LCD Display  -------------------------

void Fnc_Lcd(){
  lcd.setCursor(0,0);
  if(Flg_Tx == 1)
    lcd.write('T');
    else if(Flg_Mode == 1)
      lcd.write('C');
      else if(Flg_Ent == 1)
        lcd.write('P');
        else
          lcd.print(Byt_Chn);

  Fnc_Step_Disp();

  if(Flg_Over == 0){
    lcd.setCursor(16,1);
    lcd.print("    ");
  }
     
  if(Flg_Rit == 1){                              // Rit display
    lcd.setCursor(5,1);
    if(Rit_Dat != Rit_Datb){
      lcd.print("R          ");
      Rit_Datb = Rit_Dat;
    }
    lcd.setCursor(6,1);
    if(Rit_Dat >=0)
      lcd.write('+');
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.print(Lcd_Dat);
    lcd.print("Hz");
  }

  if(Flg_Spl == 1){                              // Split display
    lcd.setCursor(5,1);
    if(Rit_Dat != Rit_Datb){
      lcd.print("T          ");
      Rit_Datb = Rit_Dat;
    }
    lcd.setCursor(6,1);
    if(Rit_Dat >=0)
      lcd.write('+');
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.print(Lcd_Dat);
    lcd.print("Hz");
  }

  if((Flg_Rit == 0) && (Flg_Spl == 0)){
    Fnc_Fdsp(Vfo_Dat);
    Fnc_Mdisp();
    if((Flg_Mode == 0) && (Flg_Ent == 0)){
      lcd.setCursor(5,1);
      lcd.print(CALL);
    }
  }
}

//----------  Function Frequency Display  -------------------

void Fnc_Fdsp(long f_disp){
  Fnc_Dot_Edit(Lcd_Dat,f_disp);
  lcd.setCursor(1,0);
  if(f_disp != Vfo_Datb){
    lcd.write(':');
    lcd.print("               ");
    Vfo_Datb = f_disp;
  }

  lcd.setCursor(3,0);
  lcd.print(Lcd_Dat);
  lcd.print("Hz");
}

//----------  Function Rit  ---------------------------------

void Fnc_Rit(){
  if(Flg_Vfo == 0){
    if(Flg_Rit == 0){
      if(Flg_Spl == 1)
        Flg_Spl = 0;
      Flg_Rit = 1;
      lcd.setCursor(5,1);
      lcd.print("R          ");
      if(Rit_Dat >=0){
        lcd.setCursor(6,1);
        lcd.write('+');
        lcd.write('0');
        lcd.print("Hz");
      }
    }
    else{
      lcd.setCursor(5,1);
      lcd.print(CALL);
      Flg_Rit = 0;
      Rit_Dat = 0;
    }
  }
  else
    Byt_Vfo++;

  while(digitalRead(SW_RIT) == LOW)
    ;
}

//----------  Function Channel SW Check  --------------------

void Fnc_Chsw(){
  byte cnt = 0;
 
  Byt_Chn++;
  while(digitalRead(SW_CH) == LOW){
    delay(500);
    cnt++;
    if(6 <= cnt){                            // Eep Initial start(3sec)?
      Fnc_Eep_Int();
      Byt_Chn = EEPROM.read(Chn_Eep);         // Channel
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();                           // EEPROM Read
      lcd.setCursor(0,0);                     // LCD display
      lcd.print(Byt_Chn);
      Fnc_Fdsp(Vfo_Dat);
      lcd.setCursor(5,1);
      lcd.print("Init End  ");
    }
  }
}

//---------- Function Eeprom Initialization -----------------

void Fnc_Eep_Int(){
  int i;

  for (i=0;i<160;i++)                            // 0 clear(160byte)
    EEPROM.write(i, 0);

  for(i=0;i<Max_Chn;i++){
    Fnc_Eep_Sav4(DEF_FRQ,Frq_Eep+i*4);            // Frequency(7.05MHz)
    Fnc_Eep_Sav4(DEF_STP,Stp_Eep+i*4);            // Step(1kHz)
  }

  Fnc_Eep_Sav4(DEF_IF,If_Eep);                    // IF(10.7MHz)
  Fnc_Eep_Sav4(DEF_LSB,Care_Eep+0);               // Career LSB
  Fnc_Eep_Sav4(DEF_USB,Care_Eep+4);               //        USB
  Fnc_Eep_Sav4(DEF_CW,Care_Eep+8);                //        CW
  Fnc_Eep_Sav4(DEF_SUB,Care_Eep+12);              //        SUB
  EEPROM.write(Vfo_Eep,DEF_VFO);                  // Vfo Mode
  EEPROM.write(Eep_Int,Int_End);                  // Init end set(73)
}

//----------  Function EEPROM Read  ------------------------

void Fnc_Eep_Rd(){
  if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep+Byt_Chn*4);
  else{
    Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep+0*4);
    Byt_Chn = 0;
  }

   if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    Enc_Stp = Fnc_Eep_Lod4(Stp_Eep+Byt_Chn*4);
  else
    Enc_Stp = Fnc_Eep_Lod4(Stp_Eep+0*4);

  Vfo_If = Fnc_Eep_Lod4(If_Eep);            // 2016/7/6
  Byt_Mode = EEPROM.read(Mode_Eep+Byt_Chn);      
  Byt_Vfo = EEPROM.read(Vfo_Eep);
}

//----------  Function EEPROM Write  -----------------------

void Fnc_Eep_Wt(byte chn){
  if((0 <= chn) && (chn < Max_Chn)){
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep+chn*4);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep+chn*4);
  }
  EEPROM.write(Chn_Eep,Byt_Chn);
  EEPROM.write(Mode_Eep+chn,Byt_Mode);
}

//----------  Function Split  ------------------------------

void Fnc_Spl(){
  if(Flg_Spl == 0){
    if(Flg_Rit == 1)
      Flg_Rit = 0;
    Flg_Spl = 1;
    lcd.setCursor(5,1);
    lcd.print("T          ");
    if(Rit_Dat >=0){
      lcd.setCursor(6,1);
      lcd.write('+');
      lcd.write('0');
      lcd.print("Hz");
    }
  }
  else{
    lcd.setCursor(5,1);
    lcd.print(CALL);
    Flg_Spl = 0;
    Rit_Dat = 0;
  }

  while(digitalRead(SW_SPLIT) == LOW)
    ;
}

//----------  Function Mode  -------------------------------

void Fnc_Mode(){
  byte cnt = 0;

  Byt_Mode++;
  if(Flg_Mode == 0){
    while(digitalRead(SW_MODE) == LOW){
      delay(500);
      cnt++;
      if(6 <= cnt){                              // Change MODE(3sec)
        lcd.setCursor(0,0);
        lcd.write('C');
        Byt_Mode = 0;                            // LSB set
        Flg_LSB = 0;
        Flg_Spl = 0;
        Flg_Rit = 0;
        Vfo_Save = Vfo_Dat;
        Car_Dat = Fnc_Eep_Lod4(Care_Eep+0);
        Fnc_Fdsp(Car_Dat);
        lcd.setCursor(5,1);
        lcd.print("Career DDS     ");
        Flg_Mode = 1;
      }
    }
  }
  else{
    while(digitalRead(SW_MODE) == LOW){
      delay(500);
      cnt++;
      if((6 <= cnt) && (Byt_Mode == 1)){       // Exit MODE(3sec) and LSB
        Vfo_Dat = Vfo_Save;
        Fnc_Fdsp(Vfo_Dat);
        lcd.setCursor(5,1);
        lcd.print(CALL);
        if(Flg_Over == 1){
          lcd.setCursor(16,1);
          lcd.print("Over");
        }
        Flg_Mode = 0;
        Byt_Mode = 0;                          // LSB set
        lcd.setCursor(0,0);
        lcd.print(Byt_Chn);
      }
    }
  }
}

//----------  Function Career PROC  ------------------------

void Fnc_Care(){
  switch(Byt_Mode){
    case 0:                              // LSB
      if(Flg_LSB == 0){
        Vfo_Dat = Fnc_Eep_Lod4(Care_Eep+0);
        Flg_LSB = 1;
      }
      break;
    case 1:                              // USB
      if(Flg_LSB == 1){
        Fnc_Eep_Sav4(Vfo_Dat,Care_Eep+0);
        Flg_LSB = 0;
      }
      if(Flg_USB == 0){
        Vfo_Dat = Fnc_Eep_Lod4(Care_Eep+4);
        Flg_USB = 1;
      }
      break;
    case 2:                              // CW
      if(Flg_USB == 1){
        Fnc_Eep_Sav4(Vfo_Dat,Care_Eep+4);
        Flg_USB = 0;
      }
      if(Flg_CW == 0){
        Vfo_Dat = Fnc_Eep_Lod4(Care_Eep+8);
        Flg_CW = 1;
      }
      break;
    case 3:                              // SUB
      if(Flg_CW == 1){
        Fnc_Eep_Sav4(Vfo_Dat,Care_Eep+8);
        Flg_CW = 0;
      }
      if(Flg_SUB == 0){
        Vfo_Dat = Fnc_Eep_Lod4(Care_Eep+12);
        Flg_SUB = 1;
      }
      break;
    default:
      if(Flg_SUB == 1){
        Fnc_Eep_Sav4(Vfo_Dat,Care_Eep+12);
        Flg_SUB = 0;
      }
      Byt_Mode = 0;
      break;
  }
  Car_Dat = Vfo_Dat;
}

//----------  Function Mode Display  -----------------------

void Fnc_Mdisp(){
  lcd.setCursor(17,0);
  switch(Byt_Mode){
    case 0:                              // LSB
      lcd.print("LSB");
      break;
    case 1:                              // USB
      lcd.print("USB");                
      break;
    case 2:                              // CW
      lcd.print("CW ");                
      break;
    case 3:                              // SUB
      lcd.print("SUB");                
      break;
    default:
      Byt_Mode = 0;
      lcd.print("LSB");
      break;
  }
  Car_Dat = Fnc_Eep_Lod4(Care_Eep+Byt_Mode*4);
  EEPROM.write(Mode_Eep+Byt_Chn,Byt_Mode);
}

//----------  Function Band  -------------------------------

void Fnc_Band(long vfo){
  if((Flg_Mode == 0) && (Flg_Ent == 0)){
    if((vfo >= LW_VFO80) && (vfo <= HI_VFO80))
      Flg_Over = 0;
      else if((vfo >= LW_VFO40) && (vfo <= HI_VFO40))
        Flg_Over = 0;
        else if((vfo >= LW_VFO20) && (vfo <= HI_VFO20))
          Flg_Over = 0;
          else if((vfo >= LW_VFO15) && (vfo <= HI_VFO15))
            Flg_Over = 0;
            else if((vfo >= LW_VFO10) && (vfo <= HI_VFO10))
              Flg_Over = 0;
              else{
                lcd.setCursor(16,1);
                lcd.print("Over");
                Flg_Over = 1;
              }
  }
  else
    Flg_Over = 0;
}

//----------  Function ENT  --------------------------------

void Fnc_Ent(){
  byte cnt = 0;

  if(Flg_Ent == 0){
    Fnc_Eep_Wt(Byt_Chn);
    while(digitalRead(SW_ENT) == LOW){
      delay(500);
      cnt++;
      if(6 <= cnt){                              // Parameter change mode(3sec)
        lcd.setCursor(0,0);
        lcd.print("P");
        Flg_Ent = 1;
        Flg_Rit = 0;
        Flg_Spl = 0;
        Byt_Ent = 0;
        if(Flg_If == 0){
          Vfo_Save = Vfo_Dat;
          Vfo_Dat = Fnc_Eep_Lod4(If_Eep);
          Flg_If = 1;
        }
        Fnc_Fdsp(Vfo_Dat);
        lcd.setCursor(5,1);
        lcd.print("IF             ");
      }
    }
  }
  else{
    while(digitalRead(SW_ENT) == LOW){
      delay(500);
      cnt++;
      if(6 <= cnt){                              // Return Parameter cahne mode(3sec)
        lcd.setCursor(0,0);
        lcd.print(Byt_Chn);
        Flg_Ent = 0;
        Flg_Vfo = 0;
        Flg_If = 0;
        Vfo_Dat = Vfo_Save;
        Fnc_Fdsp(Vfo_Dat);
        lcd.setCursor(5,1);
        lcd.print(CALL);
        EEPROM.write(Vfo_Eep,Byt_Vfo);
      }
      else
        Byt_Ent++;
    }
  }
}

//----------  Function Prameter PROC  ----------------------

void Fnc_Prm(){
  lcd.setCursor(5,1);
  switch(Byt_Ent){
    case 0:                                       // IF Set
      if(Flg_If == 0){
        Vfo_Dat = Fnc_Eep_Lod4(If_Eep);
        Flg_If = 1;
      }
      lcd.setCursor(5,1);
      lcd.print("IF         ");
      break;
    case 1:                                      // VFO Mode Set
      if(Flg_If == 1){
        Fnc_Eep_Sav4(Vfo_Dat,If_Eep);
        Vfo_If = Vfo_Dat;
        Flg_If = 0;
      }
      if(Flg_Vfo == 0){
        Byt_Vfo = EEPROM.read(Vfo_Eep);          // Vfo Mode data
        if(Byt_Vfo < 0)
          Byt_Vfo = 0;
        Flg_Vfo = 1;
      }
      lcd.setCursor(10,1);
      switch(Byt_Vfo){
        case 0:
          lcd.print("Roff  ");                  // TX=VFO RX=0
          break;
        case 1:
          lcd.print("TR    ");                  // TX=VFO RX=VFO
          break;
        case 2:
          lcd.print("R+IF  ");                  // TX=VFO RX=VFO+IF
          break;
        case 3:
          lcd.print("TR+IF ");                  // TX=VFO+IF RX=VFO+IF
          break;
        default:
          Byt_Vfo = 0;
          lcd.print("Roff  ");
          break;
      }
      lcd.setCursor(5,1);
      lcd.print("VFO  ");
      break;
    default:
      if(Flg_Vfo == 1){
        EEPROM.write(Vfo_Eep,Byt_Vfo);
        Flg_Vfo = 0;
      }
      lcd.setCursor(5,1);
      lcd.print("IF         ");
      Byt_Ent = 0;
      break;
  }
}

//----------  Function IF Proc.  ---------------------------

void Fnc_If(byte if_mode){
  switch(if_mode){
    case 0:                             // Roff
      RX_Dat = 0L;                      // RX = off
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;
    case 1:                             // TR
      RX_Dat = Vfo_Dat;                 // RX = VFO
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;
    case 2:                             // R+IF
      RX_Dat = Vfo_Dat + Vfo_If;        // RX = VFO + IF
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;
    case 3:                             // TR+IF
      RX_Dat = Vfo_Dat + Vfo_If;        // RX = VFO + IF
      TX_Dat = Vfo_Dat + Vfo_If;        // TX = VFO + IF
      break;
    default:
      RX_Dat = 0L;                      // RX = off
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;
    }
  if((RX_Dat != 0) && (Flg_Rit == 1))
    RX_Dat = RX_Dat + Rit_Dat;
  if(Flg_Spl == 1)
    TX_Dat = TX_Dat + Rit_Dat;
}