2026年2月4日水曜日

ADF4351 VFO

PLL ADF4351(35MHz-4.4GHz PLL)を使ってVFOを作った。このADF4351の用途は、SFH帯のLOとして固定周波数で使う事が多いと思われる。以前は1200MHz帯の自作でも、LOが出来れば半分以上完成したと言われていた。今回の製作は、10kHzステップのVFOとした。ADF4351ボードは数種類有るようだ。クロック25MHz搭載タイプを入手した。しかしオシレータの精度が悪いため、秋月電子製12.8MHz VCTCXOと交換。VFOの機能は、レピータシフト(最大±90MHz)、最小10kHzステップ。





PCBの様子

左側がADF4351をプラグイン仕様に改造し、メインボードに実装している。マイコンはPro mini 3.3V。oledの上側に有るのがレベル変換ボード。






回路図


 










スケッチ

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

//       Copyright©2018.JA2GQP.All rights reserved.
//            ADF4351 Pll Local oscillator        
//                                                    2026/2/4
//                                                    JA2GQP    
//
//----------------------------------------------------------------------------    
//  The original is here.
//      https://github.com/Giorgiofox/ADF4351-Arduino-LCDSHIELD
//
//////////////////////////////////////////////////////////////////////////////

#include "src/Rotary.h"             // http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
#include <SPI.h>
#include <Tiny4kOLED.h>
#include "font/Tlcdnums14x24.h"
#include "font/Tfont5x7.h"
#include <EEPROM.h>

//------------------------ Define value ---------------------------------------

#define ENC_A         2                 // encorder A
#define ENC_B         3                 //          B
#define LE            5                 //         LE
#define SW_STEP       6                 // STEP SW
#define SW_REPT       7                 // REPT SW
#define SW_TX         8                 // TX SW
#define Xtal_Freq     12.8              // ADF4351 clock 12.8MHz
#define Scal_10kHz    0.01              //         STEP 10kHz

#define DEF_Freq      115000            // default frequency 1150.00MHz
#define DEF_Step      100               //         step 1MHz
#define DEF_Rsft      -2000             //         repeater shift -20.00MHz

///---------- Set Device -----------------------------

Rotary r = Rotary(ENC_A, ENC_B);              

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

#define Eep_Init    0x00                // Eep Init(1byte)
#define Eep_Resw    0x02                // REPT sw(1byte)
#define Eep_Step    0x04                // STEP(4byte)
#define Eep_Rsft    0x08                // REPT shift(4byte)
#define Eep_Freq    0x0c                // Frequency(4byte)

//---- frequency limit offset
#define LOW_REPT   -9000
#define HI_REPT    9000

//------------------------ Register definition --------------------------------

/////////////////////////////////////////
// ADF4351 Register initialize value
/////////////////////////////////////////
unsigned long registers[6] = {          // 437.00MHz @12.8MHz
        0x888008,                       // Register 0( 0x4580A8   @25MHz)
        0x8008041,                      //          1(0x80080C9         )
        0x4E42,                         //          2(   0x4E42         )          
        0x4B3,                          //          3(    0x4B3         )
        0xB6703C,                       //          4( 0xBC803C         )
        0x580005} ;                     //          5( 0x580005         )    

/////////////////////////////////////////
// Register declaration
/////////////////////////////////////////
double  RFout,
        REFin,
        PFDRFout = Xtal_Freq,               // X'tal frequency set
        OutputChannelSpacing = Scal_10kHz,  // Scaling(10kHz)
        FRACF;
long    RFint,
        RFintold = 0,
        INTA,
        MOD,
        FRAC;
byte OutputDivider;

/////////////////////////////////////////
// etc
/////////////////////////////////////////
const byte Int_End = 73;                // Initial end code
byte Flg_eepWT = 0;                     // EEP Write Flag
byte Flg_Tx = 0;
byte Flg_Resw;
byte Flg_Re=0;
int Rsft = DEF_Rsft;
unsigned long Time_Passd;               // int to hold the arduino miilis since startup
long Time_Mode;                         // Mode change Time
int32_t Enc_Step;                       // STEP
int8_t Enc_Dir = 0;

//------------------------ Setup ----------------------------------------------

void setup(){
  pinMode(SW_STEP, INPUT_PULLUP);
  pinMode(SW_REPT, INPUT_PULLUP);
  pinMode(SW_TX, INPUT_PULLUP);          
  pinMode(LE, OUTPUT);                  // Setup pins

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

  oled.begin();
  oled.clear();
  oled.on();
 
  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);
    }
  }

  digitalWrite(LE, HIGH);
  SPI.begin();                          // Init SPI bus
  SPI.setDataMode(SPI_MODE0);           // CPHA = 0 et Clock positive
  SPI.setBitOrder(MSBFIRST);            // highs in the lead

  eep_rdata();
  freq_disp(RFint);                     // frequency display
  step_disp();
}

//------------------------ Main -----------------------------------------------

void loop(){
/////////////////////////////////////////
// TX SW check
/////////////////////////////////////////
  if(digitalRead(SW_TX) == LOW)        
    Flg_Tx = 1;                         // <<< Tx >>>
  else
    Flg_Tx = 0;                         // <<< Rx >>>

/////////////////////////////////////////
// Repeater PROC
/////////////////////////////////////////
  if(Flg_Resw == 0){                    // repeater off?
    freq_disp(RFint);
    rpt_disp(Rsft);
    Pll_ADF4351(RFint);  
  }
  if(Flg_Resw == 1){                    // repeater on?
    freq_disp(RFint);
    rpt_disp(Rsft);
    if(Flg_Tx == 1)                     // <<< Tx >>>
      Pll_ADF4351(RFint + Rsft);        // frequency shift
    else                                // <<< Rx >>>
      Pll_ADF4351(RFint);               // normal frequency  
  }
  else if(Flg_Resw == 2){
    shift_disp(Rsft);
    rpt_disp(Rsft);
  }

/////////////////////////////////////////
// Step PROC
/////////////////////////////////////////
  if (digitalRead(SW_STEP) == LOW) {    // increment events
    enc_step();
    step_disp();
    delay(300);
    while (digitalRead(SW_STEP) == LOW);
  }

/////////////////////////////////////////
// Repeater SW check
/////////////////////////////////////////
  if(digitalRead(SW_REPT) == LOW){
    Time_Mode = millis();
 
    while (digitalRead(SW_REPT) == LOW){
      while (digitalRead(SW_REPT) == LOW);
      if(Time_Mode+1000 < millis()){
        Flg_Resw = 2;
        break;
      }      
      if(Flg_Resw == 0){
        Flg_Resw = 1;
        EEPROM.write(Eep_Resw,Flg_Resw);                  
        break;
      }
      else {
        Flg_Resw = 0;
        EEPROM.write(Eep_Resw,Flg_Resw);                
        break;
      }
    }
   
  }

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

//----------  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(){
  RFint = eep_read4(Eep_Freq);
  Enc_Step = eep_read4(Eep_Step);
  Rsft = eep_read4(Eep_Rsft);
  Flg_Resw = EEPROM.read(Eep_Resw);
}

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

void eep_wdata(){
  eep_write4(RFint,Eep_Freq);
  eep_write4(Enc_Step,Eep_Step);
  eep_write4(Rsft,Eep_Rsft);
}  
   
//----------  EEPROM Initialization ------------------------------------

void eep_init(){
  int i;

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

  EEPROM.write(Eep_Resw,Flg_Resw);      // Repeater off
  eep_write4(DEF_Freq,Eep_Freq);        // Frequency 1150MHz
  eep_write4(DEF_Step,Eep_Step);        // Step 1MHz
  eep_write4(DEF_Rsft,Eep_Rsft);        // Repeater shift -20MHz

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

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

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

  if(Flg_Tx == 0){
    if (result) {
      if (result == DIR_CW){
        wk2 = Rsft + Enc_Step;
        wk4 = RFint + Enc_Step;
      }  
      else{
        wk2 = Rsft - Enc_Step;
        wk4 = RFint - Enc_Step;
      }

      wk2 = constrain(wk2,LOW_REPT,HI_REPT);

      if(Flg_Resw == 2)
        Rsft = wk2;
      else
        RFint = wk4;
     
      Flg_eepWT = 1;
      Time_Passd = millis();
    }
  }
}

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

void enc_step() {
  if(Enc_Step == 1)
    Enc_Step = 10;
  else if(Enc_Step == 10)
    Enc_Step = 100;
  else if(Enc_Step == 100)
    Enc_Step = 1000;
  else if(Enc_Step == 1000)
    Enc_Step = 1;
  else
    Enc_Step = 100;
}

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

void step_disp() {
  oled.setCursor(64, 3);
  oled.print("    ");                  
  oled.setCursor(64, 3);
  oled.setFont(&Tfont5x7);
  if (Enc_Step == 1)
    oled.print(" 10k");                 // 10k
  else if(Enc_Step == 10)
    oled.print("100k");                 // 100k
  else if(Enc_Step == 100)
    oled.print("  1M");                 // 1M
  else
    oled.print(" 10M");                 // 10M
}

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

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

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

void rpt_disp(int32_t rep_shift) {
  oled.setFont(FONT8X16);
  if(Flg_Resw == 1){
    oled.setFont(FONT8X16);
    oled.setCursor(102, 0);
    oled.print("REP");
    oled.setCursor(102, 2);
    if(rep_shift >= 0)
      oled.print('+');
      oled.print(rep_shift / 100);
      oled.print(' ');
  }
  else {
    oled.setCursor(102, 0);
    oled.print("   ");
    oled.setCursor(102, 2);
    oled.print("   ");
  }
}

//----------  Shift Display  ---------------------------------------

void shift_disp(int32_t sf_rx) {
  int32_t fr;

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

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

void freq_disp(int32_t sf_rx) {
  int32_t fr;

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

//------------------------ SPI 32BIT Register Write proc. ---------------------

void WriteRegister32(const uint32_t value){
  digitalWrite(LE, LOW);
  for (int i = 3; i >= 0; i-- )              
    SPI.transfer((value >> 8 * i) & 0xFF);
  digitalWrite(LE, HIGH);
  digitalWrite(LE, LOW);
}

//------------------------ ADF4351 Register set -------------------------------

void Set_Reg()                                
{
  for (int i = 5; i >= 0; i-- )         // Reg5 --> Reg0 Write
  WriteRegister32(registers[i]);
}

//------------------------ Pll ADF4351 proc. ----------------------------------

void Pll_ADF4351(int32_t frq){
  RFout=frq;
  RFout=RFout/100;

  if (frq != RFintold){
    if (RFout >= 2200){
      OutputDivider = 1;
      bitWrite (registers[4], 22, 0);
      bitWrite (registers[4], 21, 0);
      bitWrite (registers[4], 20, 0);
    }
    if (RFout < 2200){
      OutputDivider = 2;
      bitWrite (registers[4], 22, 0);
      bitWrite (registers[4], 21, 0);
      bitWrite (registers[4], 20, 1);
    }
    if (RFout < 1100){
      OutputDivider = 4;
      bitWrite (registers[4], 22, 0);
      bitWrite (registers[4], 21, 1);
      bitWrite (registers[4], 20, 0);
    }
    if (RFout < 550){
      OutputDivider = 8;
      bitWrite (registers[4], 22, 0);
      bitWrite (registers[4], 21, 1);
      bitWrite (registers[4], 20, 1);
    }
    if (RFout < 275){
      OutputDivider = 16;
      bitWrite (registers[4], 22, 1);
      bitWrite (registers[4], 21, 0);
      bitWrite (registers[4], 20, 0);
    }
    if (RFout < 137.5){
      OutputDivider = 32;
      bitWrite (registers[4], 22, 1);
      bitWrite (registers[4], 21, 0);
      bitWrite (registers[4], 20, 1);
    }
    if (RFout < 68.75){
      OutputDivider = 64;
      bitWrite (registers[4], 22, 1);
      bitWrite (registers[4], 21, 1);
      bitWrite (registers[4], 20, 0);
    }

    INTA = (RFout * OutputDivider) / PFDRFout;
    MOD = (PFDRFout / OutputChannelSpacing);
    FRACF = (((RFout * OutputDivider) / PFDRFout) - INTA) * MOD;
    FRAC =round(FRACF); // On arrondit le résultat

    registers[0] = 0;                   // Register 0
    registers[0] = INTA << 15;// OK
    FRAC = FRAC << 3;
    registers[0] = registers[0] + FRAC;

    registers[1] = 0;                   // Register 1
    registers[1] = MOD << 3;
    registers[1] = registers[1] + 1 ;   // adding the address "001"
    bitSet (registers[1], 27);          // Prescaler on 8/9

    bitSet (registers[2], 28);          // Register 2(Pll lock setup)
    bitSet (registers[2], 27);
    bitClear (registers[2], 26);

    Set_Reg();                          // ADF4351 Register write
    RFintold = frq;
  }
}

ダウンロード

回路図、スケッチなどJA2GQP's Download siteのadf4351フォルダからダウンロード出来る。

     

2025年11月16日日曜日

UV-K58無改造50MHz AMP

UV-K58をH/W改造なし(F/W改造とアドオンボード)で、50MHz AMPを作った。UV-K58をF/W改造後、スペクトラムを見るとがっかりする。UV-K58本体改造で27MHzにした例はある。ただ本体改造はリスク(LCD破損など)が伴う。そこで付加装置として対応すと事とし、出力500mW以上を目標とした。



改造前本体のスペクトラム


UV-K58 LOW設定
送信した時、最大出力が100MHzに現れる。フィルタを入れるか同調回路の入ったバッファ回路が必要と思われる。UV-K58の出力設定をLOWにした時が50MHzで最大となったのでLOW設定で使う事にする。50MHzで9.2dBm





UV-K58 MID設定
50MHzで5.2dBm













UV-K58 HIGH設定  
50MHzde3.2dBm
  

    

2SK241AMP出力スペクトラム 

同調回路方式のAMPによって、50MHzの出力が最大になった。
  


回路
デバイスは、入手が容易で安価なBS170を使った。本体未改造のため、キャリコン方式のスタンバイ回路にした。







結果

UV-K58に接続し、スペクトラムを測定した。出力約500mWあり、概ね目標クリアーできた。生産終了のRQA0009を使うと約5W出力。







Download

JA2GQP's Download siteのUV-K58_AMPフォルダーから必要なファイルがダウンロード出来ます。

2025年9月8日月曜日

CA3028モドキを使った50MHzAM TX

CA3028モドキと本体回路のトランジスタをPN2222を使った50MHzAM TX。広帯域増幅を採用したので、n次高調波がある。この回路定数で50MHzに於いて変調時400mW出力がある。また、27MHzでは約1W出力となった。評価用に作ったので、実使用ではフィルタが必要である。


スペクトラム  

AM無変調時のスペクトラムである。同調回路が入ってないのでn次高調波多い。LPFを入れれば簡単に高調波を取り除けると思う。






回路図

2025年3月28日金曜日

CW ABC

CWから遠ざかっているので、忘れた感覚を取り戻す為にCW練習機を作った。練習モードは、ABC連続、ABC数字連続、ABC数字ランダムおよびカナ連続、カナランダムから選択できる。LCD0802を使って、5文字表示と打鍵速度表示を行った。マイコンはATiny1614を使って、BCDスイッチ(モード切り替えSW)とRepeat SWは割込み処理にした。









回路図












スケッチ

fabcとfkanaは、ANKコード表による。但しコード表にない文字 ヰは#と表示、ヱはェ
(小さいエ)と表示することにした。ANKコードは下表。
























モード設定はBCD SW行い、速度はボリュームで設定する。
REP_SW操作でリピート開始/リピート中止ができる。

////////////////////////////////////////////////  
//  CW Trainer Ver.1.0
//                                2025/3/31
//                                JA2GQP
////////////////////////////////////////////////

#include <LiquidCrystal.h>

/////////////////////////////
//  Micro define
/////////////////////////////  
#define SP_DO   4                   // SP
#define SPEED   8                   // SPEED
#define freq    700                 // tone freq(Hz)
#define msw_1   7                   // mode SW BIT0  
#define msw_2   6                   //            1
#define msw_4   5                   //            2
#define REP_SW  11

const int rs = 10 , en = 9, d4 = 3, d5 = 2, d6 = 1, d7 = 0;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

/////////////////////////////
//  Morse Code & font table
/////////////////////////////
byte acode[36] =
{0x06,0x11,0x15,0x09,0x02,0x14,0x0b,0x10,0x04,0x1e,  // A B C D E F G H I J
  0x0d,0x12,0x07,0x05,0x0f,0x16,0x1b,0x0a,0x08,0x03,  // K L M N O P Q R S T
  0x0c,0x18,0x0e,0x19,0x1d,0x13,0x3f,0x3e,0x3c,0x38,  // U V W X Y Z 0 1 2 3
  0x30,0x20,0x21,0x23,0x27,0x2f};                     // 4 5 6 7 8 9

byte fabc[36]  =
{0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,  // A B C D E F G H I J
  0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,  // K L M N O P Q R S T
  0x55,0x56,0x57,0x58,0x59,0x5a,0x30,0x31,0x32,0x33,  // U V W X Y Z 0 1 2 3
  0x34,0x35,0x36,0x37,0x38,0x39};                     // 4 5 6 7 8 9

byte kcode[50] =
{0x3b,0x06,0x0c,0x3d,0x22,0x12,0x25,0x18,0x1d,0x1f,  // ア イ ウ エ オ カ キ ク ケ コ  
  0x35,0x2b,0x37,0x2e,0x17,0x05,0x14,0x16,0x3a,0x24,  // サ シ ス セ ソ タ チ ツ テ ト
  0x0a,0x15,0x10,0x1b,0x1c,0x11,0x33,0x13,0x02,0x09,  // ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ
  0x19,0x34,0x03,0x31,0x29,0x0e,0x39,0x07,0x08,0x0b,  // マ ミ ム メ モ ヤ ユ ヨ ラ リ
  0x2d,0x0f,0x1a,0x0d,0x2a,0x04,0x2c,0x29,0x26,0x1e}; // ル レ ロ ワ ン " ゜㋼ エ ヲ

byte fkana[50] =
{0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,  // ア イ ウ エ オ カ キ ク ケ コ
  0xbb,0xbc,0xbd,0xbe,0xbf,0xc0,0xc1,0xc2,0xc3,0xc4,  // サ シ ス セ ソ タ チ ツ テ ト
  0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,  // ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ
  0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,  // マ ミ ム メ モ ヤ ユ ヨ ラ リ
  0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,0x23,0xaa,0xa6}; // ル レ ロ ワ ン " ゜㋼ エ ヲ

/////////////////////////////
// memory define
/////////////////////////////
int dottime;
int dashtime;
int interval1;
int interval2;
byte mode_val = 0;
byte mode_i = 0;                    // mode IRQ flag
byte rep_i = 0;                     // repeat IRQ flag

//-------- set up --------------------------------------------------//

void setup(){
  pinMode(msw_1, INPUT_PULLUP);
  pinMode(msw_2, INPUT_PULLUP);
  pinMode(msw_4, INPUT_PULLUP);
  pinMode(REP_SW, INPUT_PULLUP);

  attachInterrupt(msw_1,mode_irq,CHANGE);
  attachInterrupt(REP_SW,rep_irq,FALLING);

  randomSeed(100);
  lcd.begin(8, 2);
  lcd.print("CW ABC");
  lcd.setCursor(0, 1);
  lcd.print("ver1.0");
  delay (1000);
  lcd.clear();
  mode_SW();
};

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

void loop(){
  mode_SW();
  lcd.clear();
  lcd.setCursor(0 ,0);

  switch(mode_val){
    case 0:                           // ABC to number sequence
      lcd.print("Seq A09");
      delay(1000);
      HR_BT();
      WPM();
      lcd.setCursor(0, 1);
      seqChar(36);
      break;

    case 1:                           // random ABC
      lcd.print("Ran ABC");
      delay(1000);
      HR_BT();
      WPM();
      lcd.setCursor(0, 1);
      rndChar(26);
      break;

    case 2:                           // ABC to number ramdom
      lcd.print("Ran A09");
      delay(1000);
      HR_BT();
      WPM();
      lcd.setCursor(0, 1);
      rndChar(36);
      break;

    case 3:                           // kana sequence
      lcd.print("Seq kana");
      delay(1000);
      HR_HORE();
      WPM();
      lcd.setCursor(0, 1);
      seqChark(50);
      break;

    case 4:                           // kana ramdom
      lcd.print("Ran kana");
      delay(1000);
      HR_HORE();
      WPM();
      lcd.setCursor(0, 1);
      rndChark(50);
      break;

    case 5:
    case 6:
    case 7:
      break;
    default:
      break;
  }
}

//--------  ABC 0-9 sequence output --------------------------------//

void seqChar(int n){
int cnt=0;                            // counter clear

  while (cnt <n){
    morseTone(acode[cnt]);            // morsecode out
    delay(interval1);                 // wait
    lcd.write(fabc[cnt]);             // A to Z LCD out

    if (( (cnt+1) % 5) ==0){          // 5 dijit check
      delay(300);
      lcd.clear();
      WPM();
      lcd.setCursor(0, 1);

      if(rep_i == 1)
        cnt = cnt - 5;
    }

    cnt++;
    if(mode_i == 1){                  // IRQ check
      rep_i = 0;
      break;                          // exit loop
    }
  }
  AR();
  lcd.clear();
}

//-------- random ABC output ---------------------------------------//

void rndChar(int n){
int cnt=0;                              // counter clear
int i;
byte m[60];

  for(i=0;i<60;i++){
    m[i] = random(n);
  }

  while (cnt <60){
    morseTone(acode[m[cnt]]);           // morsecode out
    delay(interval1);                   // wait
    lcd.write(fabc[m[cnt]]);            // A to Z LCD out

    if (( (cnt+1) % 5) ==0){            // 5 dijit check
      delay(300);
      lcd.clear() ;
      WPM();
      lcd.setCursor(0, 1);

      if(rep_i == 1)
        cnt = cnt - 5;
    }

    cnt++;
    if(mode_i == 1){                    // IRQ check
      rep_i = 0;
      break;                            // exit loop
    }
  }
  AR();
  lcd.clear();
}

//--------  kana sequence output -----------------------------------//

void seqChark(int n){
int cnt=0;                              // counter clear

  while (cnt <n){
    morseTone(kcode[cnt]);              // morsecode out
    delay(interval1);                   // wait
    lcd.write(fkana[cnt]);              // kana LCD out

    if (( (cnt+1) % 5) ==0){            // 5 dijit check
      delay(300);
      lcd.clear() ;
      WPM();
      lcd.setCursor(0, 1);

      if(rep_i == 1)
        cnt = cnt - 5;
    }
    cnt++;
    if(mode_i == 1){                    // IRQ check
      rep_i = 0;
      break;                            // exit loop
    }
  }
  SN();
  lcd.clear();
}

//-------- kana random output --------//

void rndChark(int n){
int cnt=0;                              // counter clear
int i;
byte m[60];

  for(i=0;i<60;i++){
    m[i] = random(n);
  }

  while (cnt <60){
    morseTone(kcode[m[cnt]]);           // morsecode out
    delay(interval1);                   // wait
    lcd.write(fkana[m[cnt]]);           // kana LCD out

    if (( (cnt+1) % 5) ==0){            // 5 dijit check
      delay(300);
      lcd.clear() ;
      WPM();
      lcd.setCursor(0, 1);

      if(rep_i == 1)
        cnt = cnt - 5;
    }

    cnt++;
    if(mode_i == 1){                    // IRQ check
      rep_i = 0;
      break;                            // exit loop
    }
  }
  SN();
  lcd.clear();
}

//-------- mode SW -------------------------------------------------//

void mode_SW(){
  mode_val = 0;
  if(digitalRead(msw_1) == LOW)
    mode_val = mode_val + 1;
  if(digitalRead(msw_2) == LOW)
    mode_val = mode_val + 2;
  if(digitalRead(msw_4) == LOW)
    mode_val = mode_val + 4;
  mode_i = 0;
}

//-------- mode IRQ ------------------------------------------------//

void mode_irq(){
  mode_i = 1;
}

//-------- ESC IRQ ------------------------------------------------//

void rep_irq(){
  delay(50);
  rep_i = rep_i ^ 1;
}

//-------- HR HR BT code output ------------------------------------//

void HR_BT(){
  lcd.clear();
  WPM();
  lcd.setCursor(0 ,1);

  HR();
  HR();
  lcd.print("BT");
  morseTone(0x11);                    // B code output
  morseTone(0x03);                    // T code output
  delay(interval2 *2);
  lcd.clear();
}

//-------- HR code output ------------------------------------------//

void HR(){
  lcd.print("HR ");
  morseTone(0x10);                    // H code output
  delay(interval1);
  morseTone(0x0a);                    // R code output
  delay(interval1);
}

//-------- AR code output ------------------------------------------//

void AR(){
  morseTone(0x2a);
  delay(interval1);
}

//-------- ラタ code output ------------------------------------------//

void SN(){
  morseTone(0x28);
  delay(interval1);
}

//-------- code speed ----------------------------------------------//

void code_speed(){
  dottime = analogRead(SPEED) / 5;
  dashtime = dottime * 3;
  interval1 = dottime * 2;
  interval2 = dottime * 4;
}

//-------- code tone output ----------------------------------------//

void morseTone(int m){
  while (m != 1){
    if ((m & 1) == 0){
      tone(SP_DO,freq,dottime);         // dot
      delay(interval1);
    }
    else{
      tone(SP_DO,freq,dashtime);        // dash
      delay(interval2);
    }
    m = m >> 1;                         // 1bit shift right
  }
}

//-------- WPM -----------------------------------------------------//

void WPM(){
  code_speed();
  lcd.setCursor(0, 0);
  lcd.print("WPM");
  lcd.print(2400 / interval1);
  lcd.setCursor(7, 0);
  lcd.print(mode_val);
}

//-------- HR HR ホレ code output ------------------------------------//

void HR_HORE(){
  lcd.clear();
  WPM();
  lcd.setCursor(0 ,1);

  HR();
  HR();
  morseTone(0x09);                      // ホ code output
  morseTone(0x0f);                      // レ code output
  lcd.write(0xce);
  lcd.write(0xda);
  delay(interval2 *2);
  lcd.clear();
}


ダウンロード
スケッチ、回路図はJA2GQP's Download siteCWフォルダーからダウンロードできる。