2014年2月28日金曜日

Arduino AD9850 DDS VFO

Arduino UNO R3によるAD9850 DDS VFOである。Arduinoにトライした理由は、BASCOM AVR FREE版で限界を感じ、細かな部分を割愛していた為である。Arduinoは、BASCOMを単純に移植しても、十分なメモリーがある。
公開中のAD9850 DDS VFO Version1.1b相当の機能を盛り込んだプログラムとした。変更点は、ロータリーエンコーダを割り込み処理にした事と、SPLIT機能の周波数制限を行った位である。プログラムは単純なコード変換の為、冗長かも知れない。
UNO R3が、中華サイトで1200円位で買えるので、遊ぶのも面白い。
Arduinoには、閉じた独自の文化が有るようで、参考になれば幸いだ。   
基本的にBASCOM版と同じだが、パターン引き回し都合で、I/O割り付けを替えている。エンコーダは、割り込み処理のため他のI/O割り付けできない。
     










 

基板サイズ 54 x69。
無論、基板はスタッカブルである。












Program

割り込み処理を行っており、ライブラリーが必要。ライブラリーは、プログラムのヘッダーに書いてあるURLから
ダウンロードし、Arduino IDEのスケッチタブのライブラリ使用で設定する。

//////////////////////////////////////////////////////////////////////
//  AD9850 DDS VFO Premixed type program ver.1.0
//
//    Copyright(C)2014.JA2GQP.All rights reserved.
//
//      7.000MHz to 7.200MHz Limitted.
//      (Target frequency = IF frquency + frequency)
//                                                  2014/2/28
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.Upper Heterodyne(Target Frequency = IF Frequency + Frequency)
//    2.RIT Operation(-50kHZ to 50kHZ)
//    3.STEP(100k,10k,1k,100,10)
//    4.Memory Operation is Push RIT
//      (Frequency and Step)
//    5.Protection Operation At The Time Of Transmission
//    6.Channel Memory.Main Channel(Ch0) + 3 Channel(Ch1,Ch2,Ch3)
//    7.Split Operation(7.00MHz to 7.20MHz Limited!)
//--------------------------------------------------------------------
//  Library
//  http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
//
//--------------------------------------------------------------------
//  Bug Fix
//    2016/7/10 Fixed erroneous display.(Fnc_Step_Disp)
//////////////////////////////////////////////////////////////////////

#include <LiquidCrystal.h>
#include <rotary.h>
#include <EEPROM.h>

//----------  LCD Pin Assign  ------------------

LiquidCrystal lcd(13, 12, 11, 10, 9, 8);   // RS,R/W,DB4,DB5,DB6,DB7

//----------  Define Constant Value   ----------
                                               
const byte  ENC_A = 2;                     // Encorder A
const byte  ENC_B = 3;                     // Encoeder B
const byte  SW_STEP = 4;                   // STEP Sw
const byte  SW_RIT = 5;                    // RIT Sw
const byte  SW_SPLIT = 6;                  // SPLIT Sw
const byte  SW_TX = 7;                     // TX Sw
const byte  W_CLK = 14;                    // DIO14(A0)
const byte  FQ_UD = 15;                    // DIO15(A1)
const byte  DATA = 16;                     // DIO16(A2)
const byte  SW_CH1 = 17;                   // DIO17(A3)
const byte  SW_CH2 = 18;                   // DIO18(A4)
const byte  SW_CH3 = 19;                   // DIO18(A5)

const long  IF_FRQ = 9996500L;             // IF Frequency
const long  LW_FRQ = 7000000L;             // Lower Limit
const long  HI_FRQ = 7200000L;             // Upper Limit
const long  DEF_FRQ = 7050000L;            // Init Frequency
const long  DEF_STP = 1000L;               // Init STEP
const long  LW_RIT = -50000L;              // RIT Lower Limit
const long  HI_RIT = 50000L;               // RIT Upper Limit
const long  LW_VFO = IF_FRQ + LW_FRQ;      // Vfo Lower Limit
const long  HI_VFO = IF_FRQ + HI_FRQ;      // Vfo Upper Limit
const long  DEF_VFO = IF_FRQ + DEF_FRQ;    // Vfo Default Frequency

const unsigned long  DDS_CLK = 125000000L; // AD9850 Clock
const unsigned long  TWO_E32 = 4294967295L;// 2^32
const byte  DDS_CMD = B00000000;           // AD9850 Command

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

const byte  Frq_Eep0 = 0x00;               // Frequency Ch0
const byte  Frq_Eep1 = 0x04;               //           Ch1                                              
const byte  Frq_Eep2 = 0x08;               //           Ch2
const byte  Frq_Eep3 = 0x0c;               //           Ch3

const byte  Stp_Eep0 = 0x10;               // STEP Ch0
const byte  Stp_Eep1 = 0x14;               //      Ch1                                              
const byte  Stp_Eep2 = 0x18;               //      Ch2
const byte  Stp_Eep3 = 0x1c;               //      Ch3

//----------  Encorder Pin Assign(INT)  --------

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

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

long Vfo_Dat = 0;                         // VFO Data
long Dds_Dat = 0;                         // DDS Data
long Rit_Dat = 0;                         // RIT Data
long Rit_Datb = 0;                        // RIT Data Old
long Enc_Stp = 0;                         // STEP
long Lng_Wk1 = 0;                         // Long Work1
long Lng_Wk2 = 0;                         // Long Work2

char *Lcd_Dat = "           ";            // Lcd Display Buffer

byte Byt_Chn = 0;                         // Channel SW
byte Byt_Chnb = 0;                        // Channel SW Old
byte Flg_Rit = 0;                         // RIT Flag
byte Flg_Ritb = 0;                        // RIT Flag Old
byte Flg_Tx = 0;                          // TX Flag
byte Flg_Spl = 0;                         // SPLIT Flag

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

void setup(){
  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_RIT,INPUT_PULLUP);
  pinMode(SW_SPLIT,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH1,INPUT_PULLUP);
  pinMode(SW_CH2,INPUT_PULLUP);
  pinMode(SW_CH3,INPUT_PULLUP);

  lcd.begin(16, 2);                        // LCD 16*2

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

  pinMode(FQ_UD,OUTPUT);
  pinMode(W_CLK,OUTPUT);
  pinMode(DATA,OUTPUT);

  Flg_Tx = 0;
  Flg_Rit = 0;
  Flg_Spl = 0;
 
  lcd.clear();
  Fnc_Chsw();                                // Channel Sw Read
  Byt_Chnb = Byt_Chn;
  Fnc_Eep_Rd();                              // EEPROM Read
}

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

void loop() {
  if(Flg_Tx == 0){                          // Tx off?
    if(digitalRead(SW_STEP) == LOW){        // STEP Sw On?
      Fnc_Stp();                            //     Yes,STEP proc.
    }
    if(digitalRead(SW_RIT) == LOW){         // RIT Sw On?
      Fnc_Rit();                            //     Yes,RIT proc.
    }
    if(digitalRead(SW_SPLIT) == LOW){       // SPLIT Sw On?
      Fnc_Spl();                            //     Yes,SPLIT proc.
    }
    Fnc_Chsw();                             // Channel Sw read
   
    if(Byt_Chnb != Byt_Chn){                // Channnel SW Chenge?
      if(Byt_Chnb == 0){                    // Channnel 0?    
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep0);     //   Yes,Vfo_Dat Save
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep0);     //       Enc_Step Save
        Flg_Ritb = Flg_Rit;
        Rit_Datb = Rit_Dat;
        Flg_Rit = 0;
        Flg_Spl = 0;
        Rit_Dat = 0;
      }
     
      if(Byt_Chnb != 0){                    // Other(Ch1-Ch3) Channnel?
        Flg_Rit = 0;
        Flg_Spl = 0;
        if((Byt_Chn == 0) && (Flg_Ritb == 1)){
          Flg_Rit = 1;
          Rit_Dat = Rit_Datb;
        }
      }
       
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
    }
  }
  if(digitalRead(SW_TX) == LOW){            // Tx On?
    Flg_Tx = 1;                             //    Yes,Flg_Tx Set
  }
  else{                                    
    Flg_Tx = 0;                            //     No,Flg_Tx Reset              
  }

  if(Flg_Rit == 1){                        // RIT?
    Dds_Dat = Vfo_Dat + Rit_Dat;           //    Yes,Dds_Dat Set
  }
  else{
    Dds_Dat = Vfo_Dat;                     //    No,Dds_Dat Set
  }

  if(Flg_Tx == 1){                         // Tx?
    if(Flg_Spl == 1){                      // SPLIT?
      Dds_Dat = Vfo_Dat + Rit_Dat;         //    Yes,Dds_Dat Set
    }
      else{
        Dds_Dat = Vfo_Dat;                 //    No,Dds_Dat Set
      }
  }
  Fnc_Dds(Dds_Dat);                        // AD9850 DDS Out
  Fnc_Lcd();                               // LCD Display
  delay(100);
}

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

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

  if(Flg_Tx == 0){
    if(result) {  
      if(result == DIR_CW){
        Lng_Wk1 = Vfo_Dat + Enc_Stp;
        Lng_Wk2 = Rit_Dat + Enc_Stp;
      }
      else{
          Lng_Wk1 = Vfo_Dat - Enc_Stp;
          Lng_Wk2 = Rit_Dat - Enc_Stp;
      }      
      if((Flg_Rit == 1) || (Flg_Spl == 1)){
        Rit_Dat = Lng_Wk2;
      }
      else{
        Vfo_Dat = Lng_Wk1;
        Rit_Dat = 0;
      }
      Vfo_Dat = constrain(Vfo_Dat,LW_VFO,HI_VFO);

      if(Flg_Spl == 1){
        Rit_Dat = constrain(Rit_Dat,(LW_VFO - Vfo_Dat),(HI_VFO - Vfo_Dat));
      }
      else{
        Rit_Dat = constrain(Rit_Dat,LW_RIT,HI_RIT);
      }
    }
  }
}

//----------  Function DDS set  ---------------

void Fnc_Dds(double frquency){
  unsigned long wrk = frquency * TWO_E32 / DDS_CLK;
 
  digitalWrite(FQ_UD,LOW);

  shiftOut(DATA,W_CLK,LSBFIRST,wrk);
  shiftOut(DATA,W_CLK,LSBFIRST,(wrk >> 8));
  shiftOut(DATA,W_CLK,LSBFIRST,(wrk >> 16));
  shiftOut(DATA,W_CLK,LSBFIRST,(wrk >> 24));
  shiftOut(DATA,W_CLK,LSBFIRST,DDS_CMD);   // AD9850 command

  digitalWrite(FQ_UD,HIGH);
}

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

void Fnc_Stp(){
  if(Enc_Stp == 10){                      // Step = 10Hz ?
    Enc_Stp = 100000;                     //   Yes,100khz set
    }
    else{
      Enc_Stp = Enc_Stp / 10;             // Step down 1 digit
      }
//  delay(250);
  Fnc_Step_Disp();
//  Fnc_Lcd();
  while(digitalRead(SW_STEP) == LOW)
    ;
  delay(250);
}

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

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

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

  do{
    *p++ = "0123456789"[u % 10];
    u = u / 10;
    i++;
    if((0 != u) && (0 == (i % 3)))
      *p++ = '.';
    }
  while( 0 != u );

  if ( n < 0 )
     *p++ = '-';
   *p = '\0';
   Fnc_Revr( str );
   return str;
}

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

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

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

//----------  Function Save EEPROM 2byte  ---------

void Fnc_Eep_Sav2(unsigned int value,int address){
  address += 1;
  for(int i = 0;i < 2;i++){
    byte toSave = value & 0xFF;
    if(EEPROM.read(address) != toSave){
      EEPROM.write(address,toSave);
      }
    value = value >> 8;
    address--;
  }
}

//----------  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 2byte  ---------

unsigned int  Fnc_Eep_Lod2(int address){
  unsigned int value = EEPROM.read(address);
  value = value << 8;
  return value | EEPROM.read(address + 1);
}

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

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

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

  if(Flg_Rit == 1){
    lcd.setCursor(5,1);
    lcd.print("R:          ");
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.setCursor(7,1);
    lcd.print(Lcd_Dat);
    if((Rit_Dat >= 1000) || (Rit_Dat <= -1000)){
      lcd.print("k");
    }
  }

  if(Flg_Spl == 1){
    lcd.setCursor(5,1);
    lcd.print("X:          ");
    Fnc_Dot_Edit(Lcd_Dat,Rit_Dat);
    lcd.setCursor(7,1);
    lcd.print(Lcd_Dat);
    if((Rit_Dat >= 1000) || (Rit_Dat <= -1000)){
      lcd.print("k");
    }
  }

  if((Flg_Rit == 0) && (Flg_Spl == 0)){
    Fnc_Dot_Edit(Lcd_Dat,Vfo_Dat - IF_FRQ);
    lcd.setCursor(1,0);
    lcd.print(":              ");
    lcd.setCursor(3,0);
    lcd.print(Lcd_Dat);
    lcd.print("MHz");

    lcd.setCursor(5,1);
    lcd.print("     JA2GQP");
  }
}
 

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

void Fnc_Rit(){
  if(Flg_Rit == 0){
    Rit_Dat = 0;
    Flg_Rit = 1;
    Flg_Spl = 0;
    switch(Byt_Chn){
      case 1:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep1);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep1);
        break;
      case 2:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep2);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep2);
        break;
      case 3:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep3);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep3);
        break;
      default:
        Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep0);
        Fnc_Eep_Sav4(Enc_Stp,Stp_Eep0);
        break;
    }
  }
  else{
    Flg_Rit = 0;
  }
  while(digitalRead(SW_RIT) == LOW)
    ;
  delay(250);
}
 
//----------  Function Channel SW Check  ---------

void Fnc_Chsw(){
  if(digitalRead(SW_CH1) == LOW){
    Byt_Chn = 1;
  }
  else if(digitalRead(SW_CH2) == LOW){
    Byt_Chn = 2;
  }
  else if(digitalRead(SW_CH3) == LOW){
    Byt_Chn = 3;
  }
  else{
    Byt_Chn = 0;
  }
}

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

void Fnc_Eep_Rd(){
  if(Fnc_Eep_Lod4(Frq_Eep0) <= LW_VFO){
    Vfo_Dat = DEF_VFO;
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep0);
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep1);
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep2);
    Fnc_Eep_Sav4(Vfo_Dat,Frq_Eep3);
  }
  else{
    switch(Byt_Chn){
      case 1:
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep1);
        break;
      case 2:
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep2);
        break;
      case 3:
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep3);
        break;
      default:
        Vfo_Dat = Fnc_Eep_Lod4(Frq_Eep0);
        break;
    }
  }
  if(Vfo_Dat <= 0){
    Vfo_Dat = DEF_VFO;
  }
  if(Fnc_Eep_Lod4(Stp_Eep0) <= 0){
    Enc_Stp = DEF_STP;
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep0);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep1);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep2);
    Fnc_Eep_Sav4(Enc_Stp,Stp_Eep3);
  }
  else{
    switch(Byt_Chn){
      case 1:
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep1);
        break;
      case 2:
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep2);
        break;
      case 3:
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep3);
        break;
      default:
        Enc_Stp = Fnc_Eep_Lod4(Stp_Eep0);
        break;
    }
  }
  if(Enc_Stp <= 0){
    Enc_Stp = DEF_STP;
  }
}

//----------  Function Split  ---------

void Fnc_Spl(){
  if(Flg_Spl == 0){
    Flg_Spl = 1;
    Flg_Rit = 0;
    Rit_Dat = 0;
  }
  else{
    Flg_Spl = 0;
  }
  while(digitalRead(SW_SPLIT) == LOW)
    ;
  delay(250);
}

2014年1月25日土曜日

Windows8.1 USB

今まで使っていたWindows Vistaが故障した為、Windows8.1を入手した。Atmelのプログラム開発に支障が無い様、Windows8.1の環境整備を行った。


Windows8.1

Microsoft User登録を行う為、ユーザ名を漢字入力すると、Userホルダーが漢字名となり、特に海外S/Wが上手く動かない事がある。この為、半角英語の登録名にする必要がある。
新規にユーザー登録するのであれば何ら問題ないが、登録済みの場合、ユーザ名変更または、他の解決を行えば良い。(内容が理解できないのであれば、再インストールが無難。)



Atmel Studio6.1


AVRISP MKⅡを使う事を前提とした。
Atmel Studio6.1 Update 2.0(build 2730)インストール後、AtmelUSBドライバーWindows8.1対応版をインストールで動作する。
Userホルダーに漢字(2Byte code)が使われている時、AVR書込みを行ったが、途中で止まった。HEXファイルをC:\に置いたら正常書込みが出来た。(Userに漢字を使うべきでない理由だ。)












Arduino IDE

AVRISP MKⅡを使う事を前提とした。
Arduino IDE1.0.5インストールのみで、問題なく動作(LED Blinkテスト)した。
更にArudino Ide for Atmel Studio 6.1をインストールし、Atmel Studio 6.1の統合環境でArudino開発可能となった。
















BASCOM AVR

AVRISP MKⅡを使う事を前提としたが、USBドライバAtmelUSBが上手く動作しない様だ。
他のドライバーを使えば、AVRISP MKⅡも正常に動作する事を確認出来たが、USBaspを使う事にした。
BASCOM AVR DEMO版をインストール。
USBaspをパソコンのUSBに付け、Zadigを実行し、libusb-win32タイプのドライバーをインストールする。AVRISP MKⅡでも、このドライバーで動作する。Atmel Studio6.1では、Zadigのlibusb-win32ドライバーでは動かなかったので、BASCOM AVRのみ、USBaspとした。
 























2014年1月8日水曜日

AD9834 DDS VFO Upper heterodyne

AD9834 DDS VFOの発振周波数を上側(アッパーヘテロダイン)のプログラム。
VFO frequency = IF frequency + Frequencyである。この変更に伴い、LPFのシュミレーションを行い定数を決めた。 









 
入出力インピーダンス50Ωの時のシュミレーション結果。
不整合で使った場合どの様な問題があるかを知るため、シュミレーション。
入力インピーダンス220Ω、出力インピーダンス50Ωの時のシュミレーション結果、4dBのリップルがある。問題ないレベルと考えるが気になるのであれば、入力側に変換トランスを入れれば良い。 







Program
KN-Q7A Likeを意識してプログラムが書いてあるが、キャリアポイントが正しいか検証手段が無いので判らない。また、最新のAD9850 Version1.1bを参考にすれば、機能追加も簡単な筈だ。

'********************************************************
'AD9834 DDS VFO program
'
'     7.000Mhz to 7.200Mhz Limitted!
'     (VFO frequency = IF frequency + Frequency)
'                                       2014/01/07
'                                           JA2GQP
' BASCOM AVR 2.0.7.5(DEMO version) Compiled
'--------------------------------------------------------
'  Function
'
'     1.Upper heterodyne
'     2.RIT operation(-10khz to +10khz)
'     3.STEP(10000,1000,100,10)
'     4.Memory operation is push RIT
'       (Frequency and Step)
'     5. Protection operation at the time of transmission
'********************************************************

$regfile = "m88adef.dat"
$crystal = 800000                                           '0.8Mhz clock

'--- config port ---
Config Portb = &B00000000                                   '0=TX,1-6=none
Config Portd = &B00001111                                   '0=FSYNC,1=SCLK,2=SDATA,3=none
                                                            '4=ENC B,5=ENC A,6=STEP,7=RIT
'--- port pullup ---
Portb = &B11111111                                          'All
Portd = &B11110000                                          'RIT,STEP,ENC A,ENC B

'--- debounce set ---
Config Debounce = 1

'---LCD port assign ---
Config Lcdpin = Pin , Db7 = Portc.0 , Db6 = Portc.1
Config Lcdpin = Pin , Db5 = Portc.2 , Db4 = Portc.3
Config Lcdpin = Pin , E = Portc.4 , Rs = Portc.5
Config Lcd = 16 * 2

'--- constant data ---
Const If_frq = 8468500                                      'IF frequency(LSB carrier point)
Const Lw_frq = 7000000                                      'Lower limit operation frequency
Const Hi_frq = 7200000                                      'Upper limit operation frequency
Const Def_frq = 7050000                                     'Operation frequency(initial)
Const Lw_vfo = If_frq + Lw_frq                              'VFO lower limit
Const Hi_vfo = If_frq + Hi_frq                              'VFO upper limit
Const Def_vfo = If_frq + Def_frq                            'VFO operation frequency(initial)
Const Lw_rit = -10000                                       'RIT lower limit
Const Hi_rit = 10000                                        'RIT upper limit
'Const Scal = 4.00000                                       '2^28/2^26  2^26(X'tal 67.108864Mhz)
Const Scal = 5.36870912                                     '2^28/50000000 (X'tal 50.000Mhz)

'--- define subrutine ---
Declare Sub Enc_sub                                         'Encorder
Declare Sub Dds_sub                                         'DDS
Declare Sub Lcd_sub                                         'LCD
Declare Sub Stp_sub                                         'STEP
Declare Sub Rit_sub                                         'RIT
Declare Sub Rx_sub                                          'RX
Declare Sub Tx_sub                                          'TX

'--- define memory ---
Dim Vfo_dat As Long                                         'VFO freqency data
Dim Dds_dat As Long                                         'DDS frequency data
Dim Str_frq As String * 10                                  'String frequency
Dim Dsp_frq As String * 10                                  'Display frequency
Dim Sng_wrk As Single                                       'main channel
Dim Lng_wk1 As Long                                         'Long work1
Dim Lng_wk2 As Long                                         'Long work2
Dim Wrd_wk1 As Word                                         'Word work1
Dim Wrd_wk2 As Word                                         'Word work2
Dim Wrd_wk3 As Word                                         'Word work3
Dim Enc_stp As Integer                                      'Encorder step
Dim Rit_dat As Integer                                      'RIT data
Dim Int_wrk As Integer                                      'Integer work
Dim Flg_rit As Byte                                         'RIT flag
Dim Flg_tx As Byte                                          'TX flag
Dim Frq_eep As Eram Long                                    'power off frequency A
Dim Stp_eep As Eram Integer                                 'EEP STEP data

'--------------
'Main roution
'--------------

Main:
   Flg_tx = 0
   Flg_rit = 0                                              'RIT flag

   If Frq_eep =< 0 Then                                     'EEP VFO data check
      Vfo_dat = Def_vfo                                     'Initialize VFO data
      Frq_eep = Vfo_dat
      Else
         Vfo_dat = Frq_eep                                  'Restore VFO data
         End If

   If Stp_eep =< 0 Then                                     'EEP STEP data check
      Enc_stp = 1000
      Stp_eep = Enc_stp                                     'Initialize STEP data
      Else
         Enc_stp = Stp_eep
         End If                                             'Restore STEP data

   Cursor Off
   Cls
   Call Lcd_sub                                             'LCD

   Do
      If Flg_tx = 0 Then
         Debounce Pind.5 , 0 , Enc_sub , Sub                'Encorder
         Debounce Pind.6 , 0 , Stp_sub , Sub                'Step
         Debounce Pind.7 , 0 , Rit_sub , Sub                'RIT
         End If

         Debounce Pinb.0 , 1 , Rx_sub , Sub                 'RX
         Debounce Pinb.0 , 0 , Tx_sub , Sub                 'TX

         If Flg_rit = 1 Then
            Dds_dat = Vfo_dat + Rit_dat
            Else
               Dds_dat = Vfo_dat
               End If

         If Flg_tx = 1 Then
            Dds_dat = Vfo_dat
            End If

         Call Dds_sub

   Loop
End

'-----------------------------
'Encoder check,Create DDS data
'-----------------------------

Sub Enc_sub
   Int_wrk = Enc_stp
   If Pind.4 = 1 Then                                       'Up
      Lng_wk1 = Vfo_dat + Int_wrk
      Lng_wk2 = Rit_dat + Enc_stp
      Else
         Lng_wk1 = Vfo_dat - Int_wrk                        'down
         Lng_wk2 = Rit_dat - Enc_stp
         End If


   If Flg_rit = 1 Then
      Rit_dat = Lng_wk2
      Else
         Vfo_dat = Lng_wk1
         Rit_dat = 0
         End If

   If Vfo_dat < Lw_vfo Then                                 'VFO lower limit check
      Vfo_dat = Lw_vfo
      End If

   If Vfo_dat > Hi_vfo Then                                 'VFO upper limit check
      Vfo_dat = Hi_vfo
      End If

   If Rit_dat < Lw_rit Then                                 'RIT lower limit check
      Rit_dat = Lw_rit
      End If

   If Rit_dat > Hi_rit Then                                 'RIT upper limit check
      Rit_dat = Hi_rit
      End If

   Call Lcd_sub
End Sub

'-----------------------------
'AD9834(DDS) Data write
'-----------------------------

Sub Dds_sub
   Sng_wrk = Dds_dat * Scal
   Lng_wk1 = Sng_wrk
   Wrd_wk1 = Lng_wk1 And &H3FFF
   Wrd_wk2 = Wrd_wk1 Or &H4000

   Shift Lng_wk1 , Right , 14
   Wrd_wk3 = Lng_wk1 Or &H4000

   Wrd_wk1 = &H2000

   Reset Portd.2
   Shiftout Portd.0 , Portd.1 , Wrd_wk1 , 0
   Shiftout Portd.0 , Portd.1 , Wrd_wk2 , 0
   Shiftout Portd.0 , Portd.1 , Wrd_wk3 , 0
   Set Portd.2
End Sub

'-----------------------------
'LCD Data write
'-----------------------------

Sub Lcd_sub
   Cls
   Locate 1 , 1
   Lng_wk1 = If_frq
   Lng_wk1 = Vfo_dat - If_frq
   Str_frq = Str(lng_wk1)
   Str_frq = Format(str_frq , "00.000000")
   Dsp_frq = Left(str_frq , 3) + Mid(str_frq , 4 , 3) + "." + Mid(str_frq , 7 , 3)
   Lcd "F:" ; Dsp_frq ; "MHz"
   Locate 2 , 1
   Lcd "S:    "
   Locate 2 , 3

   If Enc_stp < 1000 Then
      Lcd Enc_stp
      Elseif Enc_stp = 10000 Then
         Lcd "10k  "
         Else
            Lcd "1k   "
            End If

   If Flg_rit = 1 Then
      Locate 2 , 8
      Lcd "R:"
      Str_frq = Str(rit_dat)
      Str_frq = Format(str_frq , "00.000")
      Locate 2 , 10
      Lcd Str_frq
      Else
         Locate 2 , 8
         Lcd "   JA2GQP"
         End If
End Sub

'-----------------------------
'Step
'-----------------------------

Sub Stp_sub
   Select Case Enc_stp
      Case 10000:
         Enc_stp = 1000                                     '1000
      Case 1000:
         Enc_stp = 100                                      '100
      Case 100:
         Enc_stp = 10                                       '10
      Case 10:
         Enc_stp = 10000                                    '10000
      Case Else:
         Enc_stp = 1000                                     '1000(initial)
   End Select

   Call Lcd_sub
End Sub

'-----------------------------
'RIT
'-----------------------------

Sub Rit_sub
   If Flg_rit = 0 Then
      Rit_dat = 0
      Flg_rit = 1
      Frq_eep = Vfo_dat                                     'Save VFO data
      Stp_eep = Enc_stp                                     'Save STEP data
      Else
         Flg_rit = 0
         End If
   Call Lcd_sub
End Sub

'-----------------------------
'RX
'-----------------------------

Sub Rx_sub
   If Flg_tx = 1 Then
      Flg_tx = 0                                            'TX flag rest
      Locate 1 , 1
      Lcd "F"
      End If
End Sub

'-----------------------------
'TX
'-----------------------------

Sub Tx_sub
   If Flg_tx = 0 Then
      Flg_tx = 1                                            'TX flag set
      Locate 1 , 1
      Lcd "T"
      End If
End Sub   

2013年12月6日金曜日

SDR HF Converter case

SDR Converterを以前ハムフェアーで入手したケースに収納した。ケース(外形寸 37x92x30)を先に決めたわけでないが、上手く収める事ができた。写真で判別不明だが、PCBの下にレギュレータ7805がある。SDRに使う場合、特にシールド特性の良い事が望まれるが、このケースはCATV?で使われていた物の様だ。PCB剥き出しで使われている方もみえるので参考になれば、と思う。
















前面                                   背面

2013年12月1日日曜日

SDR Upverter(HF Converter)

R820TドングルでHF帯受信する為のUpverter(HF コンバータ)である。回路方式は色々なサイトで紹介されているが 、KF7LZE's Blogに整理されている。 http://blog.kf7lze.net/tag/rtl2832u/
今回、DBMと50MHzオシレターを使って製作した。また、オシレターからの輻射を低減すべく、受信範囲を0-25MHzとした。   



 LPFのシュミレーションをAADE Filter Design V4.5で行った。コイルはT37-6 12tでのインダクタンス値で、50MHzで-50dbm以上の減衰が得られる様、コンデンサーを決めた。結果、Fc=25MHz、減衰量 -57dbm(at 50MHz)である。 


回路図である。DBMはTUF-1を使ったが、秋月電子販売のTUF-2で問題ない。 


PCBサイズ 31 x 53












参考
 SDR受信ソフトのインストールは、多くのHPに紹介されているが、ここを参考にした。
 http://www.icom.co.jp/beacon/talk/001518.html

2013年11月8日金曜日

AD9850 DDS VFO Premixed Version 1.1b


AD9850 DDS VFO Premixed版にスプリット機能を追加した。これで一通りの機能が揃った事になる。本来ならば、全ての機能を織り込んで、Version 1.0とすべきだが、他との識別の為、Version 1.1bとした。スプリット操作は、split SWを押し、Xと表示が出たら、ロータリーエンコーダで値をセットするのみである。他のVFOをセットする必要もない。簡単にSPLIT運用ができる。


回路図である。SPLITスイッチを追加した以外、Ver1.1aと同じ。
 
Program

SPLIT機能は、RIT機能のサブルーチンを使ってメモリー消費をおさえた。SPLITとRITは排他的な関係で、直感的なオペレーションが出来るが、RIT制限範囲 = SPLIT制限範囲である。
最大STEP値が、100kと50kを選択出来るよう、条件付コンパイルプログラムとした。STEP 100kにする時Step_100k=1。また、STEP 50kにする時、Step_100k=0と書き換えれば良い。(下記プログラムは、STEP 50k)

'********************************************************
'AD9850 DDS VFO Premixed type program ver.1.1b
'
'  Copyright (C)2013.JA2GQP.All rights reserved.
'
'     7.000Mhz to 7.200Mhz Limitted!
'     (Target frequency = IF frequency + frequency)
'                                       2013/11/07
'                                           JA2GQP
' BASCOM AVR 2.0.7.5(DEMO version) Compiled
'--------------------------------------------------------
'  Function
'
'     1.Upper heterodyne
'     2.RIT operation(-50khz to +50khz)
'     3.STEP(100k,10k,1k,100,10)
'     4.Memory operation is push RIT
'       (Frequency and Step)
'     5.Protection operation at the time of transmission
'     6.Channel memory main channel(ch0) + 2 chanenl(ch1,ch2)
'     7.Sprit operation(-50khz to +50khz)
'********************************************************
$regfile = "m88adef.dat"
$crystal = 800000                       '0.8Mhz clock
'--- config port ---
Config Portb = &B11000000               '0=TX,1=none,2=STEP,3=RIT
                                         '4=ENC A,5=ENC B,6-7=LCD
Config Portc = &B00000111               '0=DATA,1=FU_UD,2=W_CLK,3-5=ch_SW
'--- port pullup ---
Portb = &B00111111                      'ENC B,ENC A,RIT,STEP,none,TX
Portc = &B00111000                      'Bit 3-5 pull up
'--- debounce set ---
Config Debounce = 1
'---LCD port assign ---
Config Lcdpin = Pin , Db7 = Portd.6 , Db6 = Portd.5
Config Lcdpin = Pin , Db5 = Portb.7 , Db4 = Portb.6
Config Lcdpin = Pin , E = Portd.2 , Rs = Portd.0
Config Lcd = 16 * 2
'---Max STEP select ---
Const Step_100k = 0                     'STEP 100k=1,50k=0
'--- constant data ---
Const If_frq = 9996500                  'IF frequency
Const Lw_frq = 7000000                  'Lower limit operation frequency
Const Hi_frq = 7200000                  'Upper limit operation frequency
Const Def_frq = 7050000                 'Operation frequency(initial)
Const Lw_vfo = If_frq + Lw_frq          'VFO lower limit
Const Hi_vfo = If_frq + Hi_frq          'VFO upper limit
Const Def_vfo = If_frq + Def_frq        'VFO operation frequency(initial)
Const Lw_rit = -50000                   'RIT lower limit
Const Hi_rit = 50000                    'RIT upper limit
Const Scal = 34.35973837                '2^32/125.000Mhz
Const Dds_cmd = &B00000000              'DDS command
'--- define subrutine ---
Declare Sub Enc_sub                     'Encorder
Declare Sub Dds_sub                     'DDS
Declare Sub Lcd_sub                     'LCD
Declare Sub Stp_sub                     'STEP
Declare Sub Rit_sub                     'RIT
Declare Sub Rx_sub                      'RX
Declare Sub Tx_sub                      'TX
Declare Sub Chsw_sub                    'Channel SW check
Declare Sub Eep_rd_sub                  'EEP read
Declare Sub Spl_sub                     'SPLIT
'--- define memory ---
Dim Vfo_dat As Long                     'VFO freqency data
Dim Dds_dat As Long                     'DDS frequency data
Dim Str_frq As String * 10              'String frequency
Dim Dsp_frq As String * 10              'Display frequency
Dim Sng_wrk As Single                   'main channel
Dim Lng_wk1 As Long                     'Long work1
Dim Lng_wk2 As Long                     'Long work2
Dim Wrd_wk1 As Word                     'Word work1
Dim Wrd_wk2 As Word                     'Word work2
Dim Wrd_wk3 As Word                     'Word work3
Dim Enc_stp As Long                     'Encorder step
Dim Rit_dat As Long                     'RIT data
Dim Rit_datb As Long                    'RIT data old
Dim Int_wrk As Integer                  'Integer work
Dim Flg_rit As Byte                     'RIT flag
Dim Flg_ritb As Byte                    'RIT flag old
Dim Flg_tx As Byte                      'TX flag
Dim Flg_spl As Byte                     'SPLIT flag
Dim Frq_eep0 As Eram Long               'EEP frequency ch0
Dim Frq_eep1 As Eram Long               '              ch1
Dim Frq_eep2 As Eram Long               '              ch2
Dim Stp_eep0 As Eram Long               'EEP STEP ch0
Dim Stp_eep1 As Eram Long               '         ch1
Dim Stp_eep2 As Eram Long               '         ch2
Dim Flg_enc As Byte                     'Encorder dir flag
Dim Byt_cmd As Byte                     'DDS command
Dim Byt_wrk As Byte                     'Byte work
Dim Byt_chn As Byte                     'Channel
'--------------
'Main roution
'--------------
Main:
   Flg_tx = 0
   Flg_rit = 0                          'RIT flag
   Flg_spl = 0
   Cursor Off
   Cls
   Call Chsw_sub                        'Channel SW check
   Byt_wrk = Byt_chn
   Call Eep_rd_sub                      'EEP initial
   Do
      If Flg_tx = 0 Then
         Debounce Pinb.4 , 0 , Enc_sub , Sub       'Encorder
         Debounce Pinb.2 , 0 , Stp_sub , Sub       'Step
         Debounce Pinb.3 , 0 , Rit_sub , Sub       'RIT
         Debounce Pinb.1 , 0 , Spl_sub , Sub       'SPLIT
         Call Chsw_sub                  'Channel SW check
         If Byt_wrk <> Byt_chn Then
            If Byt_wrk = 0 Then
               Frq_eep0 = Vfo_dat       'Save VFO0 data
               Stp_eep0 = Enc_stp       'Save STEP0 data
               Flg_ritb = Flg_rit       'Save RIT flag
               Rit_datb = Rit_dat       'Save RIT data
               Flg_rit = 0
               Flg_spl = 0
               Rit_dat = 0
               End If
               If Byt_wrk <> 0 Then
                  Flg_rit = 0
                  Flg_spl = 0
                  If Byt_chn = 0 Then
                     If Flg_ritb = 1 Then
                        Flg_rit = 1
                        Rit_dat = Rit_datb
                        End If
                     End If
                  End If
               Byt_wrk = Byt_chn
               Call Eep_rd_sub          'EEP load
               End If
            End If
         Debounce Pinb.0 , 1 , Rx_sub , Sub       'RX
         Debounce Pinb.0 , 0 , Tx_sub , Sub       'TX
         If Flg_rit = 1 Then
            Dds_dat = Vfo_dat + Rit_dat
            Else
               Dds_dat = Vfo_dat
               End If
         If Flg_tx = 1 Then
            If Flg_spl = 1 Then
               Dds_dat = Vfo_dat + Rit_dat
               Else
                  Dds_dat = Vfo_dat
                  End If
               End If
         Call Dds_sub
   Loop
End

'-----------------------------
'Encoder check,Create DDS data
'-----------------------------
Sub Enc_sub
   If Pinb.5 = 1 Then
      Flg_enc = 0                       'Up
      Else
         Flg_enc = 1                    'down
         End If
   If Flg_enc = 0 Then
      Lng_wk1 = Vfo_dat + Enc_stp       'Up
      Lng_wk2 = Rit_dat + Enc_stp
      Else
         Lng_wk1 = Vfo_dat - Enc_stp    'down
         Lng_wk2 = Rit_dat - Enc_stp
         End If
   If Flg_rit = 1 Or Flg_spl = 1 Then
      Rit_dat = Lng_wk2
      Else
         Vfo_dat = Lng_wk1
         Rit_dat = 0
         End If
   If Vfo_dat < Lw_vfo Then             'VFO lower limit check
      Vfo_dat = Lw_vfo
      End If
   If Vfo_dat > Hi_vfo Then             'VFO upper limit check
      Vfo_dat = Hi_vfo
      End If
   If Rit_dat < Lw_rit Then             'RIT lower limit check
      Rit_dat = Lw_rit
      End If
   If Rit_dat > Hi_rit Then             'RIT upper limit check
      Rit_dat = Hi_rit
      End If
   Call Lcd_sub
End Sub
'-----------------------------
'AD9850(DDS) Data write
'-----------------------------
Sub Dds_sub
   Sng_wrk = Dds_dat * Scal
   Lng_wk1 = Sng_wrk
   Byt_cmd = Dds_cmd                    'DDS command
   Reset Portc.1
   Shiftout Portc.0 , Portc.2 , Lng_wk1 , 3
   Shiftout Portc.0 , Portc.2 , Byt_cmd , 3
   Set Portc.1
End Sub
'-----------------------------
'LCD Data write
'-----------------------------
Sub Lcd_sub
   Locate 1 , 1
   Lng_wk1 = Vfo_dat - If_frq
   Str_frq = Str(lng_wk1)
   Str_frq = Format(str_frq , "00.000000")
   Dsp_frq = Left(str_frq , 3) + Mid(str_frq , 4 , 3) + "." + Mid(str_frq , 7 , 3)
   Lcd Byt_chn ; ":" ; Dsp_frq ; "Mhz"
   Locate 2 , 1
   Lcd "S:     "
   Locate 2 , 3
   If Enc_stp < 1000 Then
      Lcd Enc_stp
#if Step_100k = 1
      Elseif Enc_stp = 100000 Then
         Lcd "100k "
#else
      Elseif Enc_stp = 50000 Then
         Lcd "50k  "
#endif
         Elseif Enc_stp = 10000 Then
            Lcd "10k  "
            Else
               Lcd "1k   "
               End If
   Locate 2 , 8
   If Flg_rit = 1 Then
      Lcd "R:       "
      End If
   If Flg_spl = 1 Then
      Lcd "X:       "
      End If
   Str_frq = Str(rit_dat)
   Str_frq = Format(str_frq , "00.000")
   Locate 2 , 10
   Lcd Str_frq
   If Flg_rit = 0 And Flg_spl = 0 Then
      Locate 2 , 8
      Lcd "   JA2GQP"
      End If
End Sub
'-----------------------------
'Step
'-----------------------------
Sub Stp_sub
   Select Case Enc_stp
#if Step_100k = 1
      Case 100000:
         Enc_stp = 10000                '10000
#else
      Case 50000:
         Enc_stp = 10000                '10000
#endif
      Case 10000:
         Enc_stp = 1000                 '1000
      Case 1000:
         Enc_stp = 100                  '100
      Case 100:
         Enc_stp = 10                   '10
      Case 10:
#if Step_100k = 1
         Enc_stp = 100000               '100000
#else
         Enc_stp = 50000                '50000
#endif
      Case Else:
         Enc_stp = 1000                 '1000(initial)
   End Select
   Call Lcd_sub
End Sub
'-----------------------------
'RIT
'-----------------------------
Sub Rit_sub
   If Flg_rit = 0 Then
      Rit_dat = 0
      Flg_rit = 1
      Flg_spl = 0
      Select Case Byt_chn
         Case 1:
            Frq_eep1 = Vfo_dat          'Save VFO1 data
            Stp_eep1 = Enc_stp          'Save STEP1 data
         Case 2:
            Frq_eep2 = Vfo_dat          'Save VFO2 data
            Stp_eep2 = Enc_stp          'Save STEP2 data
         Case Else:
            Frq_eep0 = Vfo_dat          'Save VFO0 data
            Stp_eep0 = Enc_stp          'Save STEP0 data
            End Select
      Else
         Flg_rit = 0
         End If
   Call Lcd_sub
End Sub
'-----------------------------
'RX
'-----------------------------
Sub Rx_sub
   If Flg_tx = 1 Then
      Flg_tx = 0                        'TX flag rest
      Locate 1 , 1
      Lcd Byt_chn
      End If
End Sub
'-----------------------------
'TX
'-----------------------------
Sub Tx_sub
   If Flg_tx = 0 Then
      Flg_tx = 1                        'TX flag set
      Locate 1 , 1
      Lcd "T"
      End If
End Sub
'-----------------------------
'Channel SW check
'-----------------------------
Sub Chsw_sub
   If Pinc.3 = 0 Then
      Byt_chn = 1
      Elseif Pinc.4 = 0 Then
         Byt_chn = 2
            Else
               Byt_chn = 0
               End If
   Locate 1 , 1
   Lcd Byt_chn
End Sub
'-----------------------------
'EEP set
'-----------------------------
Sub Eep_rd_sub
   If Frq_eep0 =< 0 Then                'EEP VFO data check
      Vfo_dat = Def_vfo                 'Initialize VFO data
      Frq_eep0 = Vfo_dat
      Frq_eep1 = Vfo_dat
      Frq_eep2 = Vfo_dat
      Else                              'Restore VFO data
        Select Case Byt_chn
            Case 1:
               Vfo_dat = Frq_eep1
            Case 2:
               Vfo_dat = Frq_eep2
            Case Else:
               Vfo_dat = Frq_eep0
               End Select
            End If
   If Stp_eep0 =< 0 Then                'EEP STEP data check
      Enc_stp = 1000
      Stp_eep0 = Enc_stp                'Initialize STEP data
      Stp_eep1 = Enc_stp
      Stp_eep2 = Enc_stp
      Else                              'Restore STEP data
        Select Case Byt_chn
            Case 1:
               Enc_stp = Stp_eep1
            Case 2:
               Enc_stp = Stp_eep2
            Case Else:
               Enc_stp = Stp_eep0
               End Select
            End If
   Call Lcd_sub
End Sub
'-----------------------------
'SPLIT
'-----------------------------
Sub Spl_sub
   If Flg_spl = 0 Then
      Flg_spl = 1
      Flg_rit = 0
      Rit_dat = 0
      Else
         Flg_spl = 0
         End If
   Call Lcd_sub
End Sub

  

2013年11月6日水曜日

AD9850 DDS VFO Premixed Version 1.1a

AD9850 DDS VFOのプリミックス用として9/6に公開したものの、Version UPである。10/27公開したProgramは、受信部にシングルスーパーを使うことを前提にしたものである。今回のVersionは、10/27版より機能が低い。変更内容は、STEP 100k追加とメモリーチャンネル2ch追加である。メモリーチャンネル多チャンネル追加を狙ったが、BASCOM DEMO版(4kb)の制限で、2chが限度であった。2chのメモリーでも、無いより使い勝手向上する筈だ。メインチャンネル(ch0)のみ、他のチャンネル(ch1,ch2)に移ってもRITを保持する事など、10/27版と同じ仕様。Software識別のため、Ver1.1a。


 
Program
 
'********************************************************
'AD9850 DDS VFO Premixed type program ver.1.1a
'
'  Copyright (C)2013.JA2GQP.All rights reserved.
'
'     7.000Mhz to 7.200Mhz Limitted!
'     (Target frequency = IF frequency + frequency)
'                                       2013/11/05
'                                           JA2GQP
' BASCOM AVR 2.0.7.5(DEMO version) Compiled
'--------------------------------------------------------
'  Function
'
'     1.Upper heterodyne
'     2.RIT operation(-10khz to +10khz)
'     3.STEP(100k,10k,1k,100,10)
'     4.Memory operation is push RIT
'       (Frequency and Step)
'     5.Protection operation at the time of transmission
'     6.Channel memory main channel(ch0) + 2 chanenl(ch1,ch2)
'********************************************************
$regfile = "m88adef.dat"
$crystal = 800000                       '0.8Mhz clock
'--- config port ---
Config Portb = &B11000000               '0=TX,1=none,2=STEP,3=RIT
                                         '4=ENC A,5=ENC B,6-7=LCD
Config Portc = &B00000111               '0=DATA,1=FU_UD,2=W_CLK,3-5=ch_SW
'--- port pullup ---
Portb = &B00111111                      'ENC B,ENC A,RIT,STEP,none,TX
Portc = &B00111000                      'Bit 3-5 pull up
'--- debounce set ---
Config Debounce = 1
'---LCD port assign ---
Config Lcdpin = Pin , Db7 = Portd.6 , Db6 = Portd.5
Config Lcdpin = Pin , Db5 = Portb.7 , Db4 = Portb.6
Config Lcdpin = Pin , E = Portd.2 , Rs = Portd.0
Config Lcd = 16 * 2
'--- constant data ---
Const If_frq = 9996500                  'IF frequency
Const Lw_frq = 7000000                  'Lower limit operation frequency
Const Hi_frq = 7200000                  'Upper limit operation frequency
Const Def_frq = 7050000                 'Operation frequency(initial)
Const Lw_vfo = If_frq + Lw_frq          'VFO lower limit
Const Hi_vfo = If_frq + Hi_frq          'VFO upper limit
Const Def_vfo = If_frq + Def_frq        'VFO operation frequency(initial)
Const Lw_rit = -10000                   'RIT lower limit(Min -99999)
Const Hi_rit = 10000                    'RIT upper limit(Max 99999)
Const Scal = 34.35973837                '2^32/125.000Mhz
Const Dds_cmd = &B00000000              'DDS command
'--- define subrutine ---
Declare Sub Enc_sub                     'Encorder
Declare Sub Dds_sub                     'DDS
Declare Sub Lcd_sub                     'LCD
Declare Sub Stp_sub                     'STEP
Declare Sub Rit_sub                     'RIT
Declare Sub Rx_sub                      'RX
Declare Sub Tx_sub                      'TX
Declare Sub Chsw_sub                    'Channel SW check
Declare Sub Eep_rd_sub                  'EEP read
'--- define memory ---
Dim Vfo_dat As Long                     'VFO freqency data
Dim Dds_dat As Long                     'DDS frequency data
Dim Str_frq As String * 10              'String frequency
Dim Dsp_frq As String * 10              'Display frequency
Dim Sng_wrk As Single                   'main channel
Dim Lng_wk1 As Long                     'Long work1
Dim Lng_wk2 As Long                     'Long work2
Dim Wrd_wk1 As Word                     'Word work1
Dim Wrd_wk2 As Word                     'Word work2
Dim Wrd_wk3 As Word                     'Word work3
Dim Enc_stp As Long                     'Encorder step
Dim Rit_dat As Long                     'RIT data
Dim Rit_datb As Long                    'RIT data old
Dim Int_wrk As Integer                  'Integer work
Dim Flg_rit As Byte                     'RIT flag
Dim Flg_ritb As Byte                    'RIT flag old
Dim Flg_tx As Byte                      'TX flag
Dim Frq_eep0 As Eram Long               'EEP frequency ch0
Dim Frq_eep1 As Eram Long               '              ch1
Dim Frq_eep2 As Eram Long               '              ch2
Dim Stp_eep0 As Eram Long               'EEP STEP ch0
Dim Stp_eep1 As Eram Long               '         ch1
Dim Stp_eep2 As Eram Long               '         ch2
Dim Flg_enc As Byte                     'Encorder dir flag
Dim Byt_cmd As Byte                     'DDS command
Dim Byt_wrk As Byte                     'Byte work
Dim Byt_chn As Byte                     'Channel
'--------------
'Main roution
'--------------
Main:
   Flg_tx = 0
   Flg_rit = 0                          'RIT flag
   Cursor Off
   Cls
   Call Chsw_sub                        'Channel SW check
   Byt_wrk = Byt_chn
   Call Eep_rd_sub                      'EEP initial
   Do
      If Flg_tx = 0 Then
         Debounce Pinb.4 , 0 , Enc_sub , Sub       'Encorder
         Debounce Pinb.2 , 0 , Stp_sub , Sub       'Step
         Debounce Pinb.3 , 0 , Rit_sub , Sub       'RIT
         Call Chsw_sub                  'Channel SW check
         If Byt_wrk <> Byt_chn Then
            If Byt_wrk = 0 Then
               Frq_eep0 = Vfo_dat       'Save VFO0 data
               Stp_eep0 = Enc_stp       'Save STEP0 data
               Flg_ritb = Flg_rit       'Save RIT flag
               Rit_datb = Rit_dat       'Save RIT data
               Flg_rit = 0
               Rit_dat = 0
               End If
               If Byt_wrk <> 0 Then
                  Flg_rit = 0
                  If Byt_chn = 0 Then
                     If Flg_ritb = 1 Then
                        Flg_rit = 1
                        Rit_dat = Rit_datb
                        End If
                     End If
                  End If
               Byt_wrk = Byt_chn
               Call Eep_rd_sub          'EEP load
               End If
            End If
         Debounce Pinb.0 , 1 , Rx_sub , Sub       'RX
         Debounce Pinb.0 , 0 , Tx_sub , Sub       'TX
         If Flg_rit = 1 Then
            Dds_dat = Vfo_dat + Rit_dat
            Else
               Dds_dat = Vfo_dat
               End If
         If Flg_tx = 1 Then
            Dds_dat = Vfo_dat
            End If
         Call Dds_sub
   Loop
End

'-----------------------------
'Encoder check,Create DDS data
'-----------------------------
Sub Enc_sub
   If Pinb.5 = 1 Then
      Flg_enc = 0                       'Up
      Else
         Flg_enc = 1                    'down
         End If
   If Flg_enc = 0 Then
      Lng_wk1 = Vfo_dat + Enc_stp       'Up
      Lng_wk2 = Rit_dat + Enc_stp
      Else
         Lng_wk1 = Vfo_dat - Enc_stp    'down
         Lng_wk2 = Rit_dat - Enc_stp
         End If
   If Flg_rit = 1 Then
         Rit_dat = Lng_wk2
      Else
         Vfo_dat = Lng_wk1
         Rit_dat = 0
         End If
   If Vfo_dat < Lw_vfo Then             'VFO lower limit check
      Vfo_dat = Lw_vfo
      End If
   If Vfo_dat > Hi_vfo Then             'VFO upper limit check
      Vfo_dat = Hi_vfo
      End If
   If Rit_dat < Lw_rit Then             'RIT lower limit check
      Rit_dat = Lw_rit
      End If
   If Rit_dat > Hi_rit Then             'RIT upper limit check
      Rit_dat = Hi_rit
      End If
   Call Lcd_sub
End Sub
'-----------------------------
'AD9850(DDS) Data write
'-----------------------------
Sub Dds_sub
   Sng_wrk = Dds_dat * Scal
   Lng_wk1 = Sng_wrk
   Byt_cmd = Dds_cmd                    'DDS command
   Reset Portc.1
   Shiftout Portc.0 , Portc.2 , Lng_wk1 , 3
   Shiftout Portc.0 , Portc.2 , Byt_cmd , 3
   Set Portc.1
End Sub
'-----------------------------
'LCD Data write
'-----------------------------
Sub Lcd_sub
   Locate 1 , 1
   Lng_wk1 = Vfo_dat - If_frq
   Str_frq = Str(lng_wk1)
   Str_frq = Format(str_frq , "00.000000")
   Dsp_frq = Left(str_frq , 3) + Mid(str_frq , 4 , 3) + "." + Mid(str_frq , 7 , 3)
   Lcd Byt_chn ; ":" ; Dsp_frq ; "Mhz"
   Locate 2 , 1
   Lcd "S:     "
   Locate 2 , 3
   If Enc_stp =< 0 Then
      Enc_stp = 1000
      End If
   If Enc_stp => 1000 Then              'Unit Conversion
      Lng_wk2 = Enc_stp / 1000          'kilo
      Lcd Lng_wk2 ; "k"
      Else
         Lcd Enc_stp
         End If
   If Flg_rit = 1 Then
      Locate 2 , 8
      Lcd "R:       "
      Str_frq = Str(rit_dat)
      Str_frq = Format(str_frq , "00.000")
      Locate 2 , 10
      Lcd Str_frq
      Else
         Locate 2 , 8
         Lcd "   JA2GQP"
         End If
End Sub
'-----------------------------
'Step
'-----------------------------
Sub Stp_sub
   Select Case Enc_stp
      Case 100000:
         Enc_stp = 10000                '10000
      Case 10000:
         Enc_stp = 1000                 '1000
      Case 1000:
         Enc_stp = 100                  '100
      Case 100:
         Enc_stp = 10                   '10
      Case 10:
         Enc_stp = 100000               '100000
      Case Else:
         Enc_stp = 1000                 '1000(initial)
   End Select
   Call Lcd_sub
End Sub
'-----------------------------
'RIT
'-----------------------------
Sub Rit_sub
   If Flg_rit = 0 Then
      Rit_dat = 0
      Flg_rit = 1
      Select Case Byt_chn
         Case 1:
            Frq_eep1 = Vfo_dat          'Save VFO1 data
            Stp_eep1 = Enc_stp          'Save STEP1 data
         Case 2:
            Frq_eep2 = Vfo_dat          'Save VFO2 data
            Stp_eep2 = Enc_stp          'Save STEP2 data
         Case Else:
            Frq_eep0 = Vfo_dat          'Save VFO0 data
            Stp_eep0 = Enc_stp          'Save STEP0 data
            End Select
      Else
         Flg_rit = 0
         End If
   Call Lcd_sub
End Sub
'-----------------------------
'RX
'-----------------------------
Sub Rx_sub
   If Flg_tx = 1 Then
      Flg_tx = 0                        'TX flag rest
      Locate 1 , 1
      Lcd Byt_chn
      End If
End Sub
'-----------------------------
'TX
'-----------------------------
Sub Tx_sub
   If Flg_tx = 0 Then
      Flg_tx = 1                        'TX flag set
      Locate 1 , 1
      Lcd "T"
      End If
End Sub
'-----------------------------
'Channel SW check
'-----------------------------
Sub Chsw_sub
   If Pinc.3 = 0 Then
      Byt_chn = 1
      Elseif Pinc.4 = 0 Then
         Byt_chn = 2
            Else
               Byt_chn = 0
               End If
   Locate 1 , 1
   Lcd Byt_chn
End Sub
'-----------------------------
'EEP set
'-----------------------------
Sub Eep_rd_sub
   If Frq_eep0 =< 0 Then                'EEP VFO data check
      Vfo_dat = Def_vfo                 'Initialize VFO data
      Frq_eep0 = Vfo_dat
      Frq_eep1 = Vfo_dat
      Frq_eep2 = Vfo_dat
      Else                              'Restore VFO data
        Select Case Byt_chn
            Case 1:
               Vfo_dat = Frq_eep1
            Case 2:
               Vfo_dat = Frq_eep2
            Case Else:
               Vfo_dat = Frq_eep0
               End Select
            End If
   If Stp_eep0 =< 0 Then                'EEP STEP data check
      Enc_stp = 1000
      Stp_eep0 = Enc_stp                'Initialize STEP data
      Stp_eep1 = Enc_stp
      Stp_eep2 = Enc_stp
      Else                              'Restore STEP data
        Select Case Byt_chn
            Case 1:
               Enc_stp = Stp_eep1
            Case 2:
               Enc_stp = Stp_eep2
            Case Else:
               Enc_stp = Stp_eep0
               End Select
            End If
   Call Lcd_sub
End Sub