2017年12月5日火曜日

Knobless Wonder

Knobless Wonderは、VK3YEが開発 した単一周波数のSSBトランシーバである。このトランシーバは、ツマミが無く極めてシンプルな構造をしている。今回、7.15909MHzの水晶発振子を使い、7.160MHz版を作った。出力2W程のQRPであるが、数局とQSOした。電波品位に関しマイナス評価は、今の所ない。
ファイルは、Download siteのKnobless Wonderフォルダからダウンロード可能。






Knobless Wonderで最も重要となるのは、クリスタルフィルタである。水晶発振子は、中華の49US(小型の背が低いタイプ)を入手し、FRMSで特性を測った。最適値では無いが、LSBでのキャリアポイントは、7.1607MHzである。日本国内の7MHz帯運用状況から、1kHZステップでの運用が暗黙の了解なので、1kHZに丸める事が望ましい。従って、このフィルタは使えない。(キャリアポイント有りき、フィルタ帯域である。)



キャリアポイントを7.160MHz±100Hzを目標値とした時、市販部品で作れるフィルタである。一般的に、この様なSSBには不向きと思われる狭帯域となる定数は選ばないであろう。だが求めている物は、HiFi音質でなく、通信に必要な実用レベルの音質なので、これで良い。







オリジナルを改造した回路図である。オリジナル回路のコレクタ抵抗は、ゲインが不足することから、インダクタに交換。更に、低周波出力はスピーカーマイクを使う為にゲインを向上させた。






基板サイズ 73 × 95
pcbeでパターン設計し、中華にPCBを注文した。中華に発注したPCBで組立たが、終段で異常発振した。パターン引き回し上の単純なミスであった。左は、修正済みのパターン。 






2017年11月27日月曜日

stm32版si5351a VFO周波数校正

9月にsi5351a VFOに周波数校正機能を追加したが、機能をTwitterで紹介した程度であったので、機能説明をする。周波数校正機能の起動は、RITスイッチを約1秒長押する。周波数カウンタをCLK0周波数が10MHzとなる様、エンコーダで調整する。(LCDは、基準水晶発振子の周波数表示。)調整後、再びRITスイッチを約1秒長押しすると疑似EEPROMに書き込まれる。



周波数カウンタでCLK0出力周波数を表示している様子。













スケッチ

機能が含まれたスケッチは、JA2GQP's Download siteのstm32フォルダにあるstm32_si5351a.zipファイル。si5351a2.hは、水晶発振子の基本周波数を変数 xtalFreq が定義されているので、zipファイルに含まれたファイルを使う。
      

2017年11月2日木曜日

7.2MHz Knobless Wonder Filter

自作仲間JA2NKD 、JH8SST/7、Kさん でKnobless Wonderを試験している。ここで問題になっているのは、水晶発振子である。価格が安く、多く流通している物が使えれば好ましい。Knobless Wonderサイト、Knobless Wonderサイトに7.2MHz水晶発振子の紹介がある。そこで、日本国内で7.2MHz水晶発振子を使う場合、オフバンドが危惧されるので、バンド内に収まる様なフィルタを試験した。


試験した回路図である。7.2MHz以下に収める必要があるので、多少余裕を見てこの定数とした。試験回路をユニバーサル基板で作った。







FRMSで抵抗マッチング(680Ω)により測定した。一般的に-3dBにおける帯域幅をフィルタ帯域と言っているが、4ポールのシャープファクタの低いフィルタの為、-20dB(一般的なキャリアポイントの位置)でフィルタ定数を決めた。
cf(中心周波数) 7.1979MHz
cp(LSBキャリアポイント)7.1990MHz
試作した結果から、7.2MHzの水晶発振子をフィルタとして使える。ただし、最終的な回路を組み立て、実機検証する必要がある。






参考データ 

コンデンサを47pとした場合のデータである。
















今後の課題 

ユニバーサル基板で試作した為、リード線の浮遊容量が大きい。この回路方式の場合、浮遊インダクタンスの影響を大きく受けるので、最終的な姿で回路定数を決め検証する。




  

2017年9月16日土曜日

stm32 si5351a VFO(With BFO)

 このVFOは、JA2NKD OMのマルチバンドVFO にBFOを付加した物で、stm32F103c8t6+si5351aで構成している。特徴は、BFOが簡単に変更出来る様にした事と、光学エンコーダの採用でアナログ感覚のVFO操作である。BFO変更は、Modeスイッチを長押し(約1秒間スイッチを押す)エンコーダで周波数を調整後、再び、Modeスイッチを長押し(約1秒間)で書換を行う。
光学エンコーダは、中華製400P/R($10位)を使ったため、エンコーダのコントロールSTEPは、1Hz、10Hz、100Hzにした。






回路図である。光学エンコーダの電源は省略してある。stm32への書込みは、シリアルとした。理由は、省メモリとシリアルモニタが使える環境にした。開発環境にST-LINK V2を使った場合、I/O割付に制限がある様なので変更(9/17)した。









スケッチ

JA2NKD OMのオリジナルVFOは、max 8 Bandであるが6 Bandに変更している。VFO周波数は、周波数変化が2秒以上なければ、疑似EEPROMに保存する機能を追加した。si5351a2.hは、オリジナルの物を使っている。ただ、Ucglib.hは私のPC環境で複数のライブラリが参照されるため、参照場所の明確化をした。スケッチと関係ファイルは、download siteのstm32フォルダからダウンロード可能。

///////////////////////////////////////////////////////////////////////////////////
//    stm32 + si5351a VFO(With BFO) Ver1.01
//          (Based on 'JAN2KD 2016.10.19 Multi Band DDS VFO Ver3.1')  
//
//                                                        2017/9/16
//                                                        JA2GQP    
///////////////////////////////////////////////////////////////////////////////////

//---------- Library include ----------

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

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

#define ENC_A     PB12                    // Rotary encoder A
#define ENC_B     PB13                    // Rotary encoder B

Rotary r=Rotary(ENC_A,ENC_B);

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

#define   __CS    PB10                    // CS  
#define   __DC    PB0                     // D/C
#define   __RST   PB1                     // RESET

Ucglib_ILI9341_18x240x320_HWSPI ucg(__DC, __CS, __RST);

//----------   CW Tone  -------------------

#define   CW_TONE     700                // 700Hz

//----------   I/O Assign  -------------------

#define   MODE_OUT1    PB15             // 2017/9/17                 
#define   MODE_OUT2    PA8              // 2017/9/17               
#define   BAND_OUT1    PB3
#define   BAND_OUT2    PB4
#define   BAND_OUT3    PB5

#define   SW_BAND      PA0              
#define   SW_MODE      PC14              
#define   SW_STEP      PB14              
#define   SW_RIT       PC15                
#define   SW_TX        PC13              
#define   METER        PA1                

#define   EEP_BAND     0x00               // EEPROM BAND Adress
#define   EEP_INIT     0x0e               //        INIT end Adress

//---------- Variable setting ----------

long      romf[4];                        // EEPROM freq copy buffer
long      freq    = 7100000;
long      freqmax = 7200000;
long      freqmin = 7000000;
long      freqold = 0;
long      freqrit = 0;

String    freqt=String(freq);             // Frequency text

long      ifshift = 0;
long      ifshiftb;
long      romb[5];                        // EEPROM bfo copy buffer
long      vfofreq = 0;
long      vfofreqb;              

char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;

int       rit        = 0;
int       fstep      = 100;
uint16    steprom    = 1;
uint16    fmode      = 3;
uint16    fmodeb     = 3;
int       fmodeold   = 1;
int       flagrit    = 0;
int       fritold    = 0;
int       flagmode   = 0;
int       meterval1  = 0;
int       tmeterval  = 0;
int       romadd     = 0;
int       rombadd    = 0;
int       analogdata = 0;
uint16    band       = 0;                   // 3.5MHz
int       bandmax    = 6;                   // 6band

uint16    Status;
uint16    Data;          

unsigned long eep_freq[4];
int       eep_romadd;
int       eep_fstep;
int       eep_fmode;
unsigned long eep_bfo[6];
int       eep_rombadd;

int_fast32_t timepassed;                    // int to hold the arduino miilis since startup
int       flg_frqwt = 0;                                // Frequency data Wite Flag(EEPROM)
int       flg_bfowt = 0;                                // BFO Wite Flag(EEPROM)
int       flg_bfochg = 0;                               // BFO Wite Flag(EEPROM)


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

void setup() {
  timepassed = millis();

  afio_cfg_debug_ports(AFIO_DEBUG_NONE);    // ST-LINK(PB3,PB4,PA15,PA12,PA11) Can be used
  Wire.begin();                

  pinMode( ENC_A,INPUT_PULLUP);                   // PC13 pull up
  pinMode( ENC_B,INPUT_PULLUP);                   // PC14

  attachInterrupt( ENC_A, Rotaly_enc, CHANGE);    // Encorder A
  attachInterrupt( ENC_B, Rotaly_enc, CHANGE);    //          B

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

  pinMode(SW_BAND,INPUT_PULLUP);
  pinMode(SW_MODE,INPUT_PULLUP);
  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_RIT,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(ENC_A,INPUT_PULLUP);                   // pull up encorede A
  pinMode(ENC_B,INPUT_PULLUP);                   //         encorder B

  pinMode (BAND_OUT1,OUTPUT);
  pinMode (BAND_OUT2,OUTPUT);
  pinMode (BAND_OUT3,OUTPUT);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(MODE_OUT1,OUTPUT);
  pinMode(MODE_OUT2,OUTPUT);

  Fnc_eepINIT();
  delay(100);
  band2eep();
  delay(100);

  Status = EEPROM.read(EEP_BAND,&band);         // EEPROM read(frequency)
  romadd=0x010+(band*0x10);
  for (int i=0; i<3;i++){
   romf[i]=Fnc_eepRD((romadd+4*i));
  }
  freq = romf[0];
  freqmin = romf[1];
  freqmax = romf[2];
  Status = EEPROM.read(romadd+12,&fmode);
  Status = EEPROM.read(romadd+14,&steprom);

  eep_rombadd=0x090;                             // EEPROM read(BFO)
  for (int i=0; i<4;i++){
    romb[i]=Fnc_eepRD((eep_rombadd+(4*i)));
    eep_bfo[i] = romb[i];  
  }

  if (steprom==1){fstep=1;}                      // STEP set
  if (steprom==2){fstep=10;}
  if (steprom==3){fstep=100;}
  banddataout();
  screen01();
  chlcd();

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

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

void loop() {
  if(digitalRead(SW_STEP) == LOW)               // STEP sw check
    setstep();
  else if(digitalRead(SW_MODE) == LOW)          // MODE sw check
    modesw();
  else if(digitalRead(SW_RIT) == LOW)           // RIT sw check
    setrit();
  else if(digitalRead(SW_BAND) == LOW)          // BAND sw check
    bandcall();

  if (digitalRead(SW_TX)==LOW)                  // TX sw check
    txset();

  if (flagrit==1){
    if (freqrit == fritold){
      meter();
    }  
    if (freqrit!=fritold){
      PLL_write();
      ritlcd();
      fritold=freqrit;
    }
  }
  else{
    if (freq == freqold){
      meter();
    }
    PLL_write();
    freqt=String(freq);
    freqlcd();
    freqold=freq;
  }

  if((flg_frqwt == 1) && (flg_bfochg == 0)){                  // EEPROM auto save 2sec
    if(timepassed+1000 < millis()){
      bandwrite();
      flg_frqwt = 0;
    }
  }
}

//----------  EEPROM Data initialization  ---------------      

void band2eep(){
  Status = EEPROM.read(EEP_INIT,&Data);
  if(Data != 73){                       // Iinitialization check
    Status = EEPROM.write(EEP_BAND,1);
 
    eep_romadd=0x010;                   // BAND:0 ROMadd:0x010
    eep_freq[0]=3500000;
    eep_freq[1]=3500000;
    eep_freq[2]=3800000;
    eep_fmode=0;
    eep_fstep=2;
    band2write();

    eep_romadd=0x020;                   // BAND:1 ROMadd:0x020
    eep_freq[0]=7000000;
    eep_freq[1]=7000000;
    eep_freq[2]=7200000;
    eep_fmode=0;
    eep_fstep=2;
    band2write();

    eep_romadd=0x030;                   // BAND:2 ROMadd:0x030
    eep_freq[0]=10100000;
    eep_freq[1]=10100000;
    eep_freq[2]=10150000;
    eep_fmode=2;
    eep_fstep=1;
    band2write();

    eep_romadd=0x040;                   // BAND:3 ROMadd:0x040
    eep_freq[0]=14000000;
    eep_freq[1]=14000000;
    eep_freq[2]=14350000;
    eep_fmode=1;
    eep_fstep=2;
    band2write();

    eep_romadd=0x050;                   // BAND:4 ROMadd:0x050
    eep_freq[0]=21000000;
    eep_freq[1]=21000000;
    eep_freq[2]=21450000;
    eep_fmode=1;
    eep_fstep=2;
    band2write();

    eep_romadd=0x060;                   // BAND:5 ROMadd:0x060
    eep_freq[0]=28000000;
    eep_freq[1]=28000000;
    eep_freq[2]=29700000;
    eep_fmode=1;
    eep_fstep=2;
    band2write();

    eep_rombadd=0x090;                  // BFO ROMadd:0x090
    eep_bfo[0]=7999600;                 //     LSB
    eep_bfo[1]=8002600;                 //     USB
    eep_bfo[2]=8000400;                 //     CW
    eep_bfo[3]=8001100;                 //     AM

    for (int i=0;i<4;i++){
      Fnc_eepWT(eep_bfo[i],(eep_rombadd+4*i));
    }

    Status = EEPROM.write(EEP_INIT,73); // Initialyzed End code
  }
}

//----------  Function Band Write to EEPROM  ---------------      

void band2write(){
  for (int i=0;i<3;i++){
    Fnc_eepWT(eep_freq[i],(eep_romadd+4*i));
  }
  Status = EEPROM.write(eep_romadd+12,eep_fmode);
  Status = EEPROM.write(eep_romadd+14,eep_fstep);
}

//---------- PLL write ---------------------------

void PLL_write(){
  if(flg_bfochg == 0){
    if (flagrit==0)
      vfofreq=freq+ifshift;
    else
      vfofreq=freq+ifshift+freqrit;

    Vfo_out(vfofreq);                         // DDS out  2016/10/24 JA2GQP
    Bfo_out(ifshift);                         // BFO
  }
  else{
    ifshift = freq;
    Bfo_out(ifshift);                         // BFO
    freq = ifshift;
  }
}

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

void Vfo_out(long frequency){
  if(vfofreq != vfofreqb){
    si5351aSetFrequency(frequency);
    flg_frqwt = 1;                                // EEP Wite Flag
    timepassed = millis();
    vfofreqb = vfofreq;
  }
}

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

void Bfo_out(long frequency){
  if(ifshift != ifshiftb){
    si5351aSetFrequency2(frequency);
    flg_bfowt = 1;                                // EEP Wite Flag
    ifshiftb = ifshift;
  }
}

//---------- meter --------------------------

void meter(){
 meterval1=analogRead(METER);
// meterval1=meterval1/50;                   // old
 meterval1=meterval1/200;                
 if (meterval1>15){meterval1=15;}
  int sx1=sx1+(meterval1*17);
  sx1=sx1+41;
  int sx2=0;
  sx2=sx2+(40+((15-meterval1)*17));
  ucg.setFont(ucg_font_fub35_tr);
  ucg.setColor(0,0,0);
  ucg.drawBox(sx1,180,sx2,16);
  ucg.setPrintPos(40,200);
  for(int i=1;i<=meterval1;i++){
    if (i<=9){
      ucg.setColor(0,255,255);
      ucg.print("-");
    }
    else{
      ucg.setColor(255,0,0);
      ucg.print("-");
    }
  }
}

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

void Rotaly_enc(){
  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((flg_bfochg == 0) && (freq>=freqmax)){freq=freqmax;}
      }
      else{
        freq=freq-fstep;
        if((flg_bfochg == 0) && (freq<=freqmin)){freq=freqmin;}
      }
    }
  }
}

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

void txset(){
  if(fmode == 2)                              // CW?
    Vfo_out(vfofreq + CW_TONE);               // Vfofreq+700Hz
  else
    Vfo_out(vfofreq);                         // vfo out
 

  ucg.setPrintPos(110,140);
  ucg.setFont(ucg_font_fub17_tr);
  ucg.setColor(255,0,0);
  ucg.print("ON AIR");
  while(digitalRead(SW_TX) == LOW){
    meter();
  }

  ucg.setFont(ucg_font_fub17_tr);
  ucg.setColor(0,0,0);
  ucg.drawBox(100,120,250,30);  //45
}

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

void modeset(){
    ucg.setFont(ucg_font_fub17_tr);
    ucg.setPrintPos(82,82);
    ucg.setColor(0,0,0);
    ucg.print("USB");
    ucg.setPrintPos(12,82);
    ucg.print("LSB");
    ucg.setPrintPos(82,112);
    ucg.print("A M");
    ucg.setPrintPos(12,112);
    ucg.print("C W");  

  switch(fmode){
    case 0:                                       // LSB
      ifshift = eep_bfo[0];
      ucg.setPrintPos(12,82);
      ucg.setColor(255,255,0);
      ucg.print("LSB");
      digitalWrite(MODE_OUT1,LOW);
      digitalWrite(MODE_OUT2,LOW);
      break;
    case 1:                                       // USB                                    
      ifshift = eep_bfo[1];
      ucg.setColor(255,255,0);
      ucg.setPrintPos(82,82);
      ucg.print("USB");
      digitalWrite(MODE_OUT1,HIGH);
      digitalWrite(MODE_OUT2,LOW);  
      break;
    case 2:                                       // CW
      ifshift = eep_bfo[2];
      ucg.setPrintPos(12,112);
      ucg.setColor(255,255,0);
      ucg.print("C W");
      digitalWrite(MODE_OUT1,LOW);
      digitalWrite(MODE_OUT2,HIGH);
      break;
    case 3:                                       // AM
      ifshift = eep_bfo[3];
      ucg.setPrintPos(82,112);
      ucg.setColor(255,255,0);
      ucg.print("A M");
      digitalWrite(MODE_OUT1,HIGH);
      digitalWrite(MODE_OUT2,HIGH);
      break;
    default:
      ifshift = eep_bfo[0];
      ucg.setPrintPos(12,82);
      ucg.setColor(255,255,0);
      ucg.print("LSB");
      digitalWrite(MODE_OUT1,LOW);
      digitalWrite(MODE_OUT2,LOW);
      fmode = 0;
      break;
    }
}

//------------- Mode set SW ------------

void modesw(){
int cnt = 0;

  if(flg_bfochg == 0){
    while(digitalRead(SW_MODE) == LOW){
      delay(100);
      cnt++;
      if(10 <= cnt){                              // BFO data change mode(1sec)
        romadd=0x010+(band*0x10);
        romf[0]=Fnc_eepRD(romadd);
        freq = Fnc_eepRD(0x090+(fmode * 4));
        freqt=String(freq);
        freqlcd();
        ucg.setPrintPos(110,140);
        ucg.setFont(ucg_font_fub17_tr);
        ucg.setColor(255,255,0);
        ucg.print("BFO ADJ");
        fmodeb = fmode;
        flg_bfochg = 1;
        break;
      }
    }
  }
  else{
    while(digitalRead(SW_MODE) == LOW){
      delay(100);
      cnt++;
      if(10 <= cnt){                              // BFO data update(1sec)
        ifshift = freq;
        Fnc_eepWT(ifshift,0x090+(fmode * 4));     // data write
        eep_bfo[fmode] = ifshift;
        freq = romf[0];
        freqt=String(freq);
        freqlcd();
        ucg.setFont(ucg_font_fub17_tr);
        ucg.setColor(0,0,0);
        ucg.drawBox(100,120,250,30);  //45
        flg_bfochg = 0;
        fmode--;
        break;
        }
      }
    }
  if(flg_bfochg == 0)
    fmode++;
  modeset();
  PLL_write();
  while(digitalRead(SW_MODE) == LOW);
}

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

void setrit(){
  if(flagrit==0){
    flagrit=1;
    ucg.setFont(ucg_font_fub11_tr);
    ucg.setPrintPos(190,110);
    ucg.setColor(255,0,0);
    ucg.print("RIT");
    ritlcd();
  }
  else {
    flagrit=0;
    vfofreq=freq+ifshift;

    Vfo_out(vfofreq);                       // DDS Out  2016/10/23 JA2GQP

    freqt=String(freq);
    ucg.setFont(ucg_font_fub11_tr);
    ucg.setPrintPos(190,110);
    ucg.setColor(255,255,255);
    ucg.print("RIT");
    ucg.setColor(0,0,0);
    ucg.drawRBox(222,92,91,21,3);
    freqrit=0;
  }
  while(digitalRead(SW_RIT) == LOW);
}

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

void ritlcd(){
  ucg.setColor(0,0,0);
  ucg.drawBox(222,92,91,21);
  ucg.setFont(ucg_font_fub17_tr);
  ucg.setColor(255,255,255);
  ucg.setPrintPos(230,110);
  ucg.print(freqrit);
}

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

void setstep(){
  if (fstep==100){
    fstep=1;
  }
  else{
    fstep=fstep * 10;
  }
 steplcd();
 while(digitalRead(SW_STEP) == LOW);
}

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

void steplcd(){
  ucg.setColor(0,0,0);
  ucg.drawRBox(221,61,93,23,3);
  ucg.setFont(ucg_font_fub17_tr);
  ucg.setColor(255,255,255);
  ucg.setPrintPos(220,80);
  if (fstep==1){ucg.print("     1Hz");}
  if (fstep==10){ucg.print("    10Hz");}
  if (fstep==100){ucg.print("   100Hz");}
}

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

void freqlcd(){
  ucg.setFont(ucg_font_fub35_tn);
  int mojisuu=(freqt.length());
  if(freq<100){
    ucg.setColor(0,0,0);
    ucg.drawBox(217,9,28,36);  
  }
  if(f10 !=(freqt.charAt(mojisuu-2))){
    ucg.setColor(0,0,0);
    ucg.drawBox(245,9,28,36);
    ucg.setPrintPos(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));
  }
  if(freq<1000){
    ucg.setColor(0,0,0);
    ucg.drawBox(202,9,15,36);      
    }
  if(f100 !=(freqt.charAt(mojisuu-3))){
    ucg.setColor(0,0,0);
    ucg.drawBox(217,9,28,36);
    ucg.setPrintPos(217,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-3));
    f100 = (freqt.charAt(mojisuu-3));
  }
  if(freq>=1000){
    ucg.setPrintPos(202,45);
    ucg.setColor(0,255,0);
    ucg.print(".");
  }
  if(freq<10000){
    ucg.setColor(0,0,0);
    ucg.drawBox(146,9,28,36);  
    }
  if(f1k !=(freqt.charAt(mojisuu-4))){
    ucg.setColor(0,0,0);
    ucg.drawBox(174,9,28,36);
    ucg.setPrintPos(174,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-4));    
    f1k  = (freqt.charAt(mojisuu-4));
  }
  if(freq<100000){
    ucg.setColor(0,0,0);
    ucg.drawBox(118,9,28,36);
  }
  if(f10k !=(freqt.charAt(mojisuu-5))){
    ucg.setColor(0,0,0);
    ucg.drawBox(146,9,28,36);
    ucg.setPrintPos(146,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-5));
    f10k = (freqt.charAt(mojisuu-5));
  }
   if(freq<1000000){
    ucg.setColor(0,0,0);
    ucg.drawBox(103,9,15,36);
    }
  if(f100k !=(freqt.charAt(mojisuu-6))){
    ucg.setColor(0,0,0);
    ucg.drawBox(118,9,28,36);
    ucg.setPrintPos(118,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-6));
    f100k = (freqt.charAt(mojisuu-6));
  }
     
   if(freq>=1000000){
    ucg.setPrintPos(103,45);
    ucg.setColor(0,255,0);
    ucg.print(".");
  }
   if(freq<10000000){
     ucg.setColor(0,0,0);
    ucg.drawBox(47,9,28,36);
     }
   if(fmega !=(freqt.charAt(mojisuu-7))){
    ucg.setColor(0,0,0);
    ucg.drawBox(75,9,28,36);
    ucg .setPrintPos(75,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-7));
    fmega  = (freqt.charAt(mojisuu-7));
   }
   if(freq<100000000){
    ucg.setColor(0,0,0);
    ucg.drawBox(19,9,28,36);
       }
   if (f10m !=(freqt.charAt(mojisuu-8))){
    ucg.setColor(0,0,0);
    ucg.drawBox(47,9,28,36);
    ucg .setPrintPos(47,45);
    ucg.setColor(0,255,0);
    ucg.print(freqt.charAt(mojisuu-8));
    f10m = (freqt.charAt(mojisuu-8));
   }
}
//----------- Basic Screen -------------------------

void screen01(){
  ucg.setColor(255,255,255);
  ucg.drawRFrame(1,1,314,55,5);
  ucg.drawRFrame(2,2,312,53,5);
  ucg.setColor(50,50,50);
  ucg.drawRBox(5,60,60,25,3);
  ucg.drawRBox(75,60,60,25,3);
  ucg.drawRBox(5,90,60,25,3);
  ucg.drawRBox(75,90,60,25,3);
  ucg.setFont(ucg_font_fub17_tr);
  ucg.setPrintPos(12,82);
  ucg.setColor(0,0,0);
  ucg.print("LSB");
  ucg.setPrintPos(82,82);
  ucg.print("USB");
  ucg.setPrintPos(12,112);
  ucg.print("C W");
  ucg.setPrintPos(82,112);
  ucg.print("A M");
  ucg.setColor(255,255,255);
  ucg.drawRFrame(220,60,95,25,3);
  ucg.drawRFrame(220,90,95,25,3);
  ucg.setFont(ucg_font_fub11_tr);
  ucg.setColor(255,255,255);
  ucg.setPrintPos(175,80);
  ucg.print("STEP");
  ucg.setPrintPos(190,110);
  ucg.setColor(255,255,255);
  ucg.print("RIT");
  ucg.setColor(100,100,100);
  ucg.setPrintPos(10,210);
  ucg.print(" S:  1-----3-------6-------9---Over--------");
  ucg.setPrintPos(10,177);
  ucg.print(" P:  1-----3-----5-----------10--------------");
  ucg.setPrintPos(10,230);
  ucg.setColor(235,0,200);
  ucg.print( "stm32 VFO(with BFO) Ver1.0 JA2GQP");
  ucg.setFont(ucg_font_fub35_tr);
    ucg.setColor(0,255,0);
    ucg.setPrintPos(273,45);
    ucg.print("0");  
}

//---------- Band data call from eeprom ----------

void bandcall(){
  band=band+1;
  if (band>(bandmax-1)){band=0;}
  romadd=0x010+(band*0x010);
 for (int i=0; i<3;i++){
   romf[i]=Fnc_eepRD((romadd+4*i));
  }
  freq = romf[0];
  freqmin = romf[1];
  freqmax = romf[2];
  Status = EEPROM.read(romadd+12,&fmode);
  Status = EEPROM.read(romadd+14,&steprom);

  if (steprom==1){fstep=1;}
  if (steprom==2){fstep=10;}
  if (steprom==3){fstep=100;}

  modeset();
  steplcd();
  freqt=String(freq);
  freqlcd();
  banddataout();
  chlcd();
 while(digitalRead(SW_BAND) == LOW);
}

//---------- Band data write to eeprom ----------

void bandwrite(){
  romadd=0x010+(band*0x010);
    Fnc_eepWT(freq,romadd);
  Status = EEPROM.write(EEP_BAND,band);
  Status = EEPROM.write(romadd+12,fmode);
  if (fstep==1){steprom=1;}
  if (fstep==10){steprom=2;}
  if (fstep==100){steprom=3;}
  Status = EEPROM.write(romadd+14,steprom);
}

//----------  Function EEPROM Initialize  ---------

void Fnc_eepINIT(){
  uint16 dummy;

  EEPROM.PageBase0 = 0x801F000;
  EEPROM.PageBase1 = 0x801F800;
  EEPROM.PageSize  = 0x400;             // 2kB
  dummy = EEPROM.init();
}

//----------  Function EEPROM Read(4byte)  ---------

long Fnc_eepRD(uint16 adr){
  long val = 0;
  uint16 dat,dummy;

  dummy = EEPROM.read(adr,&dat);
  val = dat << 16;
  dummy = EEPROM.read(adr+1,&dat);
  return val | dat;
}

//----------  Function EEPROM Write(4byte)  ---------

void Fnc_eepWT(long dat,uint16 adr){
  uint16 dummy,val;

  val = dat & 0xffff;
  dummy = EEPROM.write(adr+1,val);
  val = dat >> 16;
  val = val & 0xffff;
  dummy = EEPROM.write(adr,val);
}

//---------- Band data output I/O ----------

void banddataout(){
  digitalWrite(BAND_OUT1,LOW);
  digitalWrite(BAND_OUT2,LOW);
  digitalWrite(BAND_OUT3,LOW);
  if (band==0){}
  if (band==1){
   digitalWrite( BAND_OUT1,HIGH);
  }
   if (band==2){
   digitalWrite(BAND_OUT2,HIGH);
  }
  if (band==3){
   digitalWrite(BAND_OUT1,HIGH);
   digitalWrite(BAND_OUT2,HIGH);
  }
  if (band==4){
   digitalWrite(BAND_OUT3,HIGH);
  }
  if (band==5){
   digitalWrite(BAND_OUT1,HIGH);
   digitalWrite(BAND_OUT3,HIGH);
  }
  if (band==6){
   digitalWrite(BAND_OUT2,HIGH);
   digitalWrite(BAND_OUT3,HIGH);
  }
  if (band==7){
   digitalWrite(BAND_OUT1,HIGH);
   digitalWrite(BAND_OUT2,HIGH);
   digitalWrite(BAND_OUT3,HIGH);  
  }
}

//----------  Band No.(Chanel No.) write to LCD ----------

void chlcd(){
  ucg.setColor(0,0,0);
  ucg.drawBox(5,120,80,20);
  ucg.setFont(ucg_font_fub11_tr);
  ucg.setPrintPos(12,137);
  ucg.setColor(255,255,255);
  ucg.print("CH: ");
  ucg.print(band+1);
}


     

2017年7月31日月曜日

K4GC VFO

何時もお世話になっているKさんから、K4GC VFOスケッチについて相談を受けた。エンコーダ操作で周波数調整が困難との事であった。スケッチを見ると割込み処理を行わずに、エンコーダ読取りが行われており、取りこぼしが原因と思われる。今回問題が有ったエンコーダ処理とLCD表示を変更した。

回路図である。
ダイレクトコンバージョン受信機と組合わせた40m CW QRP機で、フルブレイクイン動作する。オリジナルからkey paddleとエンコーダのIO割付のみ変更。









スケッチ

基本的な処理は、オリジナルを継承している。RIT処理がアナログ処理で行われており、参考になる所もある。スケッチは、ダウンロードサイトのsi5351aフォルダ。

/**************************************************************************
   DIRECT CONVERSION CW TRANSCEIVER CONTROLLER WITH IAMBIC KEYER FOR ARDUINO
   Uses SI5351 clock generator shild from Adafruit for VFO
   Uses NT7S SI5351 library for Arduino on github:
   https://github.com/etherkit/Si5351Arduino
   2 x 16 LCD display for frequency, offset, and tuning rate
   Has an iambic keyer with dot/dash memories
   Arduino Pro Mini pin assignments:
   2) Encoder A input
   3) Encoder B input
   4) STEP SW
   5) Iambic paddle DSH input
   6) Iambic paddle DIT input
   7)
   8) Transmit/mute output
   9) Sidetone output
   10) LCD RS output
   11) LCD E output
   12) LCD D4 output
   13) LCD D5 output
   A0) LCD D6 output
   A1) LCD D7 output
   A2)
   A3)
   A4) si5351 SDA
   A5) si5351 SCL
   A6) Offset voltage input
   A7) Keyer speed voltage input
 ***************************************************************************/

#include <si5351.h>
#include "Wire.h"
#include <Rotary.h>
#include "src/LiquidCrystal.h"                // use Arduino LCD library.


//----------   PLL setting  --------------------

Si5351 si5351;

//----------   LCD setting  --------------------

LiquidCrystal lcd(10, 11, 12, 13, A0, A1);  // RS,E,D4,D5,D6,D7

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

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

Rotary r=Rotary(ENC_A,ENC_B);


////////////////////////ENCODER SETUP///////////////////////////////////////
#define SW_STEP       4
#define Pad_Dah       5
#define Pad_Dit       6  
#define XMIT          8
#define TONE          9

#define LW_FRQ        7000000L
#define HI_FRQ        7200000L

long Vfo_Dat = 7030000L;                      //Start up frequency <<<2017/6/27>>>
long Vfo_Datb = 0;                            //                   <<<2017/6/27>>>
int Enc_Stp = 10;                             // STEP=10Hz
int rateindicator = 5;
char Lcd_data[17] = "                ";
int Flg_Set0 = 1;
/////////////////////////////////////////////////////////////////////////////

//////////////////////////////RIT SETUP//////////////////////////////////////
int rit = A6;
int ritvoltage = 0;
int oldritvoltage = 0;
int modulo = 0;
int ritcenter = 512;
int rittune = 0;
int rittuneb = rittune;
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////IAMBIC KEYER////////////////////////////////////
int count = 0;
int dit = 1;
int dah = 1;
int sidetone = 700;
int ditmem = 0;
int dahmem = 0;
int sspeed = 50;
int speedinput = A7;
/////////////////////////////////////////////////////////////////////////////

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

void setup(){
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  lcd.begin(16, 2);

  pinMode(Pad_Dah, INPUT_PULLUP);                  // Dah
  pinMode(Pad_Dit, INPUT_PULLUP);                  // Dit

  pinMode(SW_STEP, INPUT_PULLUP);                  // STEP

  pinMode(TONE, OUTPUT);
  pinMode(XMIT, OUTPUT);
  digitalWrite(XMIT, HIGH);

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

  Fnc_Step_Disp();
}

//----------  Main loop  --------

void loop() {
  if(digitalRead(SW_STEP) == LOW)                   // STEP SW On?
    Fnc_Stp();                          

  setclock0();
 
  ritvoltage = analogRead(A6);
  rittune = ritvoltage - ritcenter;
  rittune = rittune * 5;
  if (ritvoltage != oldritvoltage){
    ritune();
  }

  if (ditmem == 1) makedit();
  if (dahmem == 1) makedah();
  sspeed = analogRead(speedinput);
  sspeed = sspeed / 6.5;
  if (sspeed < 24) sspeed = 24;
  count = 0;
  checkpaddle();
}

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

ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if(result) {  
    if(result == DIR_CW)
      Vfo_Dat = Vfo_Dat + Enc_Stp;
    else
      Vfo_Dat = Vfo_Dat - Enc_Stp;
    Vfo_Dat = constrain(Vfo_Dat,LW_FRQ,HI_FRQ);
  }
  Flg_Set0 = 1;
}

//----------  Set Clock0  ---------------

void setclock0() {                            //function to set the SI5351 clock frequency
  if(Flg_Set0 == 1){
    lcd.setCursor(2, 0);
    Fnc_Dot_Edit(Lcd_data,Vfo_Dat);
    lcd.print(Lcd_data);
    lcd.print(" MHz");
    si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
  }
  Flg_Set0 = 0;
}

//----------  RIT proc  ---------------

void ritune() {                             //function to determine RIT offset frequency
  modulo = 0;
  oldritvoltage = ritvoltage;
  rittune = ritvoltage - ritcenter;
  rittune = rittune * 5;                    //RIT steps in 5 Hz increments
  if (rittune > 30) {                       //Keep a dead zone near 0 offset
    rittune = rittune;
  }
  else if (rittune < -30)  {
    rittune = rittune;                      //Keep a dead zone near 0 offset
  }
  else {
    rittune = 0;
  }
  lcd.setCursor(8, 1);
  lcd.print("        ");
  lcd.setCursor(8, 1);
  lcd.print("Rit");
  if (rittune > 0) {
    lcd.print("+");
  }
  lcd.print(rittune);
  Flg_Set0 = 1;
  setclock0();
}

//----------  Check Paddle  ---------------

void checkpaddle() {                            //function for checking iambic paddle status
  dit = digitalRead(Pad_Dit);
  dah = digitalRead(Pad_Dah);
  if (!dit) makedit();
  if (!dah) makedah();
}

//----------  Dit make proc  ---------------

void makedit() {                                //function to make dits
  count = 0;
  ditmem = 0;
  si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
  digitalWrite(XMIT, 0);
  tone(TONE, sidetone);
  while (count < sspeed) {
    dah = digitalRead(Pad_Dah);
    if (!dah) dahmem = 1;
    delay(1);
    ++count;
  }
  count = 0;
  noTone(TONE);
  digitalWrite(XMIT, 1);
  si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
    while (count < sspeed) {
    dah = digitalRead(Pad_Dah);
    delay(1);
    ++count;
  }
}

//----------  Dah make proc  ---------------

void makedah(){                                 //function to make dahs
  count = 0;
  dahmem = 0;
  si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
  digitalWrite(XMIT, 0);
  tone(TONE, sidetone);

  while (count < (sspeed * 3)){
    dit = digitalRead(Pad_Dit);
    if (!dit) ditmem = 1;
    delay(1);
    ++count;
  }

  count = 0;
  noTone(TONE);
  digitalWrite(XMIT, 1);
  si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);

  while (count < sspeed) {
    dit = digitalRead(Pad_Dit);
    if (!dit) ditmem = 1;
    delay(1);
    ++count;
  }
}

//----------  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 Encorder STEP  ---------

void Fnc_Stp(){
  if(Enc_Stp == 10000)                   // Step = 10kHz ?
    Enc_Stp = 10;                        //   Yes,100khz set
  else
    Enc_Stp = Enc_Stp * 10;              // Step up 1 digit

  Fnc_Step_Disp();
  while(digitalRead(SW_STEP) == LOW)
    ;
  delay(50);
}

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

void Fnc_Step_Disp(){
  lcd.setCursor(0,1);
  switch(Enc_Stp){
    case 10:
      lcd.print("Step10 ");
      break;
    case 100:
      lcd.print("Step100");
      break;
    case 1000:
      lcd.print("Step1k ");
      break;
    case 10000:
      lcd.print("Step10k");
      break;
    default:
      lcd.print("Step10 ");
      Enc_Stp = 10;
      break;
  }
}


     

2017年6月17日土曜日

stm32VFO 6mAM

stm32f103c8t6とsi5351aを使って、50MHzAM用VFOを作った。周波数は50MHzから51MHzまでとし、STEPは1Khz、10kHzとした。電源off時の周波数とSTEPを電源on時に復帰させるメモリ機能を付加したVFOである。資料は、Download siteのstm32フォルダに保存してある。






stm32BaseBordから不要な部分を除いた、回路図である。












スケッチ

si5351a2.hは、本来、スケッチと同じフォルダに入れるが、srcフルダに入れ階層的にした。PLL発振出力は clk0 1chのみである。デフォルト周波数は、50.6MHzとし、STEPは10kHz刻みにした。受信機はダブルスーパ(IF=10.7MHz)を想定したので、条件が異なれば修正が必要。メモリー保存は、AD7C方式を採用した。また、周波数補正は、si5351a2.hの41行目XTAL_FREQ 25000000を実周波数(カウンターなどで測定した値)に書換えれば良い。

///////////////////////////////////////////////////////////////////
//    si5351a Simple 50MHz AM VFO(Memory Version) Ver1.01
//                                        2017/6/17
//                                        JA2GQP
//-----------------------------------------------------------------
//  Bug fixes
//    Encoder processing problem.   Ve.1.01 2017/8/17
///////////////////////////////////////////////////////////////////

#include <LCD5110_Basic.h>
#include <Rotary.h>
#include <EEPROM.h>
#include "src/si5351a2.h"

#define ENC_A     PC13                            // Rotary encoder A
#define ENC_B     PC14                            // Rotary encoder B
#define SW_STEP   PC15                            // Frequency Change Step
#define SW_TX     PB12                            // TX switch

#define LOW_FREQ  50000000                        // Lowwer Frequency (50MHz)
#define HI_FREQ   51000000                        // Upper Frequency  (51MHz)
#define IF_FREQ   10700000                        // IF Frequency

#define EEP_FREQ  0x00                            // EEPROM Frequency Adress
#define EEP_STEP  0x04                            //        STEP
#define EEP_INIT  0x20                            // Initialyze check Adress
#define EEP_END   0x73                            // Initialyze check data

//------ Register define ------

long Vfo_freq =  50600000;                        // Default Frequency(50.6MHz )
long Vfo_freqb = Vfo_freq;                        // Frequency Old
long Enc_step = 10000;                            // Default STEP
byte Flg_Tx;                                      // TX Flag

uint16 Status;
uint16 Data;

int_fast32_t timepassed;                          // int to hold the arduino miilis since startup

int Flg_eepWT = 0;                                // EEP Wite Flag

char Lcd_data[10];

//------  nokia5110 ------

LCD5110 myGLCD(PB3,PB5,PA15,PA12,PA11);        // SCK,MOSI,DC,RST,CS
extern uint8_t SmallFont[];
extern uint8_t MediumNumbers[];

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

Rotary r = Rotary(ENC_A,ENC_B);               // ENC_A=2,ENC_B=3

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

void setup(){
  timepassed = millis();
  Wire.begin();                  

  attachInterrupt(PC13, Rotaly_enc, CHANGE);    // Encorder A
  attachInterrupt(PC14, Rotaly_enc, CHANGE);    //          B

  pinMode(PC13,INPUT_PULLUP);                   // PC13 pull up
  pinMode(PC14,INPUT_PULLUP);                   // PC14
  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);


  Fnc_eepINIT();
 
  Status = EEPROM.read(EEP_INIT, &Data);
  if(Data != EEP_END){
    Status = EEPROM.write(EEP_INIT, EEP_END);
    Vfo_freq = 50600000;
    Fnc_eepWT(Vfo_freq,EEP_FREQ);
    Fnc_eepWT(Enc_step,EEP_STEP);
  }
  else{
    Vfo_freq = Fnc_eepRD(EEP_FREQ);
    Enc_step = Fnc_eepRD(EEP_STEP);
  }


  Si5351_write(XTAL_LOAD_C,0x80);               // Crystal Load Capasitance=8pF
  si5351aSetFrequency(Vfo_freq);                // CLK0

  myGLCD.InitLCD();                             // nokia5110 Initialyze
  Feq_disp(Vfo_freq);
  Stp_disp();
  myGLCD.setFont(SmallFont);
  myGLCD.print("JA2GQP",CENTER,32);
}

//---------- Main Loop --------------------------------------------------------

void loop(){
  if(Flg_Tx == 0){
    if(digitalRead(SW_STEP) == LOW)             // STEP sw check
      Fnc_Stp();
  }                      

  if(digitalRead(SW_TX) == LOW)                 // Tx On?
    Flg_Tx = 1;                            
  else                                  
    Flg_Tx = 0;                                          

  if(Vfo_freq != Vfo_freqb){                    // Frequency update?
    Vfo_freqb = Vfo_freq;
    Flg_eepWT = 1;
    myGLCD.clrRow(0);
    myGLCD.clrRow(1);
    Feq_disp(Vfo_freq);                         // Frequency display
  }

    if(Flg_Tx  == 0){
      si5351aSetFrequency(Vfo_freq+IF_FREQ);    // CLK0 = RX frequency
      myGLCD.setFont(SmallFont);  
      myGLCD.print("     ", CENTER,16);
    }    
    else{
      si5351aSetFrequency(Vfo_freq);            // CLK0 = TX frequency
      myGLCD.setFont(SmallFont);  
      myGLCD.print("OnAir", CENTER,16);
    }

  if(Flg_eepWT == 1){  
    if(timepassed+2000 < millis()){
      Fnc_eepWT(Vfo_freq,EEP_FREQ);
      Flg_eepWT = 0;
    }
  }  
 
}

//---------- Rotary Encorder Interrupt handling ------------------------------

void Rotaly_enc(){
  noInterrupts();
  unsigned char result = r.process();
  if(Flg_Tx == 0){
    if(result) {  
      if(result == DIR_CW)
        Vfo_freq = Vfo_freq + Enc_step;
      if(result == DIR_CCW)
        Vfo_freq = Vfo_freq - Enc_step;
      Vfo_freq = constrain(Vfo_freq,LOW_FREQ,HI_FREQ);    // Frequency range check
    }
  }
  interrupts();
}

//---------- Step -------------------------------------------------------------

void Fnc_Stp(){
  if(Enc_step == 10000)                           // Step = 10kHz ?
//    Enc_step = 10;                                // 10Hz set
     Enc_step = 1000;                             // 1kHz set
  else
    Enc_step= Enc_step * 10;
  Stp_disp();
  while(digitalRead(SW_STEP) == LOW)
    ;
  delay(20);
}


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

void Feq_disp(long f_disp){
  char s[4] ={'\0'};

  Fnc_Dot_Edit(Lcd_data,f_disp/1000L);
  myGLCD.setFont(MediumNumbers);
  myGLCD.print(Lcd_data,RIGHT, 0);

//  myGLCD.printNumI(f_disp/1000L,RIGHT, 0);
//  myGLCD.setFont(SmallFont);
//  sprintf(s,"%03d",f_disp%1000L);
//  myGLCD.print(s,RIGHT,16);

}

//---------- Step Display ------------------------------------------------------

void Stp_disp(){
  myGLCD.setFont(SmallFont);
  switch(Enc_step){
//    case 10:
//      myGLCD.print("10  ", LEFT,16);
//      break;
//    case 100:
//      myGLCD.print("100 ", LEFT,16);
//      break;
    case 1000:
      myGLCD.print("1k  ", LEFT,16);
      break;
    case 10000:
      myGLCD.print("10k ", LEFT,16);
      break;
    default:
      myGLCD.print("10k ", LEFT,16);
      Enc_step = 10000;
      break;
  }
  Fnc_eepWT(Enc_step,EEP_STEP);
}

//----------  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 EEPROM Initialize  ---------

void Fnc_eepINIT(){
  uint16 dummy;
 
  EEPROM.PageBase0 = 0x801F000;
  EEPROM.PageBase1 = 0x801F800;
  EEPROM.PageSize  = 0x400;             // 2kB
  dummy = EEPROM.init();
}

//----------  Function EEPROM Read(4byte)  ---------

long Fnc_eepRD(uint16 adr){
  long val = 0;
  uint16 dat,dummy;

  dummy = EEPROM.read(adr,&dat);
  val = dat << 16;
  dummy = EEPROM.read(adr+1,&dat);
  return val | dat;
}

//----------  Function EEPROM Write(4byte)  ---------

void Fnc_eepWT(long dat,uint16 adr){
  uint16 dummy,val;

  val = dat & 0xffff;
  dummy = EEPROM.write(adr+1,val);
  val = dat >> 16;
  val = val & 0xffff;
  dummy = EEPROM.write(adr,val);
}


2017年6月12日月曜日

stm32f103c8t6 Base Bord

stm32f103c8t6のスケッチを開発するにあたり、プロトタイプのベースボードを作った。同時に、このボードのI/O割付に修正したスケッチサンプルを作った。このサンプルを使えば、VFOを簡単に作る事が出来るであろう。





ベースボードの回路図である。スケッチ書込みポートは、シリアルのコネクタを設けてあり、USBアダプタ(CH340G)を直接繋ぐ事ができる。表示器は、0.96"OLED、1.8"TFT、nokia5110を繋ぐ事ができる。si5351a取付コネクタを設けてあるので、このままVFO開発が可能。






サンプルスケッチ

全てのサンプルは、先に紹介した回路図に対応する様、I/O割付を変更済である。回路図通り接続し、即、スケッチが実行可能。このサンプルスケッチは、JA2GQP's Download siteのstm32フォルダ。

・Blink

LEDのブリンク。

・encorder

stm32f103c8t6の割込み処理は自由度がある。どのポートに割付しても、割込み処理で動作させる事ができる。

・si5351a

PLL出力(clk0、clk2)の出力サンプル。

・noki5110

nokia5110液晶文字表示サンプル。

・oled(ssd1306)

oledグラフィック表示サンプル。

・メモリ記憶

エンコーダと組合わせた、メモリ記憶のサンプル。

・Ucglib(ili9341、st7735)

TFT液晶の表示サンプル。

VFO製作例


              
サンプルスケッチを基にして作ったVFO。

            

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
}