2021年12月31日金曜日

uSDX

uSDXをWeb検索してたら、FTS3253の替わりに74HC4053を使ったHF5L の記事がHitした。Arduino nano 16MHz(無改造)とsi5351module(改造)を使って簡素化した回路である。ユニバーサル基板で作れるとの事だったので、早速作ってみた。一部変更したが、殆ど回路図通り配線。WB2CBAのLPFは、AADE Filter Designでシュミレーションした。電源電圧13.8V(ダイオードの短絡保護回路を入れているので、13.2V位)で試験を行った。パラメータをデフォルト値で、7MHz時3.4W、28MHz時2.6W。また、オールモード動作確認もできた。








回路図


    




 


 

      




si5351モジュール改造

1.赤丸6か所の部品を外す。


   



      







 2.1k 2か所、0オーム(ジャンパー) 2か所 部品を付ける 。



WB2CBA LPFシュミレーション

7MHz時





 






C1=330pF、L2=0.1083uH T37-6 19t、C2+C3=470pF、C4=102、C5=330pF、C6=102、L3=0.363uH T37-6 11t


28MHz時

C1=68pF、L2=0.192uH T37-6 8t、C2+C3=180pF、C4=330pF、C5=100pF、C6=330pF、L3=0.075uH T37-6 5t


スケッチ

Version1.02wを変更修正

1.行12 #define CAT 1をコメントに変更。

  //#define CAT 1

2.行13 #define F_XTAL    27005000をコメントに変更。

  //#define F_XTAL    27005000

3.行15 //#define F_XTAL  25000000を//外して宣言文を有効にする。

  #define F_XTAL  25000000

4.行29 //#define F_MCU   16000000を//外して宣言文を有効にする。

  #define F_MCU   16000000

5. 行73 #define SIG_OUT 11 11を13に変更。

  #define SIG_OUT 13

6.行75 #define DIT     13 13を11に変更。

  #define DIT     11

修正済みのスケッチ、回路図などDownload siteからuSDX.zipをダウンロード可能。  





2021年8月1日日曜日

oled CB VFO

oled 50MHz AM VFOのCB版。VFO/チャンネルの2モード方式は、50MHz AM版と全く同じである。違いは、CBの場合、指定された周波数のみでの運用である。そのため、VFO周波数が指定された周波数であるか否かをチェックしなければならない。50MHzバンド外と同様に、送信時に--.---.--と表示される。EEPROMにデータ保存しているので、電源off後、直前の状態に復帰する。




操作

・EEPROM初期化

  STEP SWを押しながら、電源onして”ーー.---.--” が表示されるまでSTEP SWを押していると、EEPROMの初期化が行われる。

・VFOモード(上の写真は、チャンネルモード)

 STEP SWを長押しすると、VFOモードからチャンネルモード、または、チャンネルモードからVFOモードに変わる。

チャンネル書き換え

 チャンネルモードの時、RIT SWを長押しし、VFOモードを表示させ希望の周波数に変更する。再び、RIT SWを長押しするとチャンネルモードに表示が変わり、変更されたチャンネルデータで表示される。書き換え可能なチャンネルは、”0”、”9”のみである。チャンネル”1”から”8”は指定周波数なので書き換え不可。


回路図


   










スケッチ

コンパイルする時、必要に応じマーカ部分の変更をする。

・RX_IF = 455000 受信時のオフセット。初期値 455000(+455kHz)

・TX_IF = 0 送信時のオフセット。初期値 0

・Int_End = 49 プログラムからの初期化を行う時の、初期化終了判断コード。

残っている前回データをクリアして、新しい初期値をセットしたいときに使う。前回の判断コードと同じ場合は、初期化されないので注意。


必要なファイルは、JA2GQP Download siteのsi5351 VFOフォルダからダウンロード出来る。


//////////////////////////////////////////////////////////////////////

//  si5351a oled(128x32) VFO program ver.1.0

//    Copyright(C)2019.JA2GQP.All rights reserved.

//

//                                                2021/7/29

//                                                  JA2GQP

//--------------------------------------------------------------------

//  Function

//    1.VFO/Channel mode

//    2.STEP(10k,1k)

//    3.Automatic memory

//    4.Protection Operation At The Time Of Transmission

//    5.S-Meter

//////////////////////////////////////////////////////////////////////


#include "src/Rotary.h"               // http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html

#include "src/si5351.h"               // https://github.com/etherkit/Si5351Arduino, v2.1.0

#include "src/SSD1306AsciiAvrI2c.h"   // https://github.com/greiman/SSD1306Ascii

#include <EEPROM.h>



////////////////////////////////

// Set Device 

////////////////////////////////

Rotary r = Rotary(2, 3);              

Si5351 si5351(0x60);                  // Si5351 I2C address

SSD1306AsciiAvrI2c oled;


////////////////////////////////

// I/O Port

////////////////////////////////

const byte SW_RIT = A0;               // RIT SW

const byte SW_STEP = A1;              // STEP SW

const byte SW_TX = A2;                // TX/RX

const byte AD_SM = A7;                // S-meter AD


////////////////////////////////

// EEPROM Memory Address

////////////////////////////////

const byte  Eep_Init = 0x00;          // Eep Init(1byte*1)

const byte  Eep_Band = 0x01;          // Band(1byte*1)

const byte  Eep_Ch = 0x02;            // Channel(1byte*1)

const byte  Eep_Chan = 0x03;          // VFO-Channel Mode(1byte*1)

const byte  Eep_Freq = 0x10;          // Frequency(4byte*5)

const byte  Eep_Step = 0x30;          // STEP(4byte*5)

const long  Eep_Chfreq = 0x50;        // Channel(4byte*5)


////////////////////////////////

// frquency data

////////////////////////////////

const unsigned long FRQ_TBL[5] = {

 // DEF_F    CW_F      SSB_F     AM_F      HI_F

  26968000 ,26515000 ,26515000 ,26515000 ,27855000

  };


const unsigned long CH_TBL[] = {          // Initial frequency value

  27524000 ,26968000 ,26976000 ,27040000 ,27080000 ,

  27088000 ,27112000 ,27120000 ,27144000 ,27005000

  };

const byte  Max_Chan = sizeof(CH_TBL) / sizeof(CH_TBL[0]);  // Max Channel


//---- data offset -----

const byte DEF_F = 0;

const byte CW_F = 1;

const byte SSB_F = 2;

const byte AM_F = 3;

const byte HI_F  = 4; 

//---- IF offset -------

const unsigned long RX_IF = 455000  // RX_IF offset = +455kHz 

const unsigned long TX_IF = 0;        // TX_IF offset 


////////////////////////////////

// Encorder STEP

////////////////////////////////

const int STEP_50 = 50;               // STEP 50Hz

const int STEP_1k = 1000;             //      1k

const int STEP_10k = 10000;           //      10k


////////////////////////////////

// etc

////////////////////////////////

const byte  Int_End = 49;             // Initial end code

const char Call[9] = "JA2GQP";        // Display Call sign


////////////////////////////////

// Memory Assign

////////////////////////////////

unsigned long Vfo_Dat;                // VFO Data

unsigned long Ch_Dat;                 // Channel Data

int Rit_Dat;                          // RIT Data

unsigned long Enc_Step;               // STEP

char Enc_Dir = 0;                     // -1 DIR_CCW, 0 DIR_NONE, 1 DIR_CCW

byte Ch_Index = 0;                    // Channel TBL index

unsigned int Val_Smeter = 0;

unsigned int Val_Smeterb = 1;


long Time_Passd;                      // int to hold the arduino miilis since startup

long Time_Mode;                       // Mode change Time

byte Flg_eepWT = 0;                   // EEP Write Flag


byte Flg_Mode = 3;

byte Flg_Over = 0;

byte Flg_Vfo = 0; 

byte Flg_Tx = 0;

byte Flg_Chan = 0;                    // Channel Flag 0:VFO, 1:Cannel

byte Disp_Over = 1;

byte Disp_Freq = 1;

byte Disp_Tx = 0;

byte Disp_Rit = 0;

byte Flg_Rit = 0;                     // RIT Flag


//----------  setup  ----------------------------------------------------


void setup() {

  pinMode(SW_STEP, INPUT_PULLUP);

  pinMode(SW_TX, INPUT_PULLUP);          

  pinMode(SW_RIT, INPUT_PULLUP);          

  pinMode(12, OUTPUT);                // pin12,pin13

  pinMode(13, OUTPUT);                // 0,0=CW 1,0=LSB 0,1=USB 1,1=AM           


  attachInterrupt(0, rotary_encoder, CHANGE);

  attachInterrupt(1, rotary_encoder, CHANGE);


  si5351.init(SI5351_CRYSTAL_LOAD_8PF,0,0);    // crystal 25.000 MHz, correction 0

  si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_4MA);//Drive lebel 4mA set 

  oled.begin(&Adafruit128x32, 0x3C);


  if(EEPROM.read(Eep_Init) != Int_End){        // Eep initialaz

    delay(10);

    eep_init();

  }

  else{

    if(digitalRead(SW_STEP) == LOW){

      delay(10);

      eep_init();

      fover_disp();

      while (digitalRead(SW_STEP) == LOW);

    }

  }

  eep_rdata();

  mode_disp();

  step_disp();

}


//----------  main  ----------------------------------------------------


void loop() {

  if(Flg_Chan == 0){

    vfo_mode();

  }

  if(Flg_Chan == 1){

    ch_mode();

  }

}


//----------  Channel mode  ------------------------------------------------


void ch_mode(){


////////////////////////

// receive

////////////////////////

  if(digitalRead(SW_TX) == HIGH){           

    Flg_Tx = 0;

    si5351.output_enable(SI5351_CLK0, 1);   // VFO enable 


    if (Flg_Rit == 0){

      if(Disp_Freq == 1){

        if((Ch_Index == 0) && (Enc_Dir == -1))

          Ch_Index = Max_Chan-1;

        else if((Ch_Index == Max_Chan-1) && (Enc_Dir == 1))  

          Ch_Index = 0;

        else

          Ch_Index += Enc_Dir;


        Enc_Dir = 0;


        Ch_Dat = eep_read4(Eep_Chfreq+Ch_Index*4);  // Channel data read

        band_check(Ch_Dat);                         // range check

        si5351_set_freq(Ch_Dat + RX_IF);            // frequency out

        ch_disp(Ch_Dat);                            // Channel display

        Disp_Freq = 0;


        Flg_Vfo = 1;

        mode_disp();

        Rit_Dat = 0;


        Time_Passd = millis();

        Flg_eepWT = 1;

      }

    }      

    else{

      if (Disp_Rit == 1){

        Rit_Dat += Enc_Dir * Enc_Step;

        Enc_Dir = 0;

        Rit_Dat = constrain(Rit_Dat, -5000, 5000);

        si5351_set_freq(Ch_Dat + RX_IF + Rit_Dat);

        rit_disp(Rit_Dat);

        mode_disp();

        Disp_Rit = 0;

        Flg_Vfo = 1;

      }

    }   


////////////////////////

// STEP

////////////////////////

    if (digitalRead(SW_STEP) == LOW) {      // increment events

      Time_Mode = millis();        


      while (digitalRead(SW_STEP) == LOW){

        if(Time_Mode+1000 < millis()){

          if(Flg_Chan == 0){                  // VFO mode?

            Flg_Chan = 1;                     //  yes,Channel mode set

            break;

          }  

          else{                               //  no,VFO mode

            Flg_Chan = 0;                   

            freq_disp(Vfo_Dat);               //  frequency display

            si5351_set_freq(Vfo_Dat + RX_IF); //  fequency data output

            Flg_Rit = 0;                      //  RIT reset

            Disp_Freq = 0;

            break;

          }

        }

      }


      while (digitalRead(SW_STEP) == LOW);

      if(Flg_Chan == 1){

        enc_step();

        step_disp();

      }

    }


////////////////////////

// RIT

////////////////////////

    if (digitalRead(SW_RIT) == LOW) {

      Time_Mode = millis();

      while (digitalRead(SW_RIT) == LOW){


        if((Ch_Index == 0) || (Ch_Index == 9)){

          if(Time_Mode+1000 < millis()){

            if(Flg_Chan == 1){

              Flg_Chan = 0;

 

              Vfo_Dat = Ch_Dat;

              freq_disp(Vfo_Dat);

              si5351_set_freq(Vfo_Dat + RX_IF);

              Flg_Rit = 0;

              break;

            }

          }

        }

        

      }


      while (digitalRead(SW_RIT) == LOW);

      if(Flg_Chan == 1){

        rit_disp(Rit_Dat);

        Fnc_Rit(); 

      }

    }

    Disp_Tx = 1;

  }


////////////////////////

// send

////////////////////////

  else{                                     

    Flg_Tx = 1;

    Disp_Over = 1;


    if(Flg_Over == 0){                      // Within transmittable range?

        freq_disp(Ch_Dat);                  // frequency display

      si5351.output_enable(SI5351_CLK0, 1); // VFO enable

      if(Flg_Vfo == 1){

        si5351_set_freq(Ch_Dat + TX_IF);

        Flg_Vfo = 0;

      }

      Disp_Freq = 1;

      Disp_Rit = 1;

    }

    else{                                   // Out of range

      si5351.output_enable(SI5351_CLK0, 0); // VFO disable 

      if(Disp_Over == 1){

        fover_disp();                       // Display of over range

        Disp_Over = 0;

      }

    }

    if(Disp_Tx == 1){

      tx_disp();

      Disp_Tx = 0;        

    }

    Disp_Freq = 1;  

  }


////////////////////////

// common

////////////////////////

  Val_Smeter = analogRead(AD_SM);

  if ((abs(Val_Smeter - Val_Smeterb)) > 3){ // if needed draw S-meter

    sm_disp();

    Val_Smeterb = Val_Smeter;

  }


  if(Flg_eepWT == 1){                       // EEPROM auto Write

    if(Time_Passd+2000 < millis()){

      eep_wdata();

      Flg_eepWT = 0; 

    }

  }

}   


//----------  VFO mode  ------------------------------------------------


void vfo_mode(){


////////////////////////

// receive

////////////////////////

  if(digitalRead(SW_TX) == HIGH){           

    Flg_Tx = 0;

    si5351.output_enable(SI5351_CLK0, 1);   // VFO enable 


    if (Flg_Rit == 0){

      if(Disp_Freq == 1){

        Vfo_Dat += Enc_Dir * Enc_Step;

        Enc_Dir = 0;

        

        si5351_set_freq(Vfo_Dat + RX_IF);

        freq_disp(Vfo_Dat);                  // frequency display

        Disp_Freq = 0;


        Flg_Vfo = 1;

        mode_disp();

        Rit_Dat = 0;


        Time_Passd = millis();

        Flg_eepWT = 1;

      }

    }      

    else{

      if (Disp_Rit == 1){

        Rit_Dat += Enc_Dir * Enc_Step;

        Enc_Dir = 0;

        Rit_Dat = constrain(Rit_Dat, -5000, 5000);

        si5351_set_freq(Vfo_Dat + RX_IF + Rit_Dat);

        rit_disp(Rit_Dat);

        mode_disp();

        Disp_Rit = 0;

        Flg_Vfo = 1;

      }

    }   


////////////////////////

// STEP

////////////////////////

    if (digitalRead(SW_STEP) == LOW) {      // increment events

      Time_Mode = millis();


      while (digitalRead(SW_STEP) == LOW){

        if(Time_Mode+1000 < millis()){

          if(Flg_Chan == 0){

            Flg_Chan = 1;

            ch_disp(Ch_Dat);

            si5351_set_freq(Ch_Dat + RX_IF);

            eep_wdata();

            Flg_Rit = 0;

            break;

          }  

          else{

            Flg_Chan = 0;

            break;

          }

        }

      }

      

      while (digitalRead(SW_STEP) == LOW);

      if(Flg_Chan == 0){

        enc_step();

        step_disp();

      }

    }


////////////////////////

// RIT

////////////////////////

    if (digitalRead(SW_RIT) == LOW) {

      Time_Mode = millis();

      while (digitalRead(SW_RIT) == LOW){

        if(Time_Mode+1000 < millis()){

          if(Flg_Chan == 0){

              eep_write4(Vfo_Dat,Eep_Freq);

              Ch_Dat = Vfo_Dat;

              ch_disp(Ch_Dat);

              eep_write4(Ch_Dat,Eep_Chfreq+Ch_Index*4);

              si5351_set_freq(Ch_Dat + RX_IF);

              Flg_Rit = 0;

              Flg_Chan = 1;

              break;

          }

        }

      }


      while (digitalRead(SW_RIT) == LOW);

      if(Flg_Chan == 0){

        rit_disp(Rit_Dat);

        Fnc_Rit(); 

      }

    }

    Disp_Tx = 1;

  }


////////////////////////

// send

////////////////////////

  else{                                     

    Flg_Tx = 1;

    Disp_Over = 1;

    band_check(Vfo_Dat);                        // range check


    

    if(Flg_Over == 0){                      // Within transmittable range?

        freq_disp(Vfo_Dat);                 // frequency display

      si5351.output_enable(SI5351_CLK0, 1); // VFO enable

      if(Flg_Vfo == 1){

        si5351_set_freq(Vfo_Dat + TX_IF);

        Flg_Vfo = 0;

      }

      Disp_Freq = 1;

      Disp_Rit = 1;

    }

    else{                                   // Out of range

      si5351.output_enable(SI5351_CLK0, 0); // VFO disable 

      if(Disp_Over == 1){

        fover_disp();                       // Display of over range

        Disp_Over = 0;

      }

    }

    if(Disp_Tx == 1){

      tx_disp();

      Disp_Tx = 0;        

    }

    Disp_Freq = 1;  

  }


////////////////////////

// common

////////////////////////

  Val_Smeter = analogRead(AD_SM);

  if ((abs(Val_Smeter - Val_Smeterb)) > 3){ // if needed draw S-meter

    sm_disp();

    Val_Smeterb = Val_Smeter;

  }


  if(Flg_eepWT == 1){                       // EEPROM auto Write

    if(Time_Passd+2000 < millis()){

      eep_wdata();

      Flg_eepWT = 0; 

    }

  }

}   


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


void Fnc_Rit(){

  if(Flg_Rit == 0){

    Rit_Dat = 0;

    Flg_Rit = 1;

  }

  else{

    Flg_Rit = 0;

    Disp_Freq = 1;

  }


//----------  RIT Display  ---------------------------------------------


void rit_disp(int rit_data) {

  unsigned int ri,rit;


  oled.setFont(lcdnums14x24);

  oled.setCursor(1, 0);

  oled.print("::::");


  if (rit_data < 0)

    oled.print('-');

  else

    oled.print('+');


  rit = abs(rit_data);

   ri = rit / 1000;  

  oled.print(ri);

  oled.print('.');

  ri = (rit % 1000) / 10;

  if (ri < 10)

    oled.print('0');

  oled.print(ri);

}


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


void eep_write4(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--;

  }

}


//----------  Read EEPROM 4byte  ---------------------------------------


long eep_read4(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;

}


//----------  EEPROM Dat Read  -----------------------------------------


void eep_rdata(){

  Vfo_Dat = eep_read4(Eep_Freq);

  Enc_Step = eep_read4(Eep_Step);

  Ch_Index = EEPROM.read(Eep_Ch);

  Flg_Chan = EEPROM.read(Eep_Chan);

  Ch_Dat = eep_read4(Eep_Chfreq+Ch_Index*4);

}


//----------  EEPROM Dat Write  ----------------------------------------


void eep_wdata(){

  eep_write4(Vfo_Dat,Eep_Freq);

  eep_write4(Enc_Step,Eep_Step);

  EEPROM.write(Eep_Ch,Ch_Index);            // Ch_Index set  

  EEPROM.write(Eep_Chan,Flg_Chan);          // VFO-Channel 0:VFO 1:Channel  

  eep_write4(Ch_Dat,Eep_Chfreq+Ch_Index*4);

}  

    

//----------  EEPROM Initialization ------------------------------------


void eep_init(){

  int i;


  for (i=0;i<128;i++)                       // 0 clear(128byte)

    EEPROM.write(i, 0);


  eep_write4(FRQ_TBL[DEF_F],Eep_Freq);

  eep_write4(STEP_1k,Eep_Step);            // Step(1kHz)

  EEPROM.write(Eep_Ch,Ch_Index);           // Ch_Index set  

  EEPROM.write(Eep_Chan,Flg_Chan);         // Ch_Index set  


  for(i=0;i<Max_Chan;i++)

    eep_write4(CH_TBL[i],Eep_Chfreq+i*4);  


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

}


//----------  Rotaly Encorder  -----------------------------------------


void rotary_encoder() {                     // rotary encoder events

  uint8_t result = r.process();


  if(Flg_Tx == 0){

    if (result) {

      Disp_Freq = 1;

      Disp_Rit = 1;

      if (result == DIR_CW)

        Enc_Dir = 1;

      else

        Enc_Dir = -1;

    }

  }

}


//----------  si5351 PLL Output  ---------------------------------------


void si5351_set_freq(uint32_t frequency) {

  si5351.set_freq(frequency * SI5351_FREQ_MULT, SI5351_CLK0);

}


//----------  Encorede STEP  -------------------------------------------


void enc_step() {

  if(Enc_Step == STEP_1k)

    Enc_Step = STEP_10k;                    // 10k

  else    

    Enc_Step = STEP_1k;                     // 1k

}


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


void step_disp() {

  oled.setCursor(109, 3);

  oled.setFont(labels);

  if (Enc_Step == STEP_50)

    oled.print("6");                        // 50Hz

  else if(Enc_Step == STEP_1k)

    oled.print("8");                        // 1k

  else

    oled.print("9");                        // 10k

}


//---------- Frequency renge over --------------------------------------


void fover_disp() {

  oled.setFont(lcdnums14x24);

  oled.setCursor(1, 0);

  oled.print("--.---.--");

}


//---------- callsign display ------------------------------------------


void call_disp() {

  oled.setFont(Arial_bold_14);

  oled.setCursor(56, 6);

  oled.print(Call);

}


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


void freq_disp(uint32_t sf_rx) {

  uint16_t fr;


  oled.setFont(lcdnums14x24);

  oled.setCursor(1, 0);

  fr = sf_rx / 1000000;

  if (fr < 10)

    oled.print(':');                        // ':' is changed to ' ' in lcdnums14x24.h

  oled.print(fr);

  oled.print('.');

  fr = (sf_rx % 1000000) / 1000;

  if (fr < 100)

    oled.print('0');

  if (fr < 10)

    oled.print('0');

  oled.print(fr);

  oled.print('.');

  fr = (sf_rx % 1000) / 10;

  if (fr < 10)

    oled.print('0');

  oled.print(fr);

}


//----------  Channel Display  -----------------------------------------


void ch_disp(uint32_t sf_rx) {

  uint16_t fr;


  oled.setFont(lcdnums14x24);

  oled.setCursor(1, 0);

  oled.print(Ch_Index);


  oled.print("::");                        // ':' is changed to ' ' in lcdnums14x24.h


  fr = sf_rx / 1000000;

  if (fr < 10)                            

    oled.print(':');                      // ':' is changed to ' ' in lcdnums14x24.h

  oled.print(fr);


  oled.print('.');

  fr = (sf_rx % 1000000) / 1000;

  if (fr < 100)

    oled.print('0');

  if (fr < 10)

    oled.print('0');

  oled.print(fr);


}


//---------- TX display ------------------------------------------------


void tx_disp() {

  oled.setCursor(2, 3);

  oled.setFont(labels);

  oled.print("1");                          // "1" is "TX" in labels.h

}


//---------- Mode display ----------------------------------------------


void mode_disp() {

  oled.setCursor(2, 3);

  oled.setFont(labels);

  if (Flg_Mode == 0){

    oled.print("2");                        // "2" is "CW" in labels.h

//    oled.print("/");                        // "/" is "AM" in labels.h

    digitalWrite(12,LOW);

    digitalWrite(13,LOW);

  }

  else if(Flg_Mode == 1){

    oled.print("3");                        // "3" is "LSB"

    digitalWrite(12,HIGH);

    digitalWrite(13,LOW);

  }

  else if(Flg_Mode == 2){

    oled.print("4");                        // "4" is "USB"

    digitalWrite(12,LOW);

    digitalWrite(13,HIGH);

  }

  else if(Flg_Mode == 3){

    oled.print("/");                        // "/" is "AM"

    digitalWrite(12,HIGH);

    digitalWrite(13,HIGH);

  }

}


//----------  S-Meter Display  -----------------------------------------


void sm_disp() {

  uint8_t a = 0;

  uint8_t m = 0;


  a = (Val_Smeter + 3) / 113;  // 1024 / 9 characters for S = 1,3,5,7,8,9,+10,+20,+30

  oled.setFont(pixels);

  oled.setCursor(25, 3);

  for (m = 0; m < a; m++)

    if (m < 6)

      oled.print('7');                      // '5' - hollow rectangle, 6px

    else

      oled.print('8');                      // '6' - filled rectangle, 6px

  for (m = a; m < 9; m++)

    oled.print('.');                        // '.' 1px

}


//----------  band chek  -----------------------------------------------


void band_check(unsigned long freq){

  Flg_Over = 1;

  for(int i=1;i<9;i++){

    if(freq == CH_TBL[i]){

      Flg_Over = 0;

      break;

    }

  }

  Flg_Mode = 3;

}


2021年7月25日日曜日

oled 50MHz AM VFO

表示器にoledを使った50MHz AM VFOである。50MHz AMを運用すると、周波数の連続可変は殆ど必要ない。そこで、チャンネル機能を含めたVFOを作った。特徴は、VFO/チャンネルの2モードで、共にRIT運用が可能。VFO/チャンネルはEEPROMに保存しいてる。電源off直前のVFO/チャンネルを保存してるので、電源on時の煩雑さは無い。VFO/チャンネルの切替は、STEPスイッチの長押しで行う。また、チャンネル周波数は、EEPROMに保存してるので、書き換え可能。


チャンネルモードの表示である。チャンネル切替は、エンコーダ操作。チャンネル周波数の初期値以外への変更は、RITスイッチを長押しし、VFOモードに移行して変更。











回路図


         

 


   




フォント     

今回、追加したAMフォントである。labels.hを変更修正。









スケッチ

ファイルは、JA2GQP's Download site si5351 VFOフォルダのoled_50MHz_AM.zipをダウンロードすれば良い。

//////////////////////////////////////////////////////////////////////
//  si5351a oled(128x32) VFO program ver.1.0
//    Copyright(C)2019.JA2GQP.All rights reserved.
//
//                                                2021/7/24
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.VFO/Channel mode
//    2.STEP(10k,1k,50)
//    3.Automatic memory
//    4.Protection Operation At The Time Of Transmission
//    5.Automatic mode switching
//    6.S-Meter
//////////////////////////////////////////////////////////////////////

#include "src/Rotary.h"               // http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
#include "src/si5351.h"               // https://github.com/etherkit/Si5351Arduino, v2.1.0
#include "src/SSD1306AsciiAvrI2c.h"   // https://github.com/greiman/SSD1306Ascii
#include <EEPROM.h>


////////////////////////////////
// Set Device 
////////////////////////////////
Rotary r = Rotary(2, 3);
Si5351 si5351(0x60);                 // Si5351 I2C address
SSD1306AsciiAvrI2c oled;

////////////////////////////////
// I/O Port
////////////////////////////////
const byte SW_RIT = A0;               // RIT SW
const byte SW_STEP = A1;              // STEP SW
const byte SW_TX = A2;                // TX/RX
const byte AD_SM = A7;                // S-meter AD

////////////////////////////////
// EEPROM Memory Address
////////////////////////////////
const byte  Eep_Init = 0x00;          // Eep Init(1byte*1)
const byte  Eep_Band = 0x01;          // Band(1byte*1)
const byte  Eep_Ch = 0x02;            // Channel(1byte*1)
const byte  Eep_Chan = 0x03;          // VFO-Channel Mode(1byte*1)
const byte  Eep_Freq = 0x10;          // Frequency(4byte*5)
const byte  Eep_Step = 0x30;          // STEP(4byte*5)
const long  Eep_Chfreq = 0x50;        // Channel(4byte*5)

////////////////////////////////
// frquency data
////////////////////////////////
const unsigned long FRQ_TBL[5] = {
 // DEF_F    CW_F      SSB_F     AM_F      HI_F
  50600000 ,50000000 ,50200000 ,50500000 ,51000000
  };

const unsigned long CH_TBL[] = {          // Initial frequency value
  50500000 ,50550000 ,50600000 ,50620000
  };
const byte  Max_Chan = sizeof(CH_TBL) / sizeof(CH_TBL[0]);  // Max Channel

//---- data offset -----
const byte DEF_F = 0;
const byte CW_F = 1;
const byte SSB_F = 2;
const byte AM_F = 3;
const byte HI_F  = 4; 
//---- IF offset -------
const unsigned long RX_IF = 0;        // RX_IF offset 
const unsigned long TX_IF = 0;        // TX_IF offset 

////////////////////////////////
// Encorder STEP
////////////////////////////////
const int STEP_50 = 50;               // STEP 50Hz
const int STEP_1k = 1000;             //      1k
const int STEP_10k = 10000;           //      10k

////////////////////////////////
// etc
////////////////////////////////
const byte  Int_End = 73;             // Initial end code
const char Call[9] = "JA2GQP";        // Display Call sign

////////////////////////////////
// Memory Assign
////////////////////////////////
unsigned long Vfo_Dat;                // VFO Data
unsigned long Ch_Dat;                 // Channel Data
int Rit_Dat;                          // RIT Data
unsigned long Enc_Step;               // STEP
char Enc_Dir = 0;                     // -1 DIR_CCW, 0 DIR_NONE, 1 DIR_CCW
byte Ch_Index = 0;                    // Channel TBL index
unsigned int Val_Smeter = 0;
unsigned int Val_Smeterb = 1;

long Time_Passd;                      // int to hold the arduino miilis since startup
long Time_Mode;                       // Mode change Time
byte Flg_eepWT = 0;                   // EEP Write Flag

byte Flg_Mode;
byte Flg_Over;
byte Flg_Vfo = 0; 
byte Flg_Tx = 0;
byte Flg_Chan = 0;                    // Channel Flag 0:VFO, 1:Cannel
byte Disp_Over = 1;
byte Disp_Freq = 1;
byte Disp_Tx = 0;
byte Disp_Rit = 0;
byte Flg_Rit = 0;                     // RIT Flag

//----------  setup  ----------------------------------------------------

void setup() {
  pinMode(SW_STEP, INPUT_PULLUP);
  pinMode(SW_TX, INPUT_PULLUP);          
  pinMode(SW_RIT, INPUT_PULLUP);          
  pinMode(12, OUTPUT);                // pin12,pin13
  pinMode(13, OUTPUT);                // 0,0=CW 1,0=LSB 0,1=USB 1,1=AM           

  attachInterrupt(0, rotary_encoder, CHANGE);
  attachInterrupt(1, rotary_encoder, CHANGE);

  si5351.init(SI5351_CRYSTAL_LOAD_8PF,0,0);    // crystal 25.000 MHz, correction 0
  si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_4MA);//Drive lebel 4mA set 
  oled.begin(&Adafruit128x32, 0x3C);

  if(EEPROM.read(Eep_Init) != Int_End){        // Eep initialaz
    delay(10);
    eep_init();
  }
  else{
    if(digitalRead(SW_STEP) == LOW){
      delay(10);
      eep_init();
      fover_disp();
      while (digitalRead(SW_STEP) == LOW);
    }
  }
  eep_rdata();
  mode_disp();
  step_disp();
}

//----------  main  ----------------------------------------------------

void loop() {
  if(Flg_Chan == 0){
    vfo_mode();
  }
  if(Flg_Chan == 1){
    ch_mode();
  }
}

//----------  Channel mode  ------------------------------------------------

void ch_mode(){

////////////////////////
// receive
////////////////////////
  if(digitalRead(SW_TX) == HIGH){           
    Flg_Tx = 0;
    si5351.output_enable(SI5351_CLK0, 1);   // VFO enable 

    if (Flg_Rit == 0){
      if(Disp_Freq == 1){
        if((Ch_Index == 0) && (Enc_Dir == -1))
          Ch_Index = Max_Chan-1;
        else if((Ch_Index == Max_Chan-1) && (Enc_Dir == 1))  
          Ch_Index = 0;
        else
          Ch_Index += Enc_Dir;

        Enc_Dir = 0;
        Ch_Dat = eep_read4(Eep_Chfreq+Ch_Index*4);  // Channel data read
        band_check(Ch_Dat);                         // range check
        si5351_set_freq(Ch_Dat + RX_IF);            // frequency out
        ch_disp(Ch_Dat);                            // Channel display
        Disp_Freq = 0;

        Flg_Vfo = 1;
        mode_disp();
        Rit_Dat = 0;

        Time_Passd = millis();
        Flg_eepWT = 1;
      }
    }      
    else{
      if (Disp_Rit == 1){
        Rit_Dat += Enc_Dir * Enc_Step;
        Enc_Dir = 0;
        Rit_Dat = constrain(Rit_Dat, -5000, 5000);
        si5351_set_freq(Ch_Dat + RX_IF + Rit_Dat);
        rit_disp(Rit_Dat);
        mode_disp();
        Disp_Rit = 0;
        Flg_Vfo = 1;
      }
    }   

////////////////////////
// STEP
////////////////////////
    if (digitalRead(SW_STEP) == LOW) {      // increment events
      Time_Mode = millis();        

      while (digitalRead(SW_STEP) == LOW){
        if(Time_Mode+1000 < millis()){
          if(Flg_Chan == 0){                  // VFO mode?
            Flg_Chan = 1;                     //  yes,Channel mode set
            break;
          }  
          else{                               //  no,VFO mode
            Flg_Chan = 0;                   
            freq_disp(Vfo_Dat);               //  frequency display
            si5351_set_freq(Vfo_Dat + RX_IF); //  fequency data output
            Flg_Rit = 0;                      //  RIT reset
            Disp_Freq = 0;
            break;
          }
        }
      }

      while (digitalRead(SW_STEP) == LOW);
      if(Flg_Chan == 1){
        enc_step();
        step_disp();
      }
    }

////////////////////////
// RIT
////////////////////////
    if (digitalRead(SW_RIT) == LOW) {
      Time_Mode = millis();
      while (digitalRead(SW_RIT) == LOW){
        if(Time_Mode+1000 < millis()){
          if(Flg_Chan == 1){
            Flg_Chan = 0;
 
            Vfo_Dat = Ch_Dat;
            freq_disp(Vfo_Dat);
            si5351_set_freq(Vfo_Dat + RX_IF);
            Flg_Rit = 0;
            break;
          }
        }
      }

      while (digitalRead(SW_RIT) == LOW);
      if(Flg_Chan == 1){
        rit_disp(Rit_Dat);
        Fnc_Rit(); 
      }
    }
    Disp_Tx = 1;
  }

////////////////////////
// send
////////////////////////
  else{                                     
    Flg_Tx = 1;
    Disp_Over = 1;

    if(Flg_Over == 0){                      // Within transmittable range?
        freq_disp(Ch_Dat);                  // frequency display
      si5351.output_enable(SI5351_CLK0, 1); // VFO enable
      if(Flg_Vfo == 1){
        si5351_set_freq(Ch_Dat + TX_IF);
        Flg_Vfo = 0;
      }
      Disp_Freq = 1;
      Disp_Rit = 1;
    }
    else{                                   // Out of range
      si5351.output_enable(SI5351_CLK0, 0); // VFO disable 
      if(Disp_Over == 1){
        fover_disp();                       // Display of over range
        Disp_Over = 0;
      }
    }
    if(Disp_Tx == 1){
      tx_disp();
      Disp_Tx = 0;        
    }
    Disp_Freq = 1;  
  }

////////////////////////
// common
////////////////////////
  Val_Smeter = analogRead(AD_SM);
  if ((abs(Val_Smeter - Val_Smeterb)) > 3){ // if needed draw S-meter
    sm_disp();
    Val_Smeterb = Val_Smeter;
  }

  if(Flg_eepWT == 1){                       // EEPROM auto Write
    if(Time_Passd+2000 < millis()){
      eep_wdata();
      Flg_eepWT = 0; 
    }
  }
}   

//----------  VFO mode  ------------------------------------------------

void vfo_mode(){

////////////////////////
// receive
////////////////////////
  if(digitalRead(SW_TX) == HIGH){           
    Flg_Tx = 0;
    si5351.output_enable(SI5351_CLK0, 1);   // VFO enable 

    if (Flg_Rit == 0){
      if(Disp_Freq == 1){
        Vfo_Dat += Enc_Dir * Enc_Step;
        Enc_Dir = 0;
        band_check(Vfo_Dat);                        // range check
        si5351_set_freq(Vfo_Dat + RX_IF);
        freq_disp(Vfo_Dat);                  // frequency display
        Disp_Freq = 0;

        Flg_Vfo = 1;
        mode_disp();
        Rit_Dat = 0;

        Time_Passd = millis();
        Flg_eepWT = 1;
      }
    }      
    else{
      if (Disp_Rit == 1){
        Rit_Dat += Enc_Dir * Enc_Step;
        Enc_Dir = 0;
        Rit_Dat = constrain(Rit_Dat, -5000, 5000);
        si5351_set_freq(Vfo_Dat + RX_IF + Rit_Dat);
        rit_disp(Rit_Dat);
        mode_disp();
        Disp_Rit = 0;
        Flg_Vfo = 1;
      }
    }   

////////////////////////
// STEP
////////////////////////
    if (digitalRead(SW_STEP) == LOW) {      // increment events
      Time_Mode = millis();

      while (digitalRead(SW_STEP) == LOW){
        if(Time_Mode+1000 < millis()){
          if(Flg_Chan == 0){
            Flg_Chan = 1;
            ch_disp(Ch_Dat);
            si5351_set_freq(Ch_Dat + RX_IF);
            eep_wdata();
            Flg_Rit = 0;
            break;
          }  
          else{
            Flg_Chan = 0;
            break;
          }
        }
      }
      
      while (digitalRead(SW_STEP) == LOW);
      if(Flg_Chan == 0){
        enc_step();
        step_disp();
      }
    }

////////////////////////
// RIT
////////////////////////
    if (digitalRead(SW_RIT) == LOW) {
      Time_Mode = millis();
      while (digitalRead(SW_RIT) == LOW){
        if(Time_Mode+1000 < millis()){
          if(Flg_Chan == 0){
            eep_write4(Vfo_Dat,Eep_Freq);
            Ch_Dat = Vfo_Dat;
            ch_disp(Ch_Dat);
            eep_write4(Ch_Dat,Eep_Chfreq+Ch_Index*4);
            si5351_set_freq(Ch_Dat + RX_IF);
            Flg_Rit = 0;
            Flg_Chan = 1;
            break;
          }
        }
      }

      while (digitalRead(SW_RIT) == LOW);
      if(Flg_Chan == 0){
        rit_disp(Rit_Dat);
        Fnc_Rit(); 
      }
    }
    Disp_Tx = 1;
  }

////////////////////////
// send
////////////////////////
  else{                                     
    Flg_Tx = 1;
    Disp_Over = 1;

    if(Flg_Over == 0){                      // Within transmittable range?
        freq_disp(Vfo_Dat);                 // frequency display
      si5351.output_enable(SI5351_CLK0, 1); // VFO enable
      if(Flg_Vfo == 1){
        si5351_set_freq(Vfo_Dat + TX_IF);
        Flg_Vfo = 0;
      }
      Disp_Freq = 1;
      Disp_Rit = 1;
    }
    else{                                   // Out of range
      si5351.output_enable(SI5351_CLK0, 0); // VFO disable 
      if(Disp_Over == 1){
        fover_disp();                       // Display of over range
        Disp_Over = 0;
      }
    }
    if(Disp_Tx == 1){
      tx_disp();
      Disp_Tx = 0;        
    }
    Disp_Freq = 1;  
  }

////////////////////////
// common
////////////////////////
  Val_Smeter = analogRead(AD_SM);
  if ((abs(Val_Smeter - Val_Smeterb)) > 3){ // if needed draw S-meter
    sm_disp();
    Val_Smeterb = Val_Smeter;
  }

  if(Flg_eepWT == 1){                       // EEPROM auto Write
    if(Time_Passd+2000 < millis()){
      eep_wdata();
      Flg_eepWT = 0; 
    }
  }
}   

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

void Fnc_Rit(){
  if(Flg_Rit == 0){
    Rit_Dat = 0;
    Flg_Rit = 1;
  }
  else{
    Flg_Rit = 0;
    Disp_Freq = 1;
  }

//----------  RIT Display  ---------------------------------------------

void rit_disp(int rit_data) {
  unsigned int ri,rit;

  oled.setFont(lcdnums14x24);
  oled.setCursor(1, 0);
  oled.print("::::");

  if (rit_data < 0)
    oled.print('-');
  else
    oled.print('+');

  rit = abs(rit_data);
   ri = rit / 1000;  
  oled.print(ri);
  oled.print('.');
  ri = (rit % 1000) / 10;
  if (ri < 10)
    oled.print('0');
  oled.print(ri);
}

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

void eep_write4(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--;
  }
}

//----------  Read EEPROM 4byte  ---------------------------------------

long eep_read4(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;
}

//----------  EEPROM Dat Read  -----------------------------------------

void eep_rdata(){
  Vfo_Dat = eep_read4(Eep_Freq);
  Enc_Step = eep_read4(Eep_Step);
  Ch_Index = EEPROM.read(Eep_Ch);
  Flg_Chan = EEPROM.read(Eep_Chan);
  Ch_Dat = eep_read4(Eep_Chfreq+Ch_Index*4);
}

//----------  EEPROM Dat Write  ----------------------------------------

void eep_wdata(){
  eep_write4(Vfo_Dat,Eep_Freq);
  eep_write4(Enc_Step,Eep_Step);
  EEPROM.write(Eep_Ch,Ch_Index);            // Ch_Index set  
  EEPROM.write(Eep_Chan,Flg_Chan);          // VFO-Channel 0:VFO 1:Channel  
  eep_write4(Ch_Dat,Eep_Chfreq+Ch_Index*4);
}  
    
//----------  EEPROM Initialization ------------------------------------

void eep_init(){
  int i;

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

  eep_write4(FRQ_TBL[DEF_F],Eep_Freq);
  eep_write4(STEP_1k,Eep_Step);            // Step(1kHz)
  EEPROM.write(Eep_Ch,Ch_Index);           // Ch_Index set  
  EEPROM.write(Eep_Chan,Flg_Chan);         // Ch_Index set  

  for(i=0;i<Max_Chan;i++)
    eep_write4(CH_TBL[i],Eep_Chfreq+i*4);  

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

//----------  Rotaly Encorder  -----------------------------------------

void rotary_encoder() {                     // rotary encoder events
  uint8_t result = r.process();

  if(Flg_Tx == 0){
    if (result) {
      Disp_Freq = 1;
      Disp_Rit = 1;
      if (result == DIR_CW)
        Enc_Dir = 1;
      else
        Enc_Dir = -1;
    }
  }
}

//----------  si5351 PLL Output  ---------------------------------------

void si5351_set_freq(uint32_t frequency) {
  si5351.set_freq(frequency * SI5351_FREQ_MULT, SI5351_CLK0);
}

//----------  Encorede STEP  -------------------------------------------

void enc_step() {
  if (Enc_Step == STEP_50) {
    Enc_Step = STEP_1k;                     // 1000 Hz, round to XX.XXX.000
    float tmp = round (Vfo_Dat / (STEP_1k * 1.000));
    Vfo_Dat = (uint32_t)(tmp * STEP_1k);
    Disp_Freq = 1;
  }
  else if(Enc_Step == STEP_1k)
    Enc_Step = STEP_10k;                    // 10k
  else    
    Enc_Step = STEP_50;                     // 50 Hz
}

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

void step_disp() {
  oled.setCursor(109, 3);
  oled.setFont(labels);
  if (Enc_Step == STEP_50)
    oled.print("6");                        // 50Hz
  else if(Enc_Step == STEP_1k)
    oled.print("8");                        // 1k
  else
    oled.print("9");                        // 10k
}

//---------- Frequency renge over --------------------------------------

void fover_disp() {
  oled.setFont(lcdnums14x24);
  oled.setCursor(1, 0);
  oled.print("--.---.--");
}

//---------- callsign display ------------------------------------------

void call_disp() {
  oled.setFont(Arial_bold_14);
  oled.setCursor(56, 6);
  oled.print(Call);
}

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

void freq_disp(uint32_t sf_rx) {
  uint16_t fr;

  oled.setFont(lcdnums14x24);
  oled.setCursor(1, 0);
  fr = sf_rx / 1000000;
  if (fr < 10)
    oled.print(':');                        // ':' is changed to ' ' in lcdnums14x24.h
  oled.print(fr);
  oled.print('.');
  fr = (sf_rx % 1000000) / 1000;
  if (fr < 100)
    oled.print('0');
  if (fr < 10)
    oled.print('0');
  oled.print(fr);
  oled.print('.');
  fr = (sf_rx % 1000) / 10;
  if (fr < 10)
    oled.print('0');
  oled.print(fr);
}

//----------  Channel Display  -----------------------------------------

void ch_disp(uint32_t sf_rx) {
  uint16_t fr;

  oled.setFont(lcdnums14x24);
  oled.setCursor(1, 0);
  oled.print(Ch_Index);

  oled.print("::");                        // ':' is changed to ' ' in lcdnums14x24.h

  fr = sf_rx / 1000000;
  if (fr < 10)                            
    oled.print(':');                      // ':' is changed to ' ' in lcdnums14x24.h
  oled.print(fr);

  oled.print('.');
  fr = (sf_rx % 1000000) / 1000;
  if (fr < 100)
    oled.print('0');
  if (fr < 10)
    oled.print('0');
  oled.print(fr);

}

//---------- TX display ------------------------------------------------

void tx_disp() {
  oled.setCursor(2, 3);
  oled.setFont(labels);
  oled.print("1");                          // "1" is "TX" in labels.h
}

//---------- Mode display ----------------------------------------------

void mode_disp() {
  oled.setCursor(2, 3);
  oled.setFont(labels);
  if (Flg_Mode == 0){
    oled.print("2");                        // "2" is "CW" in labels.h
//    oled.print("/");                        // "/" is "AM" in labels.h
    digitalWrite(12,LOW);
    digitalWrite(13,LOW);
  }
  else if(Flg_Mode == 1){
    oled.print("3");                        // "3" is "LSB"
    digitalWrite(12,HIGH);
    digitalWrite(13,LOW);
  }
  else if(Flg_Mode == 2){
    oled.print("4");                        // "4" is "USB"
    digitalWrite(12,LOW);
    digitalWrite(13,HIGH);
  }
  else if(Flg_Mode == 3){
    oled.print("/");                        // "4" is "USB"
    digitalWrite(12,HIGH);
    digitalWrite(13,HIGH);
  }
}

//----------  S-Meter Display  -----------------------------------------

void sm_disp() {
  uint8_t a = 0;
  uint8_t m = 0;

  a = (Val_Smeter + 3) / 113;  // 1024 / 9 characters for S = 1,3,5,7,8,9,+10,+20,+30
  oled.setFont(pixels);
  oled.setCursor(25, 3);
  for (m = 0; m < a; m++)
    if (m < 6)
      oled.print('7');                      // '5' - hollow rectangle, 6px
    else
      oled.print('8');                      // '6' - filled rectangle, 6px
  for (m = a; m < 9; m++)
    oled.print('.');                        // '.' 1px
}

//----------  band chek  -----------------------------------------------

void band_check(unsigned long freq){
  if((freq >= FRQ_TBL[CW_F])
      && (freq < FRQ_TBL[SSB_F])){
    Flg_Mode = 0;                             // CW(0=CW, 1=LSB, 2=USB, 3=AM)    
    Flg_Over = 0;
  }
  else if((freq >= FRQ_TBL[SSB_F])
      && (freq < FRQ_TBL[AM_F])){
    if(freq >= 10000000)                      // greate than 10MHz                        
      Flg_Mode = 2;                           // USB(0=CW, 1=LSB, 2=USB, 3=AM)
    else
      Flg_Mode = 1;                           // LSB(0=CW, 1=LSB, 2=USB, 3=AM)
    Flg_Over = 0;
  }
  else if((freq >= FRQ_TBL[AM_F])
      && (freq < FRQ_TBL[HI_F])){
    Flg_Mode = 3;                             // AM(0=CW, 1=LSB, 2=USB, 3=AM)
    Flg_Over = 0;
  }
  else
    Flg_Over = 1;
}   






        

      

    


2021年7月14日水曜日

NE602 AM Module PCB Version

このNE602 AM Moduleは、si5351などのローカル発振器と組み合わせて、AMを発生させるモジュールである。先に公開したNE602 AM ModuleのPCB化したものである。PCB化に伴って、定数の見直を一部した。何時もながら、PCBサイズ50x50に収めた。リード部品を使っているので、組み立ても容易であろう。



回路図










    



レギュレータに78L08を使って、TA2011とNE602に供給している。MSA0886は13.8Vに接続している。当初、8V単一電源を考えたが、MSA0886を含めると100mAを超える為、2電圧とした。

部品面実装シルク

PCBにシルクが入れてあるが、4面とした時に何らかのミスを犯したようだ。部品番号が1面のみ入っているが、3面は部品番号が入ってない。確認の意味でシルク図を書いておく。


ガーバーデータ      

今回のPCBガーバーデータの4面付け PCBサイズ 99.06x99.06 公開。部品番号のシルクが1面しかない不具合を改修したものを公開。4面付けのガーバーデータは、JA2GQP's Download siteのNE602フォルダからダウンロード可能。

調整

VR1、VR2でマイクゲインの調整。VR3でキャリアレベルを調整。

キャリアレベルは、パワー計を接続して音声入力無しの時にVR3を回して最大出力の1/4に調整する。

動作確認

受信機でハウリング音を聴いた時、音に濁りが無く、歪みが無いことを確認する。澄んだ音になるまで、VR1,VR3を調整する。調整後、7mW~10mWほどのAM出力が得られる。





       

2021年6月30日水曜日

NE602 AM Modulation

NE602を使った、AM変調の確認を50MHz帯で行った。AF AMPにTA2011、LOにsi5351、RF AMPにMSA0886とした。
ユニバーサル基板で組んだので、動作確認のために余分な部品が付いている。
当初、LOに水晶発振子50.62MhzをVXOして、50.60MHzで使う予定だった。VXOする事で、周波数は合っているものの、ニアバイが有り、期待した音質が得られなかった。しかし、水晶発振子周辺の定数の見直しをすれば問題ない筈だ。
今回の目的は、LOの確認ではないので、VXO定数選定に時間を割くことなく、PLL si5351を使う事にした。

回路図

レギュレータ7808は、負荷電流20~30mAのため、100mAシリーズで問題ない。キャリアレベルは、NE602 pin1に繋がっているVRで最大キャリア(音声無入力で最大出力)の1/4位にセットすれば良い。出力は、50MHzで約7mWのAMを得ることができる。バッファAMPなしで、RQA0009をドライブできるであろう。


スケッチ

動作確認のためのスケッチです。周波数は50.60Mhz、出力は4mA設定し4mW出力にしてます。この設定で、問題なくAM変調されている事は確認しましたが、最適値であるかは不問。

//////////////////////////////////////////////////////////////////////

//  si5351a NE602 AM test program ver.1.0

//    Copyright(C)2021.JA2GQP.All rights reserved.

//

//                                                2021/6/30

//                                                  JA2GQP

//////////////////////////////////////////////////////////////////////


#include "si5351.h"

#include "Wire.h"


Si5351 si5351;


//----------  setup  ----------------------------------------------------


void setup(){

  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);

                                        // SI5351_DRIVE_2MA : 1mW 

                                        // SI5351_DRIVE_4MA : 4mW  

                                        // SI5351_DRIVE_6MA : 9mW  

                                        // SI5351_DRIVE_8MA : 15mW  

  si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_4MA); 


                                        // frequency 50.60Mhz set

  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);

  si5351.set_freq(5060000000ULL, SI5351_PLL_FIXED, SI5351_CLK0);

}


//----------  main  ----------------------------------------------------


void loop(){

}