2015年12月24日木曜日

Arduino Dip_Meter

Arduino nanoを使って、周波数カウンターとレベルメータの機能を持たせたディップメータ。秋月のクリアケースに収納し、ケース加工を最小限にした。周波数調整は、アクリル板を回す構造とし、アナログ感覚の操作性を目論んだ。まだコイルを作ってないが、動作範囲1-60MHz。
また、ディップが浅い問題があり、プログラム改修で対応したいと思っている。 
USB接続が出来る様、側面に穴あけ加工した。この事で、プログラムのメンテナンスが容易になった。 
カウンターは、1/10プリスケーラにより、60MHz程の周波数を測定。 

基板サイズ 80x86 



















Program

Arduinoの周波数カウンターサンプルを使用し、13.2MHz基準周波数でキャリブレーションしている。ただ、Arduinoボードの個体差(クロック)があるので、要調整。


/////////////////////////////////////////////////////////////////////////////////
//  Frequency counters and level meter
//
//    Copyright(C)2015.JA2GQP.All rights reserved.
//
//                                                  2015/12/22
//                                                  JA2GQP
//-----------------------------------------------------------------------------
// Arduino Frequency Counter Library
// http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-frequency-counter-library/
//
/////////////////////////////////////////////////////////////////////////////////

#include <LiquidCrystal.h>
#include <FreqCounter.h>

#define LCDCOLS 16

LiquidCrystal lcd(8, 7,  6, 4, 3, 2);

long int frq;
double cal;

byte one[8] = {                                   // Special character 1
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
};

byte two[8] = {                                   // Special character 2
  B10100,
  B10100,
  B10100,
  B10100,
  B10100,
  B10100,
  B10100,
};

byte three[8] = {                                 // Special character 3
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
};

//
//-------------------------------------------- Setup proc ---------------------------------------------------------------------
//

void setup() {
   cal = 13.2 / 13.2799;                          // Calibrat frequency
  lcd.begin(LCDCOLS, 2);
  lcd.clear();
 
  lcd.createChar(1, one);
  lcd.createChar(2, two);
  lcd.createChar(3, three);
 
  analogReference(DEFAULT);

  delay(200);
}


//
//-------------------------------------------- Main Loop ---------------------------------------------------------------------
//

void loop() {
  int v;
  static unsigned long t = 0;
 
  FreqCounter::f_comp = 8;                        // Set compensation to 12
  FreqCounter::start(100);                        // Start counting with gatetime of 100ms
  while (FreqCounter::f_ready == 0);              // wait until counter ready
  frq = FreqCounter::f_freq;                      // read result

  lcd.clear();                                       // clear screen(cursol 0,0)
  lcd.print(frq * cal / 10000);                   // Frequency display
  lcd.print("MHz");

  v = analogRead(0);                              // Anarog data get
  printbar(v,16);                                  // Bar display for 16 column

  lcd.setCursor(10, 0);                           // Analog Volt display
  lcd.print(5.0/1023*v);                          // Voltage display
  lcd.print("V");
  delay(80);

}


//
//-------------------------------------------- Bar display for line2 ----------------------------------------------------------
//

void printbar(int ad_value, int disp_digit) {
  int p;
  int s;
  int i;
  int bar;
  int res;
  int bar_value;
 
  bar = disp_digit * 3;
  res = 1023.0 / bar + 0.5;
  bar_value = (float)ad_value / res + 0.5;
  p = bar_value / 3;
  s = bar_value % 3;
  lcd.setCursor(0, 1);

  for (i = 0; i < p; i++)
    lcd.write(3);

  if (s)
    lcd.write(s);
    else
      lcd.print(' ');

  for (i = 0; i < LCDCOLS - p - 1; i++)
    lcd.print(' ');
}




    

2015年11月27日金曜日

Antenna Analyzer 2.2"TFTケース

アンテナアナライザPCBを秋月電子ABS樹脂ケース(112-TS)に収納した。タクトスイッチは、同じく秋月のP-03648に、タクトスイッチキャップを2段重ね、操作部がケース全面より1mm位出る様にした。ケース蓋は、背面側にして、BNCコネクタが蓋に干渉することなく、付ける事が出来た。
 

左側。
中央にUSBコネクタ。

 

下側。
タクトスイッチキャップは2個貼り合わせて高さを調整した。基板とケース固定に使っているスペーサは、17mmに調整。
  


右側。
ケース蓋が背面側に開く。 
 

2015年11月26日木曜日

Antenna Analyzer 2.2"TFT

 Arduino nanoとAD9850 DDS Moduleを使ったアンテナアナライザで、 K6BEZ開発をDG7EAOがTFTを使ってスタンドアーロンでも使える様に改造した物である。このTFT付きアナライザは、PCリンク、スタンドアーロンでも使える優れもので、電源はUSB経由。
DG7EAOサイトの説明は断片的で,単純に真似してもIO割り付けに整合性がなく、動作しない。そのため、回路図、PCB、スケッチに矛盾が無く動作する様、纏めた。
実装基板は、秋月電子のアクリルケースに収納できるサイズとした。





部品実装基板。
TFTは、高さ8.5のピンソケット。DDSとnanoは、高さ3.5のピンソケットを使った。
抵抗0Ω(4本)は、ジャンパー。







 

回路図。
ダイオードは、1N60を使用。入手困難な部品がないので、簡単に作れる筈。


                  基板サイズ 80x112
        



















Program

コメントに字下げなどの工夫がなくて読みづらく、一部書換を行ったが、プログラム変更は3点である。

/***************************************************************************\
*  Name    : DDS_Sweeper.BAS                                                               *
*  Author  : Beric Dunn (K6BEZ)                                                              *
*  Notice  : Copyright (c) 2013  CC-BY-SA                                                 *
*          : Creative Commons Attribution-ShareAlike 3.0 Unported License                        *
*  Date    : 9/26/2013                                                                                              *
*  Version : 1.0                                                                                                         *
*  Notes   : Written using for the Arduino Micro                                                            *
*          :   Pins:                                                                                                       *
*          :   A0 - Reverse Detector Analog in                                                                *
*          :   A1 - Forward Detector Analog in                                                               *
*          : Modified by Norbert Redeker (DG7EAO) 07/2014                                            *
*          : TFT Display mit ILI9341 Chip, SPI, 240 x 320                                                  *
*          : usglib Grafik Bibliothek   https://code.google.com/p/ucglib/                             *
*---------------------------------------------------------------------------*
* Modification: 2015/11/26 JA2GQP                                                                          *
*   A1)DDS Pin Assign                                                                                             *
*   A2)Ucglib_ILI9341_18x240x320_SWSPI Parameters                                                   *
*   A3)DDS Reset Sequence                                                                                     *
\***************************************************************************/

#include <SPI.h>
#include "Ucglib.h"

// Define Pins used to control AD9850 DDS
//const int FQ_UD=10;                  // N6BEZ
//const int SDAT=11;
//const int SCLK=9;
//const int RESET=12;

//const int FQ_UD=9;                   // DG7EAO
//const int SDAT=11;
//const int SCLK=10;
//const int RESET=12;

const int FQ_UD=11;                    //A1)DDS Pin Assign JA2GQP
const int SDAT=10;                     //
const int SCLK=12;                     //
const int RESET=9;                     //

// Variablen für Display
double vswrArray[110];                //Array für SWR
int z = 0;                                // Index für Array
double SwrFreq = 14;                  // Variable für Freq. mit SWR Min.
double SwrMin = 100;                  // Variable für SWR Min.
double Freq1 = 1;                       // Freq. Links unterste Zeile Display
double Freq2 = 15;                     // Freq. Mitte unterste Zeile Display
double Freq3 = 30;                     // Freq. Mitte unterste Zeile Display
unsigned long milliold = 0;            //Millisekunden für Entprellung Interrupt
unsigned long millinew = 0;           //Millisekunden für Entprellung Interrupt
int flag = 0;                            // wir auf 1 gesetzt bei Interrupt, in void Loop perform_sweep
double counter = 0;                    // Zähler um erste Interrupts zu ignorieren

// Variablen für Messung
double Fstart_MHz = 1;                 // Start Frequency for sweep
//double Fstop_MHz = 10;             // Stop Frequency for sweep
double Fstop_MHz = 30;                // Stop Frequency for sweep
double current_freq_MHz;              // Temp variable used during sweep
long serial_input_number;              // Used to build number from serial stream
int num_steps = 100;                    // Number of steps to use in the sweep
char incoming_char;                     // Character read from serial stream


//Konstruktor für Display
//Ucglib_ILI9341_18x240x320_SWSPI ucg(/*sclk=*/ 10, /*data=*/ 11, /*cd=*/ 6 , /*cs=*/ 5, /*reset=*/ 4);             // DG7EAO
Ucglib_ILI9341_18x240x320_SWSPI ucg(/*sclk=*/ 8, /*data=*/ 7, /*cd=*/ 6 , /*cs=*/ 5, /*reset=*/ 4);             //A2) JA2GQP



// the setup routine runs once when you press reset:----------------------------------
void setup() {

  // Schreibe Info Text auf Display
  //ucg.begin(UCG_FONT_MODE_TRANSPARENT);
  ucg.begin(UCG_FONT_MODE_SOLID);
  ucg.clearScreen();

  ucg.setRotate90();
  ucg.setFont(ucg_font_ncenR14r);
  //ucg.setColor(255, 255, 255);       //weiss
  //ucg.setColor(255, 0, 0);            //rot
  ucg.setColor(0, 255, 0);               //grün
  //ucg.setColor(1, 255, 0,0);          // rot, Index1

  ucg.setPrintPos(0,75);
  ucg.print("Arduino");
  ucg.setPrintPos(10,100);
  ucg.print("Antennen");
  ucg.setPrintPos(20,125);
  ucg.print("Analyzer");
  ucg.setPrintPos(30,150);
  ucg.print("DG7EAO");



  // Configiure DDS control pins for digital output
  pinMode(FQ_UD,OUTPUT);
  pinMode(SCLK,OUTPUT);
  pinMode(SDAT,OUTPUT);
  pinMode(RESET,OUTPUT);

  //Tasten Interrupt an PIN 2
  pinMode(2,OUTPUT);
  digitalWrite(2, HIGH);
  attachInterrupt(0, key2, FALLING);
  unsigned long milliold = millis();

  //Tasten Interrupt an PIN 3
  pinMode(3,OUTPUT);
  digitalWrite(3, HIGH);
  attachInterrupt(1, key3, FALLING);
  //milliold = millis();

  // Configure LED pin for digital output
  pinMode(13,OUTPUT);


  pinMode(A0,INPUT);                   // Set up analog inputs on A0 and A1
  pinMode(A1,INPUT);
  analogReference(INTERNAL);      //internal reference voltage

  Serial.begin(57600);                  // initialize serial communication at 57600 baud


  // Reset the DDS
  //digitalWrite(RESET,HIGH);          // N6BEZ
  //digitalWrite(RESET,LOW);

  digitalWrite(RESET,HIGH);            //A3)DDS Reset Sequence JA2GQP
  delay(1);                                //                          
  digitalWrite(RESET,LOW);             //
                                            //
  digitalWrite(SCLK,HIGH);             //        
  digitalWrite(SCLK,LOW);              //
  digitalWrite(FQ_UD,HIGH);             //
  digitalWrite(FQ_UD,LOW);              //

  serial_input_number=0;                //Initialise the incoming serial number to zero

}

// the loop routine runs over and over again forever:----------------------------------
void loop() {


  //Check for character
  if(Serial.available()>0){
    incoming_char = Serial.read();
    switch(incoming_char){
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      serial_input_number=serial_input_number*10+(incoming_char-'0');
      break;
   
    case 'A':                          //Turn frequency into FStart
      Fstart_MHz = ((double)serial_input_number)/1000000;
      serial_input_number=0;
      break;
   
    case 'B':                          //Turn frequency into FStop
      Fstop_MHz = ((double)serial_input_number)/1000000;
      serial_input_number=0;
      break;
   
    case 'C':                          //Turn frequency into FStart and set
                                        //  DDS output to single frequency
      Fstart_MHz = ((double)serial_input_number)/1000000;
                                     
      SetDDSFreq(Fstart_MHz * 1000000);//SetDDSFreq(Fstart_MHz);
      delay(100);
      SetDDSFreq(Fstart_MHz * 1000000);
      serial_input_number=0;  
      break;
   
    case 'N':                         // Set number of steps in the sweep
      num_steps = serial_input_number;
      serial_input_number=0;
      break;
   
    case 'S':  
    case 's':  
      Perform_sweep();
      break;
   
    case '?':                        // Report current configuration to PC
      Serial.print("Start Freq:");
      Serial.println(Fstart_MHz*1000000);
      Serial.print("Stop Freq:");
      Serial.println(Fstop_MHz*1000000);
      Serial.print("Num Steps:");
      Serial.println(num_steps);
      break;
    }
    Serial.flush();  
  }

 if (flag == 1 && counter >2)         //Perform Sweep nach Interrupt PIN2 oder 3
{                                         // ingnoriere Startup Interrupts durch counter
 flag = 0;
 Perform_sweep();
}
}


void Perform_sweep(){
  double FWD=0;
  double REV=0;
  double VSWR;
  double Fstep_MHz = (Fstop_MHz-Fstart_MHz)/num_steps;

  z = 0;
  SwrMin = 100;

  ucg.setPrintPos(220,150);
  ucg.print("... Starte");
  ucg.clearScreen();
 
  for(int i=0;i<=num_steps;i++){                     // Start loop
    current_freq_MHz = Fstart_MHz + i*Fstep_MHz;// Calculate current frequency
    SetDDSFreq(current_freq_MHz*1000000);       // Set DDS to current frequency
    //delay(10);                                       // Wait a little for settling
    delay(100);
    REV = analogRead(A0);                    // Read the reverse voltages
    FWD = analogRead(A1);                   //          forward voltages
 
    REV = REV-5;                                //Offset Correction
     
    if(REV>=FWD){REV = FWD-1;}
 
    if (REV <1) {REV = 1;}

    VSWR = (FWD+REV)/(FWD-REV);
    VSWR = VSWR * 1000;                         //Scale Output
 
    Serial.print(current_freq_MHz*1000000);    // Send current line back to PC over serial bus
    Serial.print(",0,");
    Serial.print(VSWR);
    Serial.print(",");
    Serial.print(FWD);
    Serial.print(",");
    Serial.println(REV);
 

    vswrArray[z] = VSWR/1000;                   //Submitter SWR to Array
     
    if (vswrArray[z] > 10) vswrArray[z] = 10;   //Max SWR
 
    if (vswrArray[z] < SwrMin && vswrArray[z] > 1){  //Minimum SWR
      SwrMin = vswrArray[z];                         //Minimum SWR and frequency store
      SwrFreq = current_freq_MHz;            
    }  
 
    z = z + 1;
  }

  // Send "End" to PC to indicate end of sweep
  Serial.println("End");
  Serial.flush();

  //Zeichne Grid
  CreateGrid();

  //Linienfarbe = rot
  ucg.setColor(255, 0, 0);            //rot
 
  // Draw Line

  // 30 = swr 10    210 = swr 0
  // Diff swr 10 = 180
  // swr 2 = 18 * 2

  double last = 10;
  double xx = 6;
  int j = 1;

  for (int i = 1 ;i < 103; i++){
    xx = vswrArray[i];

    ucg.drawLine(j,210-last*18, j+1, 210-xx*18);
    ucg.drawLine(j+1,210-last*18, j+2, 210-xx*18);

    j = j + 3;
    last = xx;
  }  
}



// Setze DDS Frequenz-----------------------------------------------------------------
void SetDDSFreq(double Freq_Hz){
  int32_t f = Freq_Hz * 4294967295/125000000;  // Calculate the DDS word - from AD9850 Datasheet
  for (int b=0;b<4;b++,f>>=8){                 // Send one byte at a time
    send_byte(f & 0xFF);
  }
  send_byte(0);                                  // 5th byte needs to be zeros(AD9850 Command Parameters)                            
  digitalWrite(FQ_UD,HIGH);                    // Strobe the Update pin to tell DDS to use values
  digitalWrite(FQ_UD,LOW);
}

// Sende Daten an DDS-----------------------------------------------------------------
void send_byte(byte data_to_send){
  for (int i=0; i<8; i++,data_to_send>>=1){   // Bit bang the byte over the SPI bus
    digitalWrite(SDAT,data_to_send & 0x01);   // Set Data bit on output pin
    digitalWrite(SCLK,HIGH);                  // Strobe the clock pin
    digitalWrite(SCLK,LOW);
  }
}


//Zeichne Grid auf TFT Display--------------------------------------------------------
void CreateGrid(){
  //ucg.clearScreen();

  double maxSwr = 10;

  ucg.drawHLine(0,120,310);
  ucg.drawHLine(0,196,310);
             
  ucg.drawVLine(78,30,180);
  ucg.drawVLine(155,30,180);
  ucg.drawVLine(233,30,180);

  ucg.setPrintPos(0, 235);
  ucg.print(Freq1,3);

  ucg.setPrintPos(130, 235);
  ucg.print(Freq2,3);

  ucg.setPrintPos(260, 235);
  ucg.print(Freq3,3);

  ucg.setPrintPos(10, 15);
  ucg.print("SWR");

  ucg.setPrintPos(70, 15);
  ucg.print(SwrMin,2);

  ucg.setPrintPos(115, 15);
  ucg.print(">");

  ucg.setPrintPos(130, 15);
  ucg.print(maxSwr,2);

  ucg.setPrintPos(250, 15);
  //ucg.print((freqCenter/1000000*1.05),3);
  ucg.print(SwrFreq,3);
     
  ucg.drawRFrame(0,30,310,180, 1);

}

// Interrupt Service Routine----------------------------------------------------------
// Abfrage Low an Pin 2
void key2(){
  counter = counter + 1;                //ignoriere Startup Interrupts > counter

  //Entprellen mit millis()
  millinew = millis();

  if (millinew - milliold < 1000){
    milliold = millinew;
   return;
  }

  milliold = millinew;

  Fstart_MHz = 1;                      // Start Frequency for sweep
  Fstop_MHz = 30;                      // Stop Frequency for sweep
  num_steps = 102;                     // Steps
  Freq1 = 1;                            // Unterste Zeile Display Freq. Links
  Freq2 = 15;                           // Unterste Zeile Display Freq. Mitte
  Freq3 = 30;                           // Unterste Zeile Display Freq. Recht

  //Perform_sweep();
  flag = 1;

}

// Interrupt Service Routine----------------------------------------------------------
// Abfrage Low an Pin 3
void key3()
{
  counter = counter + 1;               //ignoriere Startup Interrupts > counter

  millinew = millis();                   //Entprellen mit millis()
  
  if (millinew - milliold < 1000){
    milliold = millinew;
    return;
  }

  milliold = millinew;

  int x = SwrFreq + 0.5;               //Runde auf Mhz

  Fstart_MHz = x-1;                    // Start Frequency for sweep
  Fstop_MHz = x+1;                     // Stop Frequency for sweep
  num_steps = 102;                     // Steps

  Freq1 = x-1;                          // Unterste Zeile Display Freq. Links
  Freq2 = x;                            // Unterste Zeile Display Freq. Mitte
  Freq3 = x+1;                          // Unterste Zeile Display Freq. Rechts

  //Perform_sweep();
  flag = 1;

}





2015年10月9日金曜日

TA7358 X'tal Converter

TA7358を使ったクリコン。50MHz用として作ったが、coilと水晶を選べば、簡単に目的の周波数の物が出来る。coilは、手巻き品の為、FCZ coilデータの通り、巻いた。 ファイルは、JA2GQP's Download siteに全てupしてある。(FCZ coilは、data sheetホルダー) 

回路図である。電源は、供給電圧の自由度からレギュレータなどを入れてない。50MHz IF7.3MHzとしたが、この周波数に拘る事は無い。 

     PCBサイズ 47 × 43 

2015年10月4日日曜日

DSP6959 50MHz AM RX

DSP6959を使った50MHz AM受信機である。DSP6959を親機に、TA7358のクリコンと組合わせた。親機の受信周波数が連続してない為、希望の受信周波数に見合う水晶発振子を選らばなければならない。手持ちの水晶発振子から10.24MHz(4逓倍の40.96MHz)、43.3MHzの2候補があった。両方共コンバータとして動作させる事が出来たが、感度重視で43.3MHzを選んだ。また、チューニング用ボリュームとシリーズの抵抗は、受信範囲を狭くする為に入れてある。その結果、受信範囲50.485MHz~50.650MHzとなった。 
回路図である。スピーカは、ROUTまたはLOUTとGNDに繋ぐのではなく、ROUTとLOUTに繋ぐ。これを間違えるると3V時、0.23A位の電流が流れる。本機の電流は、0.04A~0.06A。
 
基板サイズ 82 x 47            

2015年9月9日水曜日

Arduino AD9834 DDS VFO PCB版

Arduino AD9850 VFOのプログラムを移植。開発は、Arduino IDE1.6.5r5で行ったが、相変わらずlcd.printにバグがある。プログラムは、このバグ対策済。

回路図である。2次高調波低減の為、バッファアンプのベース抵抗を2.2kから4.7k。(プロトタイプの回路図と同じ)













Bug改修部分

修正前
 Arduino IDE 1.0.Xで、正常表示するが、IDE1.6.Xで誤表示する。

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

void Fnc_Step_Disp(){
  lcd.setCursor(0,1);
  lcd.print("    ");                    // Clear step display
  lcd.setCursor(0,1);
  if(1 <= (Enc_Stp / 1000)){            // kiro?          
    lcd.print(Enc_Stp / 1000);          //   Yes,Convert kiro
    lcd.print("k");
    }
    else{
      lcd.print(Enc_Stp);
      }
}


修正後
 IDEのバージョンに関係なく、正常表示する様、モジュールを変更。

//----------  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;
  }
}

program

Arduino AD9850 DDS VFOを移植。Fnc_Dds以外殆ど同じ。

//////////////////////////////////////////////////////////////////////
//  AD9834 DDS VFO Premixed type program ver.1.0
//
//    Copyright(C)2014.JA2GQP.All rights reserved.
//
//      7.000MHz to 7.200MHz Limitted.
//      (Target frequency = IF frquency + frequency)
//                                                  2014/12/29
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.Upper Heterodyne(Target Frequency = IF Frequency + Frequency)
//    2.RIT Operation(-50kHZ to 50kHZ)
//    3.STEP(100k,10k,1k,100,10)
//    4.Memory Operation is Push RIT
//      (Frequency and Step)
//    5.Protection Operation At The Time Of Transmission
//    6.Channel Memory.Main Channel(Ch0) + 3 Channel(Ch1,Ch2,Ch3)
//    7.Split Operation(7.00MHz to 7.20MHz Limited!)
//--------------------------------------------------------------------
//  Bug fix
//    1.2015/9/9 Arduino IDE 1.6.X lcd.print Fnc_Step_Disp()
//////////////////////////////////////////////////////////////////////

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

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

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for
                                   // a 16 chars and 2 line display

//----------  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_STEP = 7;                   // STEP Sw
const byte  SW_RIT = 8;                    // RIT Sw
const byte  SW_SPLIT = 9;                  // SPLIT Sw
const byte  SW_CH1 = 10;                   // Channel 1
const byte  SW_CH2 = 11;                   //         2
const byte  SW_CH3 = 12;                   //         3
const byte  SW_TX = 13;                    // TX Sw

const long  IF_FRQ = 9996500L;             // IF Frequency
const long  LW_FRQ = 7000000L;             // Lower Limit
const long  HI_FRQ = 7200000L;             // Upper Limit
const long  DEF_FRQ = 7050000L;            // Init Frequency
const long  DEF_STP = 1000L;               // Init STEP
const long  LW_RIT = -50000L;              // RIT Lower Limit
const long  HI_RIT = 50000L;               //     Upper Limit
const long  LW_VFO = IF_FRQ + LW_FRQ;      // Vfo Lower Limit
const long  HI_VFO = IF_FRQ + HI_FRQ;      //     Upper Limit
const long  DEF_VFO = IF_FRQ + DEF_FRQ;    // Vfo Default Frequency

const unsigned long  DDS_CLK = 56000000L;  // AD9834 Clock 56Mhz
const unsigned long  TWO_E28 = 268435456L; // 2^28

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

const byte  Frq_Eep0 = 0x00;               // Frequency Ch0
const byte  Frq_Eep1 = 0x04;               //           Ch1                                                
const byte  Frq_Eep2 = 0x08;               //           Ch2
const byte  Frq_Eep3 = 0x0c;               //           Ch3

const byte  Stp_Eep0 = 0x10;               // STEP Ch0
const byte  Stp_Eep1 = 0x14;               //      Ch1                                                
const byte  Stp_Eep2 = 0x18;               //      Ch2
const byte  Stp_Eep3 = 0x1c;               //      Ch3

//----------  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 Dds_Dat = 0;                         // DDS Data
long Rit_Dat = 0;                         // RIT Data
long Rit_Datb = 0;                        // RIT Data Old
long Enc_Stp = 0;                         // STEP
long Lng_Wk1 = 0;                         // Long Work1
long Lng_Wk2 = 0;                         // Long Work2

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

byte Byt_Chn = 0;                         // Channel SW
byte Byt_Chnb = 0;                        // Channel SW Old
byte Flg_Rit = 0;                         // RIT Flag
byte Flg_Ritb = 0;                        // RIT Flag Old
byte Flg_Tx = 0;                          // TX Flag
byte Flg_Spl = 0;                         // SPLIT Flag

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

void setup(){
  lcd.init();                            // initialize the lcd 
  lcd.backlight();                       // LCD backlight on

  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_RIT,INPUT_PULLUP);
  pinMode(SW_SPLIT,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH1,INPUT_PULLUP);
  pinMode(SW_CH2,INPUT_PULLUP);
  pinMode(SW_CH3,INPUT_PULLUP);

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

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

  Flg_Tx = 0;
  Flg_Rit = 0;
  Flg_Spl = 0;
  
  lcd.clear();
  Fnc_Chsw();                                // Channel Sw Read
  Byt_Chnb = Byt_Chn;
  Fnc_Eep_Rd();                              // EEPROM Read
}

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

void loop() {
  if(Flg_Tx == 0){                          // Tx off?
    if(digitalRead(SW_STEP) == LOW){        // STEP Sw On?
      Fnc_Stp();                            //     Yes,STEP proc.
    }
    if(digitalRead(SW_RIT) == LOW){         // RIT Sw On? 
      Fnc_Rit();                            //     Yes,RIT proc.
    }
    if(digitalRead(SW_SPLIT) == LOW){       // SPLIT Sw On?
      Fnc_Spl();                            //     Yes,SPLIT proc.
    }
    Fnc_Chsw();                             // Channel Sw read
    
    if(Byt_Chnb != Byt_Chn){                // Channnel SW Chenge?
      if(Byt_Chnb == 0){                    // Channnel 0?      
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep0);     //   Yes,Vfo_Dat Save
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep0);     //       Enc_Step Save
        Flg_Ritb = Flg_Rit;
        Rit_Datb = Rit_Dat;
        Flg_Rit = 0;
        Flg_Spl = 0;
        Rit_Dat = 0;
      }
      
      if(Byt_Chnb != 0){                    // Other(Ch1-Ch3) Channnel? 
        Flg_Rit = 0;
        Flg_Spl = 0;
        if((Byt_Chn == 0) && (Flg_Ritb == 1)){  
          Flg_Rit = 1;
          Rit_Dat = Rit_Datb;
        }
      }
        
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
    }
  }
  if(digitalRead(SW_TX) == LOW){            // Tx On?
    Flg_Tx = 1;                             //    Yes,Flg_Tx Set
  }
  else{                                     
    Flg_Tx = 0;                            //     No,Flg_Tx Reset                
  }

  if(Flg_Rit == 1){                        // RIT?
    Dds_Dat = Vfo_Dat + Rit_Dat;           //    Yes,Dds_Dat Set
  }
  else{
    Dds_Dat = Vfo_Dat;                     //    No,Dds_Dat Set
  }

  if(Flg_Tx == 1){                         // Tx?
    if(Flg_Spl == 1){                      // SPLIT?
      Dds_Dat = Vfo_Dat + Rit_Dat;         //    Yes,Dds_Dat Set
    }
      else{
        Dds_Dat = Vfo_Dat;                 //    No,Dds_Dat Set
      }
  }
  Fnc_Dds(Dds_Dat);                        // AD9850 DDS Out
  Fnc_Lcd();                               // LCD Display
  delay(100);
}  

//----------  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_VFO,HI_VFO);

      if(Flg_Spl == 1){
        Rit_Dat = constrain(Rit_Dat,(LW_VFO - Vfo_Dat),(HI_VFO - Vfo_Dat));
      }
      else{
        Rit_Dat = constrain(Rit_Dat,LW_RIT,HI_RIT);
      }
    }
  }
}

//----------  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);                       // Added 2014/12/29
  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 = 100000;                     //   Yes,100khz set
    }
    else{
      Enc_Stp = Enc_Stp / 10;             // Step down 1 digit
      }
  delay(250);
  Fnc_Step_Disp();
  Fnc_Lcd();
  while(digitalRead(SW_STEP) == LOW)
    ;
  delay(250);
}

//----------  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;
  }
}

//----------  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 2byte  ---------

void Fnc_Eep_Sav2(unsigned int value,int address){
  address += 1;
  for(int i = 0;i < 2;i++){
    byte toSave = value & 0xFF;
    if(EEPROM.read(address) != toSave){
      EEPROM.write(address,toSave);
      }
    value = value >> 8;
    address--;
  }
}

//----------  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 2byte  ---------

unsigned int  Fnc_Eep_Lod2(int address){
  unsigned int value = EEPROM.read(address);
  value = value << 8;
  return value | EEPROM.read(address + 1);
}

//----------  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(){
  if(Flg_Tx == 1){
    lcd.setCursor(0,0);
    lcd.print("T");
  }
  else{
    lcd.setCursor(0,0);
    lcd.print(Byt_Chn);
  }
  
  Fnc_Step_Disp();

  if(Flg_Rit == 1){
    lcd.setCursor(5,1);
    lcd.print("R:          ");
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.setCursor(7,1);
    lcd.print(Lcd_Dat);
    if((Rit_Dat >= 1000) || (Rit_Dat <= -1000)){
     lcd.print("k");
    }
  }

  if(Flg_Spl == 1){
    lcd.setCursor(5,1);
    lcd.print("X:          ");
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.setCursor(7,1);
    lcd.print(Lcd_Dat);
    if((Rit_Dat >= 1000) || (Rit_Dat <= -1000)){
      lcd.print("k");
    }  
  }

  if((Flg_Rit == 0) && (Flg_Spl == 0)){
    Fnc_Dot_Edit(Lcd_Dat,Vfo_Dat - IF_FRQ);
    lcd.setCursor(1,0);
    lcd.print(":              ");
    lcd.setCursor(3,0);
    lcd.print(Lcd_Dat);
    lcd.print("MHz");

    lcd.setCursor(5,1);
    lcd.print("     JA2GQP");
  }
}
  

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

void Fnc_Rit(){
  if(Flg_Rit == 0){
    Rit_Dat = 0;
    Flg_Rit = 1;
    Flg_Spl = 0;
    switch(Byt_Chn){
      case 1:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep1);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep1);
        break;
      case 2:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep2);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep2);
        break;
      case 3:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep3);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep3);
        break;
      default:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep0);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep0);
        break;
    }
  }
  else{
    Flg_Rit = 0;
  }
  while(digitalRead(SW_RIT) == LOW)
    ;
  delay(250);
}  
  
//----------  Function Channel SW Check  ---------

void Fnc_Chsw(){
  if(digitalRead(SW_CH1) == LOW){
    Byt_Chn = 1;
  }
  else if(digitalRead(SW_CH2) == LOW){
    Byt_Chn = 2;
  }
  else if(digitalRead(SW_CH3) == LOW){
    Byt_Chn = 3;
  }
  else{
    Byt_Chn = 0;
  }
}

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

void Fnc_Eep_Rd(){
  if(Fnc_Eep_Lod4(Frq_Eep0) <= LW_VFO){
    Vfo_Dat = DEF_VFO;
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep0);
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep1);
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep2);
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep3);
  }
  else{
    switch(Byt_Chn){
      case 1:
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep1);
        break;
      case 2:  
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep2);
        break;
      case 3:  
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep3);
        break;
      default:
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep0);
        break;
    }
  }
  if(Vfo_Dat <= 0){
    Vfo_Dat = DEF_VFO;
  }
  if(Fnc_Eep_Lod4(Stp_Eep0) <= 0){
    Enc_Stp = DEF_STP;
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep0);  
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep1);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep2);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep3);
  }
  else{
    switch(Byt_Chn){
      case 1:
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep1);
        break;
      case 2:  
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep2);
        break;
      case 3:  
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep3);
        break;
      default:
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep0);
        break;
    }
  }
  if(Enc_Stp <= 0){
    Enc_Stp = DEF_STP;
  }
}

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

void Fnc_Spl(){
  if(Flg_Spl == 0){
    Flg_Spl = 1;
    Flg_Rit = 0;
    Rit_Dat = 0;
  }
  else{
    Flg_Spl = 0;
  }
  while(digitalRead(SW_SPLIT) == LOW)
    ;
  delay(250);
}








      

Arduino AD9834 DDS PCB

Arduino UNO版AD9834 DDSをPCB化した。このPCBテストの為、水晶発振器代替(チャンネル切替方式)7MHz用にAD9851のプログラムを移植した。試験するには、コンパクトなプログラムなので重宝する。DDS発振周波数は、送信時、7.195MHz、7.181MHz、7.160MHz。また、受信時は、0Hz(DDS発振停止)。

回路図である。バッファアンプのベース抵抗は、2次高調波低減の為、4.7kとした。プログラムで使わないI/Oは、書いてない。
基本波のスペクトラム。
広帯域増幅なので致し方ないが、バッファアンプ付加により、n次のスプリアスがある。4次以降のスプリアスは、見当らなかった。この程度であれば、アプリケーションで対応可能だ。
電源電圧5V時、出力4mW。バッファアンプの電源は、VINからでもジャンパー出来るので、出力アップ可能。

基板サイズ 69 x 54。
オシレターは、正方形、長方形に対応。














program

7MHz AM送信機用に周波数が設定してある。受信時は、発振停止。クロックは、手持ちの部品で周波数を選んで56MHzとしたが、この周波数に拘る事は無い。
 
//////////////////////////////////////////////////////////////////////
//  AD9834 DDS VFO Premixed type program ver.1.0
//
//    Copyright(C)2014.JA2GQP.All rights reserved.
//     Crystal replacement
//                                                  2015/9/8
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.ch0=7.195Mhz ch1=7.181Mhz ch2=7.160Mhz ch3=7.195Mhz
//    2.TX=chenel frequency RX=0Hz(off)
//////////////////////////////////////////////////////////////////////

//----------  Define Constant Value   ----------
                                             
const byte  SDATA = 4;                     // AD9834 SDATA
const byte  SCLK = 5;                      //        SCLK
const byte  FSYNC = 6;                     //        FSYNC

const byte  SW_CH1 = 10;                   // Channel 1
const byte  SW_CH2 = 11;                   //         2
const byte  SW_CH3 = 12;                   //         3
const byte  SW_TX = 13;                    // TX Sw

const long  FRQ_CH0 = 7195000L;            // CH0=7.195Mhz
const long  FRQ_CH1 = 7181000L;            // CH1=7.181Mhz
const long  FRQ_CH2 = 7160000L;            // CH2=7.160Mhz
const long  FRQ_CH3 = 7195000L;            // CH3=7.195Mhz

const unsigned long  DDS_CLK = 56000000L;  // AD9834 Clock 56Mhz
const unsigned long  TWO_E28 = 268435456L; // 2^28

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

long Dds_Dat = 0;                         // DDS Data

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

void setup(){
  pinMode(SW_TX,INPUT_PULLUP);            // Input pin set
  pinMode(SW_CH1,INPUT_PULLUP);
  pinMode(SW_CH2,INPUT_PULLUP);
  pinMode(SW_CH3,INPUT_PULLUP);

  pinMode(FSYNC,OUTPUT);                  // Output pin set
  pinMode(SCLK,OUTPUT);
  pinMode(SDATA,OUTPUT);
}

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

void loop() {
  if(digitalRead(SW_CH1) == LOW){
    Dds_Dat = FRQ_CH1;
    }
  else if(digitalRead(SW_CH2) == LOW){
    Dds_Dat = FRQ_CH2;
    }
  else if(digitalRead(SW_CH3) == LOW){
    Dds_Dat = FRQ_CH3;
    }
    else{
      Dds_Dat = FRQ_CH0;
      }

  if(digitalRead(SW_TX) == HIGH){            // Rx?
    Dds_Dat = 0L;
    }

  Fnc_Dds(Dds_Dat);
  delay(100);
}

//----------  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);                       // Added 2014/12/29
  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);
}












         

2015年8月27日木曜日

AD9851 DDS 50Mhz水晶発振子代替PCB版

Arduino UNOを使ったAD9851 DDS水晶発振子代替PCB版。公開中のプロトタイプをPCB化した物で、パターン引き回し上、DIOアドレスを変更。 水晶発振子代替と表現しているが、水晶発振クオリティを目指したものでは無い。 DDSクオリテイのチャンネル切替式である。バッファアンプは同調方式を採用し、クリーンな増幅をしている。簡易スペアナで見る限り、スプリアスは見当たらない。ただ、受信機でモニターすると、多少、ざわつき(DDS固有かも知れないが・・・)を感じる。問題になるレベルでないと思う。 
回路図である。チャンネル切替方式に必要な所以外、書いてない。チェンネル切替が不要であれば、50.6Mhz(デフォルト)一波となる。送信切替は、接点入力/電圧入力可能。出力は、真空管ドライブ可能なレベルである。

基板サイズ 69 x 54














Program(スケッチ)

50Mhz AM 送信用水晶発振子の代替とすべく、チャンネル周波数を設定している。このプログラムでは、受信時、DDS発振を停止している。送受用DDSに変更も簡単だ。

//////////////////////////////////////////////////////////////////////
//  AD9851 DDS VFO Premixed type program ver.1.0
//
//    Copyright(C)2014-2015.JA2GQP.All rights reserved.
//     Crystal replacement
//                                                  2015/8/26
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.ch0=50.6Mhz ch1=50.55Mhz ch2=50.62Mhz ch3=50.69Mhz
//    2.TX=chenel frequency RX=0Hz(off)
//////////////////////////////////////////////////////////////////////

//----------  Define Constant Value   ----------
                                             
const byte  DATA = 12;                       // DIO12
const byte  W_CLK = 14;                      // DIO14
const byte  FQ_UD = 15;                      // DIO15

const byte  SW_CH1 = 9;                      // Channel 1
const byte  SW_CH2 = 10;                     //         2
const byte  SW_CH3 = 11;                     //         3
const byte  SW_TX = 13;                      // TX Sw
const byte  DDS_RST = 8;                     // DDS Reset

const long  FRQ_CH0 = 50600000L;             // CH0=50.6Mhz
const long  FRQ_CH1 = 50550000L;             // CH1=50.55Mhz
const long  FRQ_CH2 = 50620000L;             // CH2=50.62Mhz
const long  FRQ_CH3 = 50690000L;             // CH3=50.69Mhz

const unsigned long  DDS_CLK = 192000000L;   // AD9851 Clock(32MHz * 6)
const unsigned long  TWO_E32 = 4294967295L;  // 2^32
const byte  DDS_CMD = B00000001;             // AD9851 Command

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

long Dds_Dat = 0;                             // DDS Data

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

void setup(){
  pinMode(SW_TX,INPUT_PULLUP);                // Input pin set
  pinMode(SW_CH1,INPUT_PULLUP);
  pinMode(SW_CH2,INPUT_PULLUP);
  pinMode(SW_CH3,INPUT_PULLUP);

  pinMode(DDS_RST,OUTPUT);                   // Output pin set
  pinMode(FQ_UD,OUTPUT);
  pinMode(W_CLK,OUTPUT);
  pinMode(DATA,OUTPUT);

  Fnc_Dds_Int();                             // DDS Initial
}

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

void loop() {
  if(digitalRead(SW_CH1) == LOW){
    Dds_Dat = FRQ_CH1;
    }
  else if(digitalRead(SW_CH2) == LOW){
    Dds_Dat = FRQ_CH2;
    }
  else if(digitalRead(SW_CH3) == LOW){
    Dds_Dat = FRQ_CH3;
    }
    else{
      Dds_Dat = FRQ_CH0;
      }

  if(digitalRead(SW_TX) == HIGH){            // Rx?
    Dds_Dat = 0L;
    }

  Fnc_Dds(Dds_Dat);
  delay(100);
}


//----------  Function DDS Initialization  ---------------

void Fnc_Dds_Int(){
  digitalWrite(DDS_RST,HIGH);
  delay(1);
  digitalWrite(DDS_RST,LOW);
  digitalWrite(W_CLK,HIGH);
  digitalWrite(W_CLK,LOW);
  digitalWrite(FQ_UD,HIGH);
  digitalWrite(FQ_UD,LOW);
}

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

void Fnc_Dds(double frquency){
  unsigned long wrk = frquency * TWO_E32 / DDS_CLK;

  digitalWrite(FQ_UD,LOW);

  shiftOut(DATA,W_CLK,LSBFIRST,wrk);
  shiftOut(DATA,W_CLK,LSBFIRST,(wrk >> 8));
  shiftOut(DATA,W_CLK,LSBFIRST,(wrk >> 16));
  shiftOut(DATA,W_CLK,LSBFIRST,(wrk >> 24));
  shiftOut(DATA,W_CLK,LSBFIRST,DDS_CMD);   // AD9851 command

  digitalWrite(FQ_UD,HIGH);
}