2022年7月24日日曜日

TS-830トランシーバー DDS VFO

 

TS-830無線機 DDS VFO
TS-830は水晶発振10MHz基準に各周波数をPLL制御で構成されています。ただし、VFOがアナログ発振(バリコン可変)なので周波数が時間とともにズレます。


以前作ったことがあるDDS VFOが使えないか調べたら詳しい内容の記事がありました【http://jf1vru.web.fc2.com/vfo/ddsvfo7.html
使い慣れたArduino NanoとAD9850使いDDS出力をアンプしLPFを通しDDS_VFO出力します(オシロスコープで出力を内部VFOと同じ出力にVR調整)
パネルVFOスイッチによりMvfoSW信号がリレーをOFF/ON、リレーOFFで+9VがVFO切替信号に接続(内部VFO)、リレーONでDDS_VFO出力が本体に接続(外部VFO)。
DDS VFOは長い時間ワッチしても周波数ズレが気にならないレベルになりました。


現在TS-830は受信専用機として使用しています。エンコーダは30年前購入したネミコン製MKE-500-2(現在は製造中止?)
回路図


プログラム
#include <Rotary.h>            //  https://github.com/brianlow/Rotary 
#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#include <EF_AD9850.h>
// EF_AD9850(CLK,FQ_UP,RESET,DATA)
EF_AD9850 AD9850(9, 10, 11, 8);
//アドレス0x27 16文字2行の液晶
LiquidCrystal_I2C lcd(0x27, 16, 2);
Rotary r = Rotary(2, 3);              // Rotary encoder for frequency connects to interrupt pins

#define MvfoSW A0
#define RitSW A1
#define StepSW A2   
#define HoldSW A3
int CwMode = 4; 
int TxMode = 5; 
int Relay = 6;
//long unsigned int freq = 1000;         // Set initial frequency.
long freq = 5500000;   //VFO 5.5 - 6 MHZ
//long unsigned int freqOld = freq;
long freqOld = freq;
char disp_buf[16];
char disp_buf2[16];
long stepf = 100;   //1Hz 10Hz 100Hz
long  ritf = 0;
long  ritfOld = 0;
int  cw = 0 ;       //cw ssb
int  tx = 0 ;       //send
int  rl = 0 ;       //relay
int  wr = 0 ;       //ad9850 write
int  offset = 1 ;   //dds_frequency offset

void updateDisplay() {      
  if (freq < 1000) {
    sprintf(disp_buf, "%10ld", freq);
  }
  else if (freq < 1000000) {
    int freqL = freq % 1000;
    int freqM = freq / 1000;
    sprintf(disp_buf, "%6d,%03d", freqM, freqL);
  }
  else {
    int freqL = freq  % 1000;
    int freqM = (freq / 1000) % 1000;
    int freqH = freq / 1000000;
    sprintf(disp_buf, "%2d,%03d,%03d", freqH, freqM, freqL);
  }  
  lcd.setCursor(3, 1);
  lcd.print(disp_buf);
  lcd.print("Hz");  
}
                                         //encoder interrupt
ISR(PCINT2_vect) {                       //rx holdsw_off                                        
  if (digitalRead(HoldSW) == HIGH && digitalRead(TxMode) == HIGH){ 
  if (digitalRead(RitSW) == HIGH ){      //rit off
  unsigned char result = r.process();
  if (result) {
    if (result == DIR_CW) {
      if ((freq + stepf) <= 6000000) freq += stepf;
    } else {
      if ((freq - stepf) >= 5500000) freq -= stepf;
    }
    if (freq <= 1)  freq = 1;
    if (freq >= 6000000) freq = 6000000;
  }
 }
  if (digitalRead(RitSW) == LOW ){        //rit on
   unsigned char result = r.process();
  if (result) {
    if (result == DIR_CW) {
      if ((ritf + stepf) <= 10000) ritf += stepf;
    } else {
      if ((ritf - stepf) >= -10000) ritf -= stepf;
    }    
    if (ritf >= 10000) ritf = 10000;
    if (ritf <= -10000) ritf = -10000;
  } 
  }
}
}

void setup() {
  pinMode(2, INPUT);     // Pins for interrupt-driven rotary encoder and push buttons
  pinMode(3, INPUT);  
  pinMode(MvfoSW, INPUT_PULLUP); 
  pinMode(RitSW, INPUT_PULLUP); 
  pinMode(StepSW, INPUT_PULLUP); 
  pinMode(HoldSW, INPUT_PULLUP);
  pinMode(CwMode, INPUT_PULLUP); 
  pinMode(TxMode, INPUT_PULLUP);
  pinMode(Relay, OUTPUT);
  // Configure interrupt and enable for rotary encoder.
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();  
  lcd.init();
  lcd.backlight();
  lcd.clear();  
  lcd.setCursor(0, 0); 
  lcd.print("AD9850");  
  lcd.setCursor(0, 1);  
  lcd.print("DDS VFO");   
  delay(2000);
  lcd.clear(); 
  lcd.setCursor (0, 0);
  lcd.print("RX"); 
  lcd.setCursor (0, 1);
  lcd.print("SSB");  
  // Initialise the AD9850 module.
  AD9850.init();
  AD9850.reset();
  AD9850.wr_serial(0x00, freq+offset);
  updateDisplay();
}
void loop() {
     if (digitalRead(CwMode) == HIGH){  //ssb
      if(cw=10000){   
      lcd.setCursor(0, 1); 
      lcd.print("    ");   
      cw=0;        
      } 
      cw=cw+1;    
   }
   if (digitalRead(TxMode) == HIGH){   //rx
      if(tx=10000) {     
      lcd.setCursor(0, 0); 
      lcd.print("    ");
      tx=0;
      }
      tx=tx+1;         
   }   
  
   if (digitalRead(MvfoSW) == LOW){   //main vfo
      if(rl=10000) {   
      digitalWrite(Relay, HIGH);
      rl=0;
      }
      rl=rl+1;
   } 
   if (digitalRead(MvfoSW) == HIGH){  //dds vfo
      if(rl=10000) { 
      digitalWrite(Relay, LOW);
      rl=0;
      }
      rl=rl+1;         
   }
   if (digitalRead(StepSW) == LOW){   //dds 100hz
      stepf = 100; 
      }
   if (digitalRead(StepSW) == HIGH){  //dds 10hz
      stepf = 10;
      }  
  
  if (digitalRead(TxMode) == LOW ){ //send
      delay(50);
    if (digitalRead(CwMode) == LOW ){ //cw
      lcd.setCursor(0, 1); 
      lcd.print("CW ");
      lcd.setCursor(0, 0); 
      lcd.print("SEND");    
      AD9850.wr_serial(0x00, freq+offset+800 );  // freq+800            
      while(digitalRead(TxMode) == LOW){ 
      if(wr=10000) {                              //ad9850 write  1/10000
      AD9850.wr_serial(0x00, freq+offset+800);   
      wr=0;
      }
      wr=wr+1;        
    }      
      AD9850.wr_serial(0x00, freq+offset );
      lcd.setCursor(0, 1); 
      lcd.print("    ");
      lcd.setCursor(0, 0); 
      lcd.print("    ");        
      delay(50);          
    }
   
   if (digitalRead(CwMode) == HIGH ){ //ssb
      lcd.setCursor(0, 1); 
      lcd.print("SSB ");
      lcd.setCursor(0, 0); 
      lcd.print("SEND");    
      AD9850.wr_serial(0x00, freq+offset );  // freq+800            
      while(digitalRead(TxMode) == LOW){ 
      if(wr=10000) {                              //ad9850 write  1/10000
      AD9850.wr_serial(0x00, freq+offset );   
      wr=0;
      }
      wr=wr+1;   
    }      
      AD9850.wr_serial(0x00, freq+offset );
      lcd.setCursor(0, 1); 
      lcd.print("    ");
      lcd.setCursor(0, 0); 
      lcd.print("    ");       
      delay(50);         
    }
  }
        
  if (digitalRead(RitSW) == LOW && digitalRead(TxMode) == HIGH){ //rx rit_on
      lcd.setCursor (13, 0);
      lcd.print("RIT");   
      stepf = 1;       //1HZ
      while(digitalRead(RitSW) == LOW && digitalRead(TxMode) == HIGH){      
      if (ritfOld != ritf) {
      AD9850.wr_serial(0x00, freq+offset+ritf);     
      ritfOld=ritf;     
      lcd.setCursor (3, 0);
      sprintf(disp_buf2, "%10ld", ritf);
      lcd.print(disp_buf2);
      lcd.print("RIT");  
    } 
      if(wr=10000) {                              //ad9850 write  1/10000
      AD9850.wr_serial(0x00, freq+offset+ritf);   
      wr=0;
      }
      wr=wr+1;   
   }  
      ritf = ritfOld; 
      ritfOld = ritfOld-1; 
      freq = freqOld; 
      freqOld = freqOld-1;
      lcd.clear();      
  } 
  
      
  if (freqOld != freq) {
      AD9850.wr_serial(0x00, freq+offset);
      updateDisplay();
      freqOld = freq;
      
    } 
    if(wr=10000) {                              //ad9850 write  1/10000
      AD9850.wr_serial(0x00, freq+offset);   
      wr=0;
      }
      wr=wr+1;   
  }

0 件のコメント:

コメントを投稿

Raspberry Pi Donkey Car スマートカー

  2020年に製作したDonkey Car スマートカー について記事にしました。 Donkey CarはRaspberry Pi のカメラからコースを ディープラーニングさせ自動走行を行います。(動画は白線上を自動走行)   動画