2019年1月22日火曜日

AFPSN用VFO

dsPICとMAX2452を組合わせたAFPSN用のVFOである。MAX2452のローカル発振は、目的周波数の2倍が必要な為、送信用VFOとした。設計に当たり、拡張性のあるH/Wを目指す事にし、I2Cを多用した。今迄のsi5351VFOは、カスタムライブラリを使っていたが、今回はgithubのものを使っている。

VFOの主な仕様
1)8チャンネルメモリー
2)メモリー自動書き込み
3)BPF、LPF切替
4)周波数範囲チェック
5)自動モード切替
6)STEP 100Hz、1k、10k、100k、
      1M




回路図


回路図である。I2Cデバイスのアドレスが判る様に記入した。EXTスイッチは、拡張用に割り付けたが未使用。TD62083のOut1からOut8は、リレー駆動用。










スケッチ

Arduino IDE1.8.8でコンパイルした。ライブラリの相性善し悪しで、I2Cデバイス動作が左右される。その為、スケッチのフォルダーにsrcフォルダーを作り、ライブラリを入れた。必要なファイルは、JA2GQP's Download siteのafpsnフォルダーからダウンロード可能。
バンドの概念が無いので、どのチャンネルにどんなバンド帯でも設定が出来るが、設定したチャンネル番号でBPF、LPFを切替えているので注意。

//////////////////////////////////////////////////////////////////////
//  si5351a PLL AFPSN VFO program ver.1.0
//    Copyright(C)2019.JA2GQP.All rights reserved.
//
//                                                2019/1/22
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.STEP(1M,100k,10k,1k,100)
//    2.Memory Channel ch0 - ch7(8ch)
//    3.Protection Operation At The Time Of Transmission
//////////////////////////////////////////////////////////////////////
//       PCF8574  https://github.com/xreef/PCF8574_library

#include "src/si5351.h"                      // Ver2,1,0
#include "src/LiquidCrystal_I2C.h"           //    1.1.2
#include "src/Rotary.h"
#include <EEPROM.h>
#include "src/PCF8574.h"

//---------- Set I/O Device ---------------------

PCF8574 pcf8574(0x20);                    // Set i2c address
LiquidCrystal_I2C lcd(0x27,16,2);       // address 0x27, display 16x2
Si5351 si5351;
Rotary r = Rotary(2,3);                  // 2 = Encorder A, 3 = Encorder B

//----------  Define Constant Value   ----------
                                               
const byte  SW_STEP = 4;                   // STEP SW
const byte  SW_CH = 5;                     // CH SW
const byte  SW_TX = 9;                     // TX SW
const byte  OUT_MODE = 13;                 // OUTPUT Mode

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

////////////////////////////////
// default value
////////////////////////////////
const long  DEF_FRQ = 7050000L;            // Default Vfo(7.05MHz)
const long  DEF_STP = 1000L;               // Init STEP(1kHz)

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

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

const byte  Frq_Eep = 0x00;                // Frequency(4byte*10)
const byte  Stp_Eep = 0x30;                // STEP(4byte*10)
const byte  Chn_Eep = 0x60;                // Channel(1byte*1)
const byte  Vfo_Eep = 0x62;                // Vfo mode(1byte*1)
const byte  Eep_Int = 0x6e;                // Eep Init(1byte*1)

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

unsigned long Vfo_Dat = 0;                 // VFO Data
unsigned long Vfo_Datb = 0;                //          old
unsigned long Enc_Stp = 0;                 // STEP
long timepassed;                           // int to hold the arduino miilis since startup

char *Lcd_Dat = "           ";             // Lcd Display Buffer
char *Mode = "    ";                       // Mode display
byte Byt_Chn = 0;                          // Channel SW
byte Byt_Chnb = 0;                         // Channel SW Old
byte Flg_Tx = 0;                           // TX Flag
byte Flg_eepWT = 0;                        // EEP Write Flag
byte Flg_Mode = 0;                         // Mode Flag
char Flg_Over;                             // Over Flag
byte Flg_Vfo = 0;                          // DDS Flag
byte Byt_Vfo = 0;                          // VFO Mode

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

void setup(){
  pcf8574.pinMode(P0,OUTPUT);              // PCF8574 Set pinMode to OUTPUT
  pcf8574.pinMode(P1,OUTPUT);
  pcf8574.pinMode(P2,OUTPUT);
  pcf8574.pinMode(P3,OUTPUT);
  pcf8574.pinMode(P4,OUTPUT);
  pcf8574.pinMode(P5,OUTPUT);
  pcf8574.pinMode(P6,OUTPUT);
  pcf8574.pinMode(P7,OUTPUT);

  pcf8574.begin();

  pcf8574.digitalWrite(P0,LOW);
  pcf8574.digitalWrite(P1,LOW);
  pcf8574.digitalWrite(P2,LOW);
  pcf8574.digitalWrite(P3,LOW);
  pcf8574.digitalWrite(P4,LOW);
  pcf8574.digitalWrite(P5,LOW);
  pcf8574.digitalWrite(P6,LOW);
  pcf8574.digitalWrite(P7,LOW);

  si5351.init(SI5351_CRYSTAL_LOAD_8PF,0,0);//initialize the Si5351
  si5351.set_freq(0,SI5351_CLK0);          // Dummy Frequency data
  si5351.output_enable(SI5351_CLK0,0);     // CLK0 disable

  lcd.begin();
  lcd.backlight();

  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH,INPUT_PULLUP);
  pinMode(OUT_MODE,OUTPUT);

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

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

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

  Byt_Chn = EEPROM.read(Chn_Eep);         //     Channel
  pcf8574.digitalWrite(Byt_Chn,HIGH);
  Byt_Chnb = Byt_Chn;
  Fnc_Eep_Rd();                            //     VFO & STEP
}

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

void loop() {

  if(Flg_Tx == 0){                        // TX off?
    if(digitalRead(SW_STEP) == LOW)       // STEP SW On?
      Fnc_Stp();                           

    if((digitalRead(SW_CH) == LOW))       // SEL SW On?
      Fnc_Chsw();                           

    if(Byt_Chnb != Byt_Chn){              // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      pcf8574.digitalWrite(Byt_Chnb,LOW);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
    }
  }

  if(digitalRead(SW_TX) == LOW){             // Tx On?
    Flg_Tx = 1;                              //    Yes,Flg_Tx Set
    si5351.output_enable(SI5351_CLK0, 1);    // VFO enable
  }
  else{                                   
    Flg_Tx = 0;                             //     No,Flg_Tx Reset
    si5351.output_enable(SI5351_CLK0, 0);   // VFO disable
  }

  Fnc_Band();                               // Band check

  if(Vfo_Dat != Vfo_Datb){                  // Frequency update?
    si5351.set_freq((Vfo_Dat * SI5351_FREQ_MULT) * 2,SI5351_CLK0);
    Fnc_Fdsp(Vfo_Dat);
    Vfo_Datb = Vfo_Dat;
    timepassed = millis();
    Flg_eepWT = 1;
  }
 
  Fnc_Lcd();                                // LCD Display

  if(Flg_eepWT == 1){                       // EEPROM auto Write
    if(timepassed+2000 < millis()){
      Fnc_Eep_Wt(Byt_Chn);
      Flg_eepWT = 0;
    }
  } 


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

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

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

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

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

  if(Flg_Mode == 0){                      // LSB ?
    digitalWrite(OUT_MODE, HIGH);       
    lcd.print("LSB ");
  }
  else if(Flg_Mode == 1){                 // USB ?
    digitalWrite(OUT_MODE, LOW);       
    lcd.print("USB ");
  }
}

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

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

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

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

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

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

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

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

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

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

//----------  Function Write EEPROM 4byte  ---------

void Fnc_Eep_Write(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 Read EEPROM 4byte  ---------

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

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

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

void Fnc_Lcd(){
  lcd.setCursor(0,0);
  if(Flg_Tx == 1)
    lcd.print("T");
  else{
    lcd.print(Byt_Chn);
    pcf8574.digitalWrite(Byt_Chn,HIGH);
  }
 
  Fnc_Step_Disp();

    if(Flg_Over == -1){
      Fnc_Fdsp(Vfo_Dat);
      lcd.setCursor(5,1);
      lcd.print("Over");
    }
    else
      Fnc_Fdsp(Vfo_Dat);

  if(Flg_Over == 0){ 
    Fnc_Mode();
    lcd.setCursor(10,1);
    lcd.print(CALL);
  }
}

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

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

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

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

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

void Fnc_Eep_Int(){
  int i;

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

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

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

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

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

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

  Byt_Vfo = EEPROM.read(Vfo_Eep);
}

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

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

  EEPROM.write(Chn_Eep,chn);
}

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

void Fnc_Band(){
  if((Vfo_Dat >= LW_VFO80) && (Vfo_Dat <= HI_VFO80)){           // 3.5MHz
    Flg_Mode = 0;                                               //    LSB(0=LSB, 1=USB)   
    Flg_Over = 0;
  }
  else if((Vfo_Dat >= LW_VFO40) && (Vfo_Dat <= HI_VFO40)){      // 7MHz
    Flg_Mode = 0;                                               //    LSB(0=LSB, 1=USB)
    Flg_Over = 0;
  }
  else if((Vfo_Dat >= LW_VFO20) && (Vfo_Dat <= HI_VFO20)){      // 14MHz
    Flg_Mode = 1;                                               //    USB(0=LSB, 1=USB)
    Flg_Over = 0;
  }
  else if((Vfo_Dat >= LW_VFO15) && (Vfo_Dat <= HI_VFO15)){      // 21MHz
    Flg_Mode = 1;                                               //    USB(0=LSB, 1=USB)
    Flg_Over = 0;
  }
  else if((Vfo_Dat >= LW_VFO10) && (Vfo_Dat <= HI_VFO10)){      // 28MHz
    Flg_Mode = 1;                                               //    USB(0=LSB, 1=USB)
    Flg_Over = 0;
  }
  else if((Vfo_Dat >= LW_VFO6) && (Vfo_Dat <= HI_VFO6)){        // 50MHz
    Flg_Mode = 1;                                               //    USB(0=LSB, 1=USB)
    Flg_Over = 0;
  }
  else
    Flg_Over = -1;
}
    
    

0 件のコメント: