2017年6月3日土曜日

si5351a TFT VFO Ver.1.1

 2.2"TFTが入手難の為、1.8"TFTにダウンサイジングを行った。今回の移植作業と合わせ、機能追加を行う事にした。追加変更内容は、Lowerヘテロダイン対応とBFO追加である。理由は、BITX40がLowerヘテロダインである事と、si5351aのマルチ出力が生かされて無かったからである。
回路図、スケッチはダウンロードサイトsi5351a TFTフォルダに2種類有ります。
si5351_TFT18.zip,si5351_TFT181.zip



回路図である。si5351aモジュールのclk2からBFO出力を行っている。













インクルードファイル

si5351aの制御は、ライブラリを使わずに、インクルードファイルで行っている。このファイルをスケッチと同じフォルダーに保存して使う。周波数が変わる毎に発生するクリック低減のため、PLLリセットを行わない事(コメントアウトしてある)とした。但し、位相制御などタイミングを重視する場合、PLLリセットを行う必要が有るであろう。

si5351a2.hの内容。


////////////////////////////////////////////////////////////////////////
// Author: Hans Summers, 2015
// Website: http://www.hanssummers.com
//
// A very very simple Si5351a demonstration
// using the Si5351a module kit http://www.hanssummers.com/synth
// Please also refer to SiLabs AN619 which describes all the registers to use
//----------------------------------------------------------------------
// Modifications: JA2GQP,2017/5/20
//     1)Output is CLK0 and CLK2.
//     2)Arduino and stm32duino Operable.
////////////////////////////////////////////////////////////////////////

#include <Wire.h>

#define CLK0_CTRL   16               // Register definitions
#define CLK1_CTRL   17
#define CLK2_CTRL   18
#define MSNA_ADDR   26
#define MSNB_ADDR   34
#define MS0_ADDR    42
#define MS1_ADDR    50
#define MS2_ADDR    58
#define PLL_RESET   177
#define XTAL_LOAD_C 183

#define R_DIV_1      0b00000000     // R-division ratio definitions
#define R_DIV_2      0b00010000
#define R_DIV_4      0b00100000
#define R_DIV_8      0b00110000
#define R_DIV_16     0b01000000
#define R_DIV_32     0b01010000
#define R_DIV_64     0b01100000
#define R_DIV_128    0b01110000

#define Si5351A_ADDR  0x60

#define CLK_SRC_PLL_A 0b00000000
#define CLK_SRC_PLL_B 0b00100000

#define XTAL_FREQ     25000000    // Crystal frequency for Hans' board

////////////////////////////////////////////////////////////////////////
// I2C write
////////////////////////////////////////////////////////////////////////

void Si5351_write(byte Reg , byte Data){
  Wire.beginTransmission(Si5351A_ADDR);
  Wire.write(Reg);
  Wire.write(Data);
  Wire.endTransmission();
}

////////////////////////////////////////////////////////////////////////
// Set up specified PLL with mult, num and denom
// mult is 15..90
// num is 0..1,048,575 (0xFFFFF)
// denom is 0..1,048,575 (0xFFFFF)
///////////////////////////////////////////////////////////////////////

void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom){
  uint32_t P1;                            // PLL config register P1
  uint32_t P2;                            // PLL config register P2
  uint32_t P3;                            // PLL config register P3

  P1 = (uint32_t)(128 * ((float)num / (float)denom));
  P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
  P2 = (uint32_t)(128 * ((float)num / (float)denom));
  P2 = (uint32_t)(128 * num - denom * P2);
  P3 = denom;

  Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
  Si5351_write(pll + 1, (P3 & 0x000000FF));
  Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
  Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
  Si5351_write(pll + 4, (P1 & 0x000000FF));
  Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
  Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
  Si5351_write(pll + 7, (P2 & 0x000000FF));
}

////////////////////////////////////////////////////////////////////////
// Set up MultiSynth with integer divider and R divider
// R divider is the bit value which is OR'ed onto the appropriate
// register, it is a #define in si5351a.h
////////////////////////////////////////////////////////////////////////

void setupMultisynth(uint8_t synth, uint32_t divider, uint8_t rDiv){
  uint32_t P1;                          // Synth config register P1
  uint32_t P2;                          // Synth config register P2
  uint32_t P3;                          // Synth config register P3

  P1 = 128 * divider - 512;
  P2 = 0;                               // P2 = 0, P3 = 1 forces an integer value for the divider
  P3 = 1;

  Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
  Si5351_write(synth + 1, (P3 & 0x000000FF));
  Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
  Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
  Si5351_write(synth + 4, (P1 & 0x000000FF));
  Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
  Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
  Si5351_write(synth + 7, (P2 & 0x000000FF));
}

////////////////////////////////////////////////////////////////////////
// Switches off Si5351a output
// Example: si5351aOutputOff(CLK0_CTRL);
// will switch off output CLK0
////////////////////////////////////////////////////////////////////////

void si5351aOutputOff(uint8_t clk){
  Si5351_write(clk, 0x80);              // Refer to SiLabs AN619 to see
                                        //bit values - 0x80 turns off the output stage
}

////////////////////////////////////////////////////////////////////////
// Set CLK0 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL A
// and MultiSynth 0
// and produces the output on CLK0
////////////////////////////////////////////////////////////////////////

void si5351aSetFrequency(uint32_t frequency){
  uint32_t pllFreq;
  uint32_t xtalFreq = XTAL_FREQ;
  uint32_t l;
  float f;
  uint8_t mult;
  uint32_t num;
  uint32_t denom;
  uint32_t divider;

  divider = 900000000 / frequency;        // Calculate the division ratio. 900,000,000 is the maximum internal
                                          // PLL frequency: 900MHz
  if (divider % 2) divider--;             // Ensure an even integer
                                          //division ratio

  pllFreq = divider * frequency;          // Calculate the pllFrequency:
                                          //the divider * desired output frequency

  mult = pllFreq / xtalFreq;              // Determine the multiplier to
                                          //get to the required pllFrequency
  l = pllFreq % xtalFreq;                 // It has three parts:
  f = l;                                  // mult is an integer that must be in the range 15..90
  f *= 1048575;                           // num and denom are the fractional parts, the numerator and denominator
  f /= xtalFreq;                          // each is 20 bits (range 0..1048575)
  num = f;                                // the actual multiplier is mult + num / denom
  denom = 1048575;                        // For simplicity we set the denominator to the maximum 1048575

                                          // Set up PLL A with the calculated  multiplication ratio
  setupPLL(MSNA_ADDR, mult, num, denom);
                                          // Set up MultiSynth divider 0, with the calculated divider.
                                          // The final R division stage can divide by a power of two, from 1..128.
                                          // reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
                                          // If you want to output frequencies below 1MHz, you have to use the
                                          // final R division stage
  setupMultisynth(MS0_ADDR, divider, R_DIV_1);
                                          // Reset the PLL. This causes a glitch in the output. For small changes to
                                          // the parameters, you don't need to reset the PLL, and there is no glitch
//  Si5351_write(PLL_RESET, 0x20);
                                          // Finally switch on the CLK0 output (0x4F)
                                          // and set the MultiSynth0 input to be PLL A
  Si5351_write(CLK0_CTRL, 0x4F | CLK_SRC_PLL_A);    // Strength 8mA
}

////////////////////////////////////////////////////////////////////////
// Set CLK1 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency2(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL B
// and MultiSynth 1
// and produces the output on CLK1
////////////////////////////////////////////////////////////////////////

void si5351aSetFrequency2(uint32_t frequency){
  uint32_t pllFreq;
  uint32_t xtalFreq = XTAL_FREQ;
  uint32_t l;
  float f;
  uint8_t mult;
  uint32_t num;
  uint32_t denom;
  uint32_t divider;

  divider = 900000000 / frequency;        // Calculate the division ratio. 900,000,000 is the maximum internal
                                          // PLL frequency: 900MHz
  if (divider % 2) divider--;             // Ensure an even integer
                                          //division ratio

  pllFreq = divider * frequency;          // Calculate the pllFrequency:
                                          //the divider * desired output frequency

  mult = pllFreq / xtalFreq;              // Determine the multiplier to
                                          //get to the required pllFrequency
  l = pllFreq % xtalFreq;                 // It has three parts:
  f = l;                                  // mult is an integer that must be in the range 15..90
  f *= 1048575;                           // num and denom are the fractional parts, the numerator and denominator
  f /= xtalFreq;                          // each is 20 bits (range 0..1048575)
  num = f;                                // the actual multiplier is mult + num / denom
  denom = 1048575;                        // For simplicity we set the denominator to the maximum 1048575

                                          // Set up PLL B with the calculated  multiplication ratio
  setupPLL(MSNB_ADDR, mult, num, denom);
                                          // Set up MultiSynth divider 0, with the calculated divider.
                                          // The final R division stage can divide by a power of two, from 1..128.
                                          // reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
                                          // If you want to output frequencies below 1MHz, you have to use the
                                          // final R division stage
  setupMultisynth(MS2_ADDR, divider, R_DIV_1);
                                          // Reset the PLL. This causes a glitch in the output. For small changes to
                                          // the parameters, you don't need to reset the PLL, and there is no glitch
//  Si5351_write(PLL_RESET, 0x80);
                                          // Finally switch on the CLK1 output
                                          // and set the MultiSynth0 input to be PLL B
  Si5351_write(CLK2_CTRL, 0x6F | CLK_SRC_PLL_B);    // Strength 8mA
}

スケッチ

BFO出力とLOwerヘテロダインに対応。BITX40の設定は、仕様周波数で記述してあるので必要であれば、実周波数に変更する程度で良いだろう。ただ、BITX40実機を持ってないので未確認。

//////////////////////////////////////////////////////////////////////////////
//       Copyright©2016.JA2GQP.All rights reserved.
//            si5351a PLL VFO Ver1.101      << JA2NKD sketch is based >>      
//                                                    2017/6/3
//                                                    JA2GQP  
//                      << Aruduino IDE 1.8.2 >>
//
//----------------------------------------------------------------------------  
//  Function
//    1.RIT Operation(-10kHZ to 10kHZ)
//    2.STEP(10,100,1k,10k)
//    3.Memory Operation is Push RIT
//    4.Protection Operation At The Time Of Transmission
//    5.Memory 4ch(LSB,USB.CW,AM)
//    6.IF shift
//----------------------------------------------------------------------------  
//  Library
//          <Rotary.h>    https://github.com/brianlow/Rotary
//          "Ucglib.h"    https://github.com/olikraus/ucglib
//
//////////////////////////////////////////////////////////////////////////////

//---------- include Files ---------------

#include "si5351a2.h"
#include <SPI.h>
#include <Rotary.h>
#include <EEPROM.h>
#include "Ucglib.h"

//----------   TFT setting  ---------------

  Ucglib_ST7735_18x128x160_HWSPI ucg(/*sclk= 13, data= 11, */ /*cd=*/ 9 , /*cs=*/ 10, /*reset=*/ 8);

//----------   Encorder setting  ---------------

#define   ENC_A       2                   // Encorder A
#define   ENC_B       3                   // Encoeder B

Rotary r=Rotary(ENC_A,ENC_B);

//----------   I/O setting  -------------------

#define   modeout1    7                   // DIO7
#define   modeout2    12                  // DIO12
#define   modesw      6                   // DIO6
#define   stepsw      4                   // DIO4
#define   ritsw       5                   // DIO5
#define   txsw        A3                  // A3
#define   s_meter     A0                  // A0
#define   t_meter     A1                  // A1

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

#define   Frq_Eep     0x00                // Frequency(4byte*4)
#define   Stp_Eep     0x10                // STEP(4byte*4)
#define   Chn_Eep     0x20                // Channel(1byte*1)
#define   Mode_Eep    0x22                // Mode(1byte*1)
#define   Eep_Int     0x2e                // Eep Init(1byte*1)

#define   Max_Chn     4                   // Max Channel(4ch)
#define   Int_End     73                  // Initial end code

//----------- Default Frequency Value --------------------

#define   UPPER      0                    // Upoper heterodyne
#define   LOWER      1                    // Lower heterodyne

////////////////////////////////////////////////////////////////
//  BITX40 Setting example(Upper heterodyne)      No.1
////////////////////////////////////////////////////////////////


#define   DEF_FRQ    7050000L             // Init Frequency
#define   DEF_FMAX   7200000L             // Frequency Max
#define   DEF_FMIN   7000000L             //           Min
#define   DEF_RLSB   10698500L            // RX IF Shift LSB
#define   DEF_RUSB   10701500L            //             USB
#define   DEF_RCW    10699200L            //             CW
#define   DEF_RAM    10700000L            //             AM
#define   DEF_TLSB   10698500L            // TX IF Shift LSB
#define   DEF_TUSB   10701500L            //             USB
#define   DEF_TCW    10700000L            //             CW
#define   DEF_TAM    10700000L            //             AM

byte   hetero = UPPER;                         // Lower heterodyne set


////////////////////////////////////////////////////////////////
//  BITX40 Setting example(Lower heterodyne)      No.2
////////////////////////////////////////////////////////////////

/*
#define   DEF_FRQ    7050000L             // Init Frequency
#define   DEF_FMAX   7200000L             // Frequency Max
#define   DEF_FMIN   7000000L             //           Min
#define   DEF_RLSB   11998500L            // RX IF Shift LSB
#define   DEF_RUSB   12001500L            //             USB
#define   DEF_RCW    11999400L            //             CW
#define   DEF_RAM    12000000L            //             AM
#define   DEF_TLSB   11998500L            // TX IF Shift LSB
#define   DEF_TUSB   12001500L            //             USB
#define   DEF_TCW    12000000L            //             CW
#define   DEF_TAM    12000000L            //             AM

byte   hetero = LOWER;                    // Lower heterodyne set
*/

//----------- Default ETC. Value --------------------

#define   DEF_STP    100L                 // Init STEP
#define   DEF_Mode   0                    // 0=LSB 1=USB 2=CW 3=AM

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

long freq    = DEF_FRQ;                   // Frequency data
long freqb;                               //           old data
long freqmax = DEF_FMAX;                  // VFO Upper Limit
long freqmin = DEF_FMIN;                  //     Lower Limit
long freqold = 0;
long freqrit = 0;
String freqt=String(freq);
long ifshift = 0;
long ifshiftb;
long ifshiftLSB = DEF_RLSB;               // RX IF Shift LSB
long ifshiftUSB = DEF_RUSB;               //             USB
long ifshiftCW = DEF_RCW;                 //             CW
long ifshiftAM = DEF_RAM;                 //             AM
long txshiftLSB = DEF_TLSB;               // TX IF Shift LSB
long txshiftUSB = DEF_TUSB;               //             USB
long txshiftCW = DEF_TCW;                 //             CW
long txshiftAM = DEF_TAM;                 //             AM
long vfofreq = 0;                         // VFO data
long vfofreqb;                            //     old
char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;
int vfostep=2;
int rit=0;
int fstep = DEF_STP;                      // Default Step
int fmode;
int fmodeold=1;
int flagrit=0;
int fritold=0;
int flagmode=0;
int smeterval1=0;
int tmeterval=0;
byte Byt_Chn;                             // Channel SW
byte Byt_Chnb;                            //            Old

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

void setup() {
  Wire.begin();                

  delay(100);
  ucg.begin(UCG_FONT_MODE_TRANSPARENT);
  ucg.clearScreen();
  ucg.setRotate90();

  pinMode (stepsw,INPUT_PULLUP);
  pinMode (ritsw,INPUT_PULLUP);
  pinMode(txsw,INPUT_PULLUP);
  pinMode(modesw,INPUT_PULLUP);
  pinMode(modeout1,OUTPUT);
  pinMode(modeout2,OUTPUT);

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

  screen01();

  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;                    //
  Fnc_Eep_Rd();                          // EEPROM Read

  modeset();                             // modeset * 4 times
  modeset();
  modeset();
  modeset();

  steplcd();
  freqt=String(freq);
  freqlcd();
 }

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

void loop() {
  if (digitalRead(stepsw)==LOW){setstep();}
  if (digitalRead(modesw)==LOW){modeset();}
  if (digitalRead(ritsw)==LOW){setrit();Fnc_Eep_Wt(Byt_Chn);}
  if (digitalRead(txsw)==LOW){txset();}

    if(Byt_Chnb != Byt_Chn){             // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
      steplcd();
    }
     
  if (flagrit==1){
    if (freqrit == fritold){
      smeter();
    }  

    if (freqrit!=fritold){
      Vfo_write();
      ritlcd();
      fritold=freqrit;
    }
  }
  else{
    if (freq == freqold){
        smeter();
    }
    Vfo_write();
    freqt=String(freq);
    freqlcd();
    freqold=freq;
  }
}

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

void Fnc_Eep_Int(){
  int i;

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

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

  EEPROM.write(Chn_Eep,0);
  EEPROM.write(Mode_Eep,DEF_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))
    freq = Fnc_Eep_Lod4(Frq_Eep+Byt_Chn*4);
  else{
    freq = Fnc_Eep_Lod4(Frq_Eep+0);
    Byt_Chn = 0;
  }

  if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
    fstep = Fnc_Eep_Lod4(Stp_Eep+Byt_Chn*4);
  else
    fstep = Fnc_Eep_Lod4(Stp_Eep+0);
 
  fmode = EEPROM.read(Mode_Eep);
}

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

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

  EEPROM.write(Chn_Eep,Byt_Chn);
  EEPROM.write(Mode_Eep,fmode);
}

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

//----------  VFO out  ---------------      

void Vfo_out(long frequency){
  if(vfofreq != vfofreqb){
    si5351aSetFrequency(frequency);
    vfofreqb = vfofreq;
  }
}

//----------  BFO out  ---------------      

void Bfo_out(long frequency){
  if(ifshift != ifshiftb){
    si5351aSetFrequency2(frequency);
    ifshiftb = ifshift;
  }
}

//---------- S-meter --------------------------

void smeter(){
 smeterval1=analogRead(s_meter);
 smeterval1=smeterval1/50;
 if (smeterval1>14){smeterval1=14;}     //15
  int sx1=sx1+(smeterval1*9);           //16
  sx1=sx1+21;                           //41
  int sx2=0;
  sx2=sx2+(40+((15-smeterval1)*9));     //ucg_font_6x10_mf
  ucg.setFont(ucg_font_fub20_tn);       //ucg_font_fub35_tn
  ucg.setColor(0,0,0);                  // BLACK
  ucg.drawBox(sx1,99,sx2,8);
  ucg.setPrintPos(20,109);              //40,200
  for(int i=1;i<=smeterval1;i++){
    if (i<=8){
      ucg.setColor(0,255,255);
      ucg.print("-");
    }
    else{
      ucg.setColor(255,0,0);
      ucg.print("-");
    }
  }
}

//---------- Transmission Power meter ------------------

void tmeter(){
 ucg.setColor(0,0,0);                   // BLACK
 ucg.drawBox(20,99,135,8);              //41,180,270,16
 tmeterval=analogRead(t_meter);
 tmeterval=tmeterval/50;
 if (tmeterval>14){tmeterval=14;}
  int sx1=sx1+(tmeterval*9);
  sx1=sx1+21;
  int sx2=0;
  sx2=sx2+(40+((15-tmeterval)*9));
  ucg.setFont(ucg_font_fub20_tn);       //35ucg_font_fub20_tn
  ucg.setColor(0,0,0);                  //BLACK
  ucg.drawBox(sx1,78,sx2,8);
  ucg.setPrintPos(20,90);               //85(40,165)
  for(int i=1;i<=tmeterval;i++){
    if (i<=9){
      ucg.setColor(250,80,0);
      ucg.print("-");
    }
    else{
      ucg.setColor(250,0,0);
      ucg.print("-");
    }
  }
}

//---------- Encoder Interrupt -----------------------

ISR(PCINT2_vect) {
  if (flagrit==1){
  unsigned char result = r.process();
    if(result) {
      if(result == DIR_CW){
        freqrit=freqrit+fstep;
        if (freqrit>=10000){
          freqrit=10000;
        }
      }
     else{
        freqrit=freqrit-fstep;
        if (freqrit<=-10000){
          freqrit=-10000;
        }
     }
    }
  }

  else{
    unsigned char result = r.process();
      if(result) {
        if(result == DIR_CW){
          freq=freq+fstep;
          if (freq>=freqmax){freq=freqmax;}
        }
        else{
          freq=freq-fstep;
          if (freq<=freqmin){freq=freqmin;}
        }
     }
  }

}

//------------ On Air -----------------------------

void txset(){
  long vfofreq_RX = vfofreq;;
  long ifshift_RX = ifshift;;
//  noInterrupts();
  if(hetero == UPPER){                          // Upper heterodyne
    if (flagmode==0){ifshift=txshiftLSB;}
    if (flagmode==1){ifshift=txshiftUSB;}
    if (flagmode==2){ifshift=txshiftCW;}
    if (flagmode==3){ifshift=txshiftAM;}
    vfofreq=freq+ifshift;
  }
  else{                                                  // Lower heterodyne
    if (flagmode==0){ifshift=txshiftLSB;}
    if (flagmode==1){ifshift=txshiftUSB;}
    if (flagmode==2){ifshift=txshiftCW;}
    if (flagmode==3){ifshift=txshiftAM;}
    vfofreq=ifshift-freq;
  }

  Vfo_out(vfofreq);                               // vfo out
  Bfo_out(ifshift);                                 // BFO out
 
  ucg.setPrintPos(70,75);                      //140,140
  ucg.setFont(ucg_font_6x10_mf);        //17ucg_font_fub11_tn
  ucg.setColor(255,0,0);
  ucg.print("ON AIR");
  while(digitalRead(txsw) == LOW){
    tmeter();
  }
  vfofreq = vfofreq_RX;
  ifshift = ifshift_RX;

  ucg.setColor(0,0,0);
  ucg.drawBox(15,63,95,15);                   //30,120,250,30 // ON AIR Erase
  Vfo_write();
  ucg.drawBox(20,80,135,8);                   //41,145,270,16  // Level Erase
//    interrupts();
}

//------------- Mode change(LSB-USB-CW-AM) ------------

void modeset(){
  ucg.setFont(ucg_font_6x10_mf);  //17ucg_font_fub11_tn
//  if (fmode==0){                          
  if (fmode==1){                              // 2016/8/3
    ifshift=ifshiftUSB;
    flagmode = 1;                             // 2016/8/3
    ucg.setColor(255,255,0);                  //Black?
    ucg.setPrintPos(44,43);                   //(82,82
    ucg.print("USB");
    ucg.setPrintPos(9,43);                    //12,82
    ucg.setColor(0,0,0);                      //Black Yellow
    ucg.print("LSB");  
    digitalWrite(modeout1,HIGH);
    digitalWrite(modeout2,LOW);  
  }

//  if(fmode==1){                          
  if(fmode==2){                                // 2016/8/3
    ifshift=ifshiftCW;
    flagmode = 2;                             // 2016/8/3
    ucg.setPrintPos(9,60);                    //12,112
    ucg.setColor(255,255,0);                  //Yellow
    ucg.print("C W");
    ucg.setPrintPos(44,43);                   //82,82
    ucg.setColor(0,0,0);                      //Black
    ucg.print("USB");
    digitalWrite(modeout1,LOW);
    digitalWrite(modeout2,HIGH);
  }

//  if (fmode==2){                          
  if (fmode==3){                              // 2016/8/3
    ifshift=ifshiftAM;
    flagmode = 3;                             // 2016/8/3
    ucg.setPrintPos(44,60);                   //82,112
    ucg.setColor(255,255,0);                  //Yellow
    ucg.print("A M");
    ucg.setColor(0,0,0);                      //Black  
    ucg.setPrintPos(9,60);                    //12,112
    ucg.print("C W");
    digitalWrite(modeout1,HIGH);
    digitalWrite(modeout2,HIGH);
    }

//  if (fmode==3){                          
  if (fmode==0){                              // 2016/8/3
    ifshift=ifshiftLSB;
    flagmode = 0;                             // 2016/8/3
    ucg.setPrintPos(9,43);                    //12,82
    ucg.setColor(255,255,0);                  //Yellow
    ucg.print("LSB");
    ucg.setPrintPos(44,60);                   //82,112
    ucg.setColor(0,0,0);                      //Black
    ucg.print("A M");
    digitalWrite(modeout1,LOW);
    digitalWrite(modeout2,LOW);
  }

  fmode=fmode+1;

  Byt_Chn++;                              
  if(Byt_Chn > 3)            
    Byt_Chn = 0;

  if (fmode==4){fmode=0;}
  Vfo_write();
  while(digitalRead(modesw) == LOW);
}

//------------ Rit SET ------------------------------

void setrit(){
  if(flagrit==0){
    flagrit=1;
    ucg.setFont(ucg_font_6x10_mf);            //11ucg_font_fub11_tn
    ucg.setPrintPos(95,55);                   //190,110
    ucg.setColor(255,0,0);
//    freqrit=0;
    ritlcd();
  }
  else {
    flagrit=0;

    if(hetero == UPPER)
      vfofreq=freq+ifshift;
    else
      vfofreq=ifshift-freq;
    Vfo_out(vfofreq);                       // vfo Out

    freqt=String(freq);
    ucg.setFont(ucg_font_6x10_mf);          //11ucg_font_fub11_tn
    ucg.setPrintPos(95,55);                 //190,110
    ucg.setColor(255,255,255);
   // ucg.print("RIT");
    ucg.setColor(0,0,0);
    ucg.drawRBox(112,52,44,10,1);           //222,92,91,21,3
    freqrit=0;
  }
  while(digitalRead(ritsw) == LOW);
}

//----------- Rit screen ----------------------

void ritlcd(){
  noInterrupts();
  ucg.setColor(0,0,0);
  ucg.drawBox(111,51,45,13);              //222,92,91,21 110,50,47,15,
  ucg.setFont(ucg_font_6x10_mf);          //17 ucg_font_fub11_tn
  ucg.setColor(0,255,255);
  ucg.setPrintPos(115,61);                //230,110
  ucg.print(freqrit);
  interrupts();
}

//-------------- encorder frequency step set -----------

void setstep(){
  noInterrupts();
  if (fstep==10000){
    fstep=10;
  }
  else{
    fstep=fstep * 10;
  }

 steplcd();
 while(digitalRead(stepsw) == LOW);
 interrupts();
}

//------------- Step Screen ---------------------------

void steplcd(){
  ucg.setColor(0,0,0);                    //0,0,0
  ucg.drawRBox(111,33,45,11,1);           //221,61,93,23,3
  ucg.setFont(ucg_font_6x10_mf);          //17ucg_font_fub11_tn
  ucg.setColor(255,255,255);
  ucg.setPrintPos(110,43);                //220,80
  if (fstep==10000){ucg.print("  10KHz");}
  if (fstep==1000){ucg.print("   1KHz");}
  if (fstep==100){ucg.print("  100Hz");}
  if (fstep==10){ucg.print("  10Hz");}
}

//----------- Main frequency screen -------------------

void freqlcd(){
  ucg.setFont(ucg_font_osr18_tn);         //35 ucg_font_fub20_tn
  int mojisuu=(freqt.length());

  if(freq<1000000){
    ucg.setColor(0,0,0);
    ucg.drawBox(52,7,9,20);               //103,9,15,36
    }
  if(f100k !=(freqt.charAt(mojisuu-6))){
    ucg.setColor(0,0,0);
    ucg.drawBox(59,7,15,20);              //118,9,28,36
    ucg.setPrintPos(59,24);               //118,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-6));
    f100k = (freqt.charAt(mojisuu-6));
  }
 
  if(freq<100000){
    ucg.setColor(0,0,0);
    ucg.drawBox(59,7,15,20);              //118,9,28,36
  }
  if(f10k !=(freqt.charAt(mojisuu-5))){
    ucg.setColor(0,0,0);
    ucg.drawBox(73,6,15,20);              //146,9,28,36
    ucg.setPrintPos(73,24);               //146,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-5));
    f10k = (freqt.charAt(mojisuu-5));
  }
 
  if(freq<10000){
    ucg.setColor(0,0,0);
    ucg.drawBox(73,6,14,19);              //146,9,28,36
    }
  if(f1k !=(freqt.charAt(mojisuu-4))){
    ucg.setColor(0,0,0);
    ucg.drawBox(87,6,14,19);              //174,9,28,36
    ucg.setPrintPos(87,24);               //(174,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-4));    
    f1k  = (freqt.charAt(mojisuu-4));
  }

  if(freq>=1000){
    ucg.setPrintPos(101,24);              //202,45
    ucg.setColor(0,255,0);
    ucg.print(".");
  }

  if(freq<1000){
    ucg.setColor(0,0,0);
    ucg.drawBox(101,6,8,19);              //   (202,9,15,36
    }
  if(f100 !=(freqt.charAt(mojisuu-3))){
    ucg.setColor(0,0,0);
    ucg.drawBox(109,6,14,19);             //217,9,28,36
    ucg.setPrintPos(108,24);              //(215,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-3));
    f100 = (freqt.charAt(mojisuu-3));
  }

  if(freq<100){
    ucg.setColor(0,0,0);
    ucg.drawBox(109,6,14,19);             //217,9,28,36
  }
  if(f10 !=(freqt.charAt(mojisuu-2))){
    ucg.setColor(0,0,0);
    ucg.drawBox(123,6,14,19);           //245,9,28,36
    ucg.setPrintPos(123,24);            //(245,45
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-2));
    f10 = (freqt.charAt(mojisuu-2));
  }
/*
  if(freq<10){
    ucg.setColor(0,0,0);
    ucg.drawBox(245,9,28,36);  
     }
  if(f1 !=(freqt.charAt(mojisuu-1))){
    ucg.setColor(0,0,0);
    ucg.drawBox(273,9,28,36);
    ucg.setPrintPos(273,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-1));  
    f1  = (freqt.charAt(mojisuu-1));
  }
*/
}

//----------- Basic Screen -------------------------

void screen01(){
  ucg.setColor(255,255,255);            //
  ucg.drawRFrame(0,0,160,28,3);         //0,0,320,55,5 OUTside
  //ucg.drawRFrame(0,0,159,27,2);       //1,1,318,53,5  INside
  ucg.setColor(0,128,255);              //FILL COLOR for MODE back
  ucg.drawRBox(2,33,30,12,1);           //5,60,60,25,3  LSB
  ucg.drawRBox(37,33,30,12,1);          //75,60,60,25,3 USB
  ucg.drawRBox(2,50,30,12,1);           //5,90,60,25,3  CW
  ucg.drawRBox(37,50,30,12,1);          //(75,90,60,25,3  AM
  ucg.setFont(ucg_font_6x10_mf);        //17
  ucg.setPrintPos(9,43);                //12,82
  ucg.setColor(0,0,0);
  ucg.print("LSB");
  ucg.setPrintPos(44,43);               //82,82
  ucg.print("USB");
  ucg.setPrintPos(9,60);                //12,112
  ucg.print("C W");
  ucg.setPrintPos(44,60);               //(82,112
  ucg.print("A M");
  ucg.setColor(255,255,255);
  ucg.drawRFrame(110,32,47,15,1);       //220,60,95,25,3 STEP frame
  ucg.drawRFrame(110,50,47,15,1);       //220,90,95,25,3 RIT frame
  ucg.setColor(255,255,100);            //100,100,100
  ucg.setPrintPos(7,105);               //15,200
  ucg.print("S:");
  ucg.setPrintPos(7,85);                //15,165
  ucg.print("P:");
  ucg.setFont(ucg_font_6x10_mf);        //11ucg_font_fub11_tn
  ucg.setColor(250,255,0);
  ucg.setPrintPos(80,43);               //175,80
  ucg.print("STEP");
  ucg.setPrintPos(80,60);               //190,110
  ucg.setColor(255,255,0);
  ucg.print("RIT");
  ucg.setColor(255,255,255);            //100,100,100
  ucg.setPrintPos(20,115);              //40,210
  ucg.print("1--3---6---9--Over---");
  ucg.setPrintPos(20,95);               //40,175
  ucg.print("1--3---5-----10------");
  ucg.setPrintPos(5,127);               //10,230
  ucg.setColor(235,0,200);
  ucg.print("si5351a VFO Ver1.1 JA2GQP" );

  ucg.setFont(ucg_font_osr18_tn);       //35 ucg_font_fub20_tf???
    ucg .setPrintPos(37,24);            //75,45
    ucg.setColor(0,255,0);
    ucg.print("7");                     //Frequency
    ucg.setPrintPos(51,24);             //103,45
    ucg.print(".");
    ucg.setPrintPos(138,24);            //273,45
    ucg.print("0");                     //Frequency  end
}

//--------------- VFO Write -------------------------------

void Vfo_write(){
  if (flagrit==0){
    if(hetero == UPPER)
      vfofreq=freq+ifshift;
    else
      vfofreq=ifshift-freq;
    Vfo_out(vfofreq);                               // DDS out
  }

  if(flagrit==1){
    if(hetero == UPPER)
      vfofreq=freq+ifshift+freqrit;
    else
      vfofreq=ifshift-freqrit-freq;
    Vfo_out(vfofreq);                              // DDS out
  }
  Bfo_out(ifshift);                                // BFO
}



      

15 件のコメント:

  1. 回路図のTFT分解能に誤記があり、修正した。

    返信削除
  2. BFOの送信シフト処理に問題が有った為、スケッチを修正し、Ver1.101とした。

    返信削除
  3. 坂本と申します常々拝見いたしておりありがとうございます。
    Adafruitのsi5351モジュールとArduinoでsi5351a2.hをつかわさせていただきマルチ出力を発振させてみました。拍子抜けするぐらい簡単に希望の2周波数と+10dmb以上ある出力が取り出せ感動いたしました、ありがとうございます。(これでAD9851からも卒業できそうです。^^)
    si5351aSetFrequency()で出力させてスペアナ(Gigast5)で見ますと単出力であれば基本周波数とN倍高調波のみできれいに並んでおりますが双出力にします片方の出力を影響を受けた表示となるようです。近接するck0 ck2 でしかも出力も大きいのでいたし方ないのかなとも思っております。

    返信削除
  4. すみません追伸です、Adafruitのsi5351モジュールがわずかですが低い周波数となるようです。モジュールは10pFで設定されているようですが
    #define XTAL_LOAD_C 183 を適当に変更してみたのですが変化なしでした。
    お教えください。

    返信削除
  5. 初めまして、田口 典克と申します。
    休眠中のアマチュア無線家です。
    リタイヤ後の過ごし方を模索中の中で、昔趣味にしていた
    ラジオの製作をコツコツとはじめています。
    JA2GQP水野さんとJA2NKD松浦さんのブログには大変おせわになっています。

     既に、参考にさせていただいた記事で、DDS VFO(7MHzシングルSP用)
    とRF ANALYZER は完成し、活躍をはじめました。

     最近、SOLTEC工房さんより手に入れたキット基板でSi5351仕様のVFOの製作
    に取り掛かり、ハードウェアーは、完成したのですがスケッチをどうしても
    旨く書き込めないのです。秋月より購入した。ARDUINO NANO互換機(Next purpie)
    が原因とも思えないので、書き込み手順に何か原因が有るのかよくわかりません!
    大変恐縮ですが、なにか手がかりになる事がありましたら御教示願えればと思い
    投稿させていただきました。

    返信削除
    返信
    1. 田口さん こんにちは

      水野です。

      SOFTECのVFOとの事、了解です。

      まず、コンパイルする環境として、スケッチと同じフォルダにsi5351a2.hを置いてください。
      ヘッダーファイルが正しく設定されていれば、コンパイルは通るはずです。

      次に、Arduino IDE ツールのボード:”Arduino Nano”、プロセッサ:”ATmega328P”と
      なってますか?
      更に、シリアルポートが正しく認識されてますか?

      秋月のボードの素性が判りませんが、シリアルポートを正しく認識しているか確認して下さい。
      (コントロールパネルからデバイスマネージャを開いて確かめれば良いと思います。)

      ボード、CPU、シリアルポートが正しく設定されていれば、書込み出来る筈です。

      それでも不明であれば、エラーメッセージの画面を送ってください。
                                          以上

      削除
    2. ご連絡ありがとうございます。
      田口です。

      早速ですが、si5351a2.hの#includeエラーはでなくなりましたが今度は、
      #include  ・・・・
      でコンパイルエラーとなってしまいました。

      ソフトはさっぱり理解できていないので、いちいち私のボケ頭脳は、
      フリーズしてしまいます。

      Arduino IDEツールの認識と設定関係は、水野さんのご指摘の通りに
      なっていますので書き込み段階のチェックはOKかと思います。

      このブログ上で画像の添付方法がわかりませんのでメールアドレスを
      G-mail宛にご連絡いただけらば、表示された内容をPDFにしたファイルを
      送ります。

      大変、お手数をお掛けして申し訳ありませんが、よろしくお願いいたします。

      削除
  6. 追伸、田口です。
    エラーメッセージは、
    「C:\Users\90010017\Downloads\si5351_TFT181\si5351_TFT181.ino:27:20: fatal error: Rotary.h: No such file
    ordirectory
    #include

    ^
    compilation terminated.exit status 1ボードArduino Nanoに対するコンパイル時にエラーが発生しました。」

    です。

    返信削除
    返信
    1. 田口さん
      こちらにメール下さい。
      ja2gqp@gmail.com

      削除
    2. 田口さん
      水野です。
      原因が判りました。Rotaly.hがインストールされてない為に、エラーになっている様です。こちらからダウンロードして、ライブラリをインストールしてください。
      https://github.com/brianlow/Rotary

      削除
  7. I am using a tft display with ILI9341 18xx240x320. I only have VFO displaying in upper left 1/4 quadrant of the display I have worked for 2 weeks every day trying to figure what is wrong. I am turning to you for help.
    How can I make the VFO fill the whole screen? My email is rholsti@icloud.com Thank you, I hope to hear from you soon. 73's, KH2BR


    ILI9341 18xx240x320でTFTディスプレイを使用しています。何が問題なのかを理解するために毎日2週間作業したディスプレイの左上1/4象限にVFOを表示しているだけです。私はあなたに助けを求めています。
    VFOを画面全体に表示させるにはどうすればよいですか?私のメールはrholsti@icloud.comです。ありがとうございます。ご連絡をお待ちしております。 73年代、KH2BR
    ILI 9341 18 xx 240 x 320 de TFT disupurei o shiyō shite imasu. Nani ga mondaina no ka o rikai suru tame ni mainichi 2-shūkan sagyō shita disupurei no hidariue 1/ 4 shōgen ni VFO o hyōji shite iru dakedesu. Watashi wa anata ni tasuke o motomete imasu. VFO o gamen zentai ni hyōji sa seru ni wa dōsureba yoidesu ka? Watashi no mēru wa rholsti@ icloud. Komudesu. Arigatōgozaimasu. Go renraku o omachi shite orimasu. 73-Nendai, KH 2 BR

    返信削除
  8. saya mengupload program VFO ini dan sudah tampil di display st7735 dgn tampilan frekuensi output dari 7.000.000 s/d 7.200.000 saja
    yang kami tanyakan dibagian mana sketch yang perlu di edit jika akan menampilkan frekuensi output dari minimum 3.000.000 s/d 30.000.000
    atas jawabannya sebelum dan sesudahnya diucapkan terima kasih

    salam

    M zuri

    返信削除
  9. Mohon maaf tulisan diatas kami betulkan menjadi :
    saya mengupload program VFO ini dan sudah tampil di display st7735 dgn tampilan frekuensi frekuensi dari 7.000.000 s / d 7.200.000 saja
    yang kami tanyakan dibagian mana sketch yang perlu di edit jika akan menampilkan frekuensi output dari minimum 3.000.000 dam maximum 30.000.000
    atas jawaban sebelum dan sebelum diucapkan terima kasih

    返信削除
  10. For many months I have tried to make your ILI9431 VFO work properly. The breadboard setup passes all the examples and they display properly.

    From what I see, the fixed part of the display is showing properly but none of the variable data appears. A "0" does show on the frequency space, however.

    I can't tell if the rotor works because there in on visible frequency. The RF analyzer does work on the same breadboard. Other scripts work as well.

    Any suggestions of where to look? Thanks, Jack

    返信削除
  11. Hi JACK
    There was a case where the operation was unstable.
    Please download it from the download site as it has been fixed.
    https://sites.google.com/view/en2gqp
    si5351a_TFT181.zip in the si5351s TFT folder

    返信削除