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;

}





22 件のコメント:

  1. Hello. Make you this PCB board on Eagle software?

    返信削除
    返信
    1. I would like to know if he did.

      削除
    2. The CAD I am using is not Eagle. It is a popular pcbe in Japan.

      削除
  2. Hello,
    Will it be possible to modify the sketch to use 1.8" TFT display ST7735S as 2.2" display is not readily available

    返信削除
    返信
    1. Please use 2.4 "or 2.8" using ili 9341 for the controller.

      削除
    2. Thank you
      Can you please share the PCB in PDF format as getting the JPG on size is a problem

      削除
    3. Hi, gaurav
      The necessary information should be on the download site.
      https://sites.google.com/site/ja2gqp/

      削除
  3. How about using the Nextion Displays...... I guess they have a waveform widget also.

    返信削除
    返信
    1. In the Nexion Editor, make screen, touch. Arduino will only process data with Nexion.
      For this level of display, touch can be easily done with Nextion. Unfortunately it's a novice in Nextion, so I can not make it.

      削除
  4. Hi,
    i am getting a lot of errors during compilation. i have ili9341 2.2 TFT display!

    返信削除
  5. sp3nyrのアナライザは、ファームを改造して校正機能を付加したものと思われます。改造したファームと校正機能をセットで使わなければ、機能しないと思います。

    返信削除
    返信
    1. sp3nytに問い合わせたら如何ですか。

      削除
  6. Hello.
    I have a problem about the program. You have to programs, one on Your download side, and one In the top of his artikel. Non of then will run, with out a error with the Arduino Nano.
    Is it possible to send the program, that works with the Nano?

    Vy 73 de
    oZ2ADU René

    返信削除
    返信
    1. Hi,René

      Please download the hex file from the antenna analyzer folder.
      https://sites.google.com/site/ja2gqp/

      削除
  7. When trying to upload the code to the Arduino Nano, it tells me that the file exceeds the capacity. How can I solve this problem? Thank you LU1VFP Edgardo. Patagonia Argentina

    返信削除

  8. Hi Edgardo.

    This is probably due to a different version of Ucglib.
    A library is also included so that it can be compiled.
    Unzip the zip file and compile it.
    Please download from here.
    https://sites.google.com/site/ja2gqp/
    Download the zip file dated 2021/4/13 in the Antenna Analyzer folder.

    返信削除
  9. It seems that the device settings of Arduino IDE are inappropriate.
    If it is Arduino Nano ATmega328P (Old Bootloader), there can be no memory shortage.

    返信削除
  10. error: 'ucg_font_ncenR14r' was not declared in this scope

    返信削除
  11. Please download from here
    https://sites.google.com/view/ja2gqp

    Download DDS_sweeper1_TFT.zip from the Antenna Analyzer folder.
    You can unzip the zip file and compile it as it is.

    返信削除
  12. Is possible SI5351 as rf source, because ad9850 is hard to find and expensive.?

    返信削除