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;

}