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