2016年4月2日土曜日

AD9850 DUAL DDS Shields

AD9850 DDS VFOにキャリア発振器を含めた物を作る目的で、DUAL DDS Shieldsを作った。これは、AD9850 Module用で、DDSを1枚若しくは2枚登載したアプリケーションが可能。殆ど余分な回路が無い為、DDSベースボードとして使える。
AD9850 Moduleを1枚実装した例。上下どちら側で使うかは、アプリケーション次第である。従来の1DDS VFOを移植も良い。 
AD9850 Moduleを2枚実装した例。DUAL DDS システム(マルチオシレータ、変調器付きSG、VFOなど)が可能。 

回路図。 

PCBサイズ 69 x 54















Program(スケッチ)

DUAL DDSのサンプル。


//////////////////////////////////////////////////////////////////////
//  AD9850 DUAL DDS VFO test program ver.1.0
//
//    Copyright(C)2016.JA2GQP.All rights reserved.
//     Crystal replacement
//                                                  2016/4/2
//                                                  JA2GQP
//////////////////////////////////////////////////////////////////////

//----------  Define Constant Value   ----------
                                               
const byte  C_DATA = 7;                            // DIO7
const byte  C_UD = 8;                                // DIO8
const byte  C_CLK = 9;                              // DIO9

const byte  V_DATA = 10;                          // DIO10
const byte  V_UD = 11;                              // DIO11
const byte  V_CLK = 12;                            // DIO12

const long  VFO_FRQ = 7000000L;              // VFO=7.000Mhz
const long  CAL_FRQ = 7100000L;              // CAL=7.100Mhz

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

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

long Dds_Dat = 0;                                     // DDS Data

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

void setup(){
  pinMode(C_UD,OUTPUT);
  pinMode(C_CLK,OUTPUT);
  pinMode(C_DATA,OUTPUT);

  pinMode(V_UD,OUTPUT);
  pinMode(V_CLK,OUTPUT);
  pinMode(V_DATA,OUTPUT);
}

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

void loop() {
  Dds_Dat = VFO_FRQ;
  Fnc_Dds(Dds_Dat,V_DATA,V_CLK,V_UD);

  Dds_Dat = CAL_FRQ;
  Fnc_Dds(Dds_Dat,C_DATA,C_CLK,C_UD);
  delay(100);
}


//----------  Function DDS PROC  ---------------

void Fnc_Dds(double frquency,byte dat,byte clk,byte ud){
  unsigned long wrk = frquency * TWO_E32 / DDS_CLK;
 
  digitalWrite(ud,LOW);

  shiftOut(dat,clk,LSBFIRST,wrk);
  shiftOut(dat,clk,LSBFIRST,(wrk >> 8));
  shiftOut(dat,clk,LSBFIRST,(wrk >> 16));
  shiftOut(dat,clk,LSBFIRST,(wrk >> 24));
  shiftOut(dat,clk,LSBFIRST,DDS_CMD);   // AD9850 command

  digitalWrite(ud,HIGH);
}
            

2016年4月1日金曜日

AD9834 DDS VFO Parameter

Arduino版にパラメータ機能を追加した。ベースにしたVFOは、7MHz CW/DDS VFOで、RIT・SPRIT機能がない物である。今回追加したパラメータ機能は、固有要素であるDDS基準周波数、IF周波数、VFOモードをパラメータとした。この機能追加で、スケッチの完成度がupした。
パラメータの変更は、ENT SWを3秒以上、長押し。また、パラメータ機能からの復帰は、ENT SWを3秒以上、長押し。





DDS基準発振周波数設定。
ロータリーエンコーダで周波数を設定。この時、実周波数を設定すれば、VFO精度向上が望める。 
IF周波数設定。
ロータリーエンコーダで周波数を設定。
VFO動作モード設定。
MUL SWを押すと、Roff > TR > R+IF > TR+IFが循環。
Roff TX=VFO、RX=停止(0Hz出力)
TR  TX=VFO、RX=VFO
R+IF TX=VFO、RX=VFO+IF
TR+IF TX=VFO+IF、RX=VFO+IF 

回路図である。 LCD接続は、パラレル。電源回路に7808が入れてあるが、UNOボード実装のレギュレータ異常発熱対策である。UNO互換ボードを使う場合、この回路を入れる方が賢明。 











Program(スケッチ)

チャンネル0は、周波数制限と逓倍数を無しとした。

//////////////////////////////////////////////////////////////////////
//  AD9834 DDS VFO program ver.1.1
//    Copyright(C)2016.JA2GQP.All rights reserved.
//
//      Frequency Limitted.
//                                    <<<<< Arduino IDE 1.0.6 >>>>>
//                                                2016/3/27
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.STEP(1M,100k,10k,1k,100,10)
//    2.Channel Memory.Main Channel(Ch0) + 3 Channel(Ch1,Ch2,Ch3)
//    3.Protection Operation At The Time Of Transmission
//    4.Parameter settings(DDS Clock,IF Frequency,VFO Mode)
//
//--------------------------------------------------------------------
//  Library
//  http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
//
//////////////////////////////////////////////////////////////////////

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

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

LiquidCrystal lcd(12,11,10,9,8,7);        // RS,ENABLE,DB4,DB5,DB6,DB7

//----------  Define Constant Value   ----------
                                             
const byte  ENC_A = 2;                     // Encorder A
const byte  ENC_B = 3;                     //          B
const byte  SDATA = 4;                     // AD9834 SDATA
const byte  SCLK = 5;                      //        SCLK
const byte  FSYNC = 6;                     //        FSYNC
const byte  SW_TX = 13;                    // TX SW
const byte  SW_STEP = 14;                  // STEP SW
const byte  SW_CH = 15;                    // CH SW
const byte  SW_ENT = 16;                   // ENT SW
const byte  SW_MUL = 17;                   // MUL SW
const byte  SW_OPT = 18;                   // OPT SW

const long  DEF_STP = 1000L;               // Init STEP
const long  LW_VFO80 = 3500000L;           // 3.5MHz Lower Limit
const long  HI_VFO80 = 3575000L;           //        Upper Limit
const long  LW_VFO40 = 7000000L;           // 7MHz   Lower Limit
const long  HI_VFO40 = 7200000L;           //        Upper Limit
const long  LW_VFO20 = 14000000L;          // 14MHz  Lower Limit
const long  HI_VFO20 = 14350000L;          //        Upper Limit
const long  LW_VFO15 = 21000000L;          // 21MHz  Lower Limit
const long  HI_VFO15 = 21450000L;          //        Upper Limit
const long  LW_VFO10 = 28000000L;          // 28MHz  Lower Limit
const long  HI_VFO10 = 29700000L;          //        Upper Limit
const long  LW_VFO6 = 50000000L;           // 50MHz  Lower Limit
const long  HI_VFO6 = 54000000L;           //        Upper Limit

const long  DEF_VFO = 7050000L;            // Default Vfo Frequency
const long  DEF_OSC = 50000000L;           //         OSC 50MHz
const long  DEF_IF = 10700000L;            //         IF  10.7MHz

const unsigned long  TWO_E28 = 268435456L; // 2^28

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

const byte  Chn_Eep = 0x20;                // Channel
const byte  Osc_Eep = 0x22;                // OSC
const byte  If_Eep = 0x26;                 // IF
const byte  Vfo_Eep = 0x2a;                // DDS mode

//----------  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 RX_Dat = 0;                          // RX DDS Out Data
long TX_Dat = 0;                          // TX DDS Out Data
long Enc_Stp = 0;                         // STEP
long Lng_Wk1 = 0;                         // Long Work1
long Lng_Wk2 = 0;                         //      Work2
long DDS_CLK = 0;                         //      DDS Clock
long VFO_IF = 0;                          //      VFO IF

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

byte Byt_Chn = 0;                         // Channel SW
byte Byt_Chnb = 0;                        // Channel SW Old
byte Flg_Tx = 0;                          // TX Flag
byte Flg_Mul = 0;                         // Multi Flag
byte Byt_Mul = 0;
byte Flg_Ent = 0;                         // ENT Flag
byte Byt_Ent = 0;
byte Flg_Osc = 0;                         // OSC Flag
byte Flg_If = 0;                          // IF Flag
byte Flg_Vfo = 0;                         // DDS Flag
byte Byt_Vfo = 0;                         // VFO Mode

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

void setup(){
  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_ENT,INPUT_PULLUP);
  pinMode(SW_MUL,INPUT_PULLUP);
  pinMode(SW_OPT,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH,INPUT_PULLUP);

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

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

  pinMode(FSYNC,OUTPUT);
  pinMode(SCLK,OUTPUT);
  pinMode(SDATA,OUTPUT);

  Flg_Tx = 0;                             // Flag Initialization
  Flg_Ent = 0;                          
  Flg_Mul = 0;                          
  Flg_Osc = 0;                          
  Flg_Vfo = 0;                          

  lcd.clear();

  DDS_CLK = Fnc_Eep_Lod4(Osc_Eep);        // EEPROM Read DDS OSC
  if(DDS_CLK < 0)
    DDS_CLK = DEF_OSC;

  VFO_IF = Fnc_Eep_Lod4(If_Eep);          //             IF
  if(VFO_IF < 0)
    VFO_IF = DEF_IF;

  Byt_Vfo = EEPROM.read(Vfo_Eep);         //             VFO mode
  if(Byt_Vfo < 0)
    Byt_Vfo = 0;

  Byt_Chn = EEPROM.read(Chn_Eep);         //             Channel
  if(Byt_Chn < 0)
    Byt_Chn = 0;
  Byt_Chnb = Byt_Chn;

  Fnc_Eep_Rd();                          //             VFO & STEP                            

  Fnc_Band();                            // Band check
}

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

void loop() {
  if(Flg_Tx == 0){                          // TX off?
    if(digitalRead(SW_STEP) == LOW){        // STEP SW On?
      Fnc_Stp();                          
      }
    if(digitalRead(SW_ENT) == LOW){         // ENT SW On?
      Fnc_Ent();                          
      }
    if(digitalRead(SW_MUL) == LOW){         // MUL SW On?
      Fnc_Mul();                          
      }

    if(Flg_Ent == 0){                       // Parameter not chenge?
      if((digitalRead(SW_CH) == LOW)){      // SEL SW On?
        Fnc_Chsw();                          
        }
      }
    if(Byt_Chnb != Byt_Chn){                // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
      }
    if(Flg_Ent == 1){                      // ENT proc.?
      Fnc_Prm();
      }
      else{
        lcd.setCursor(5,1);
        lcd.print("    ");
        }
    }

  if(digitalRead(SW_TX) == LOW){            // Tx On?
    Flg_Tx = 1;                             //    Yes,Flg_Tx Set
    }
    else{                                  
      Flg_Tx = 0;                          //     No,Flg_Tx Reset              
      }

  Fnc_Band();                              // Band check
  Fnc_If(Byt_Vfo);                         // VFO mode data set

  if(Flg_Tx == 0)                          // RX
    Fnc_Dds(RX_Dat / Byt_Mul);            // AD9834 DDS Out

  if(Flg_Tx == 1){                         // TX
    if(Byt_Mul != 255)                     // In a range
      Fnc_Dds(TX_Dat / Byt_Mul);          // AD9834 DDS Out
      else
        Fnc_Dds(0);
        }
     
  Fnc_Lcd();                               // LCD Display
  delay(100);
}

//----------  Function IF Proc.  ---------------

void Fnc_If(byte if_mode){
  switch(if_mode){
    case 0:                             // Roff
      RX_Dat = 0L;                      // RX = off
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;

    case 1:                             // TR
      RX_Dat = Vfo_Dat;                 // RX = VFO
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;

    case 2:                             // R+IF
      RX_Dat = Vfo_Dat + VFO_IF;        // RX = VFO + IF
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;

    case 3:                             // TR+IF
      RX_Dat = Vfo_Dat + VFO_IF;        // RX = VFO + IF
      TX_Dat = Vfo_Dat + VFO_IF;        // TX = VFO + IF
      break;

    default:
      RX_Dat = 0L;                      // RX = off
      TX_Dat = Vfo_Dat;                 // TX = VFO
      break;
    }
}

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

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

  if(Flg_Tx == 0){
    if(result) {  
      if(result == DIR_CW)
        Vfo_Dat = Vfo_Dat + Enc_Stp;
        else
          Vfo_Dat = Vfo_Dat - Enc_Stp;
          }
    }
}

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

void Fnc_Dds(double frquency){
  unsigned long wrk = frquency * TWO_E28 / DDS_CLK;
  unsigned int wrk1,wrk2,wrk3;

  wrk1 = 0x2000;
  wrk2 = wrk & 0x3fff;
  wrk2 = wrk2 | 0x4000;
  wrk3 = wrk >> 14;
  wrk3 = wrk3 & 0x3fff;
  wrk3 = wrk3 | 0x4000;

  digitalWrite(SCLK,HIGH);                    
  digitalWrite(FSYNC,LOW);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk1 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk1);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk2 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk2);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk3 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk3);

  digitalWrite(FSYNC,HIGH);
}

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

void Fnc_Stp(){
  if(Enc_Stp == 10){                      // Step = 10Hz ?
    Enc_Stp = 1000000;                    //   Yes,1MHz 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;
    case 1000000:
      lcd.print("1M  ");
      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(){
  lcd.setCursor(0,0);
  if(Flg_Tx == 1)
    lcd.print("T");
    else if(Flg_Ent == 1)
      lcd.print("P");
      else
        lcd.print(Byt_Chn);

  Fnc_Step_Disp();

  if((Flg_Mul == 1) && (Byt_Mul != 255)){
    lcd.setCursor(5,1);
    lcd.print("    ");
    lcd.setCursor(5,1);
    lcd.print("x");
    lcd.print(Byt_Mul);
    Lng_Wk1 = Vfo_Dat / Byt_Mul;
    Fnc_Fdsp(Lng_Wk1);  
    }
    else if((Byt_Mul == 255) && (Flg_Ent == 0)){
      Fnc_Fdsp(Vfo_Dat);
      lcd.setCursor(5,1);
      lcd.print("Over");
      }
      else{
        Fnc_Fdsp(Vfo_Dat);
        }

  if(Flg_Vfo == 0){
    lcd.setCursor(10,1);
    lcd.print("JA2GQP");
    }
}

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

void Fnc_Fdsp(long f_disp){
  Fnc_Dot_Edit(Lcd_Dat,f_disp);
  lcd.setCursor(1,0);
  lcd.print(":              ");
  lcd.setCursor(3,0);
  lcd.print(Lcd_Dat);
  lcd.print("Hz");
}

//----------  Function ENT  ---------

void Fnc_Ent(){
  byte cnt = 0;

  if(Flg_Ent == 0){
    Fnc_Eep_Wt(Byt_Chn);
    while(digitalRead(SW_ENT) == LOW){
      delay(500);
      cnt++;

      if(6 <= cnt){                              // Parameter change mode(3sec)
        lcd.setCursor(0,0);
        lcd.print("P");
        Flg_Ent = 1;

        if(Flg_Osc == 0){
          Lng_Wk2 = Vfo_Dat;
          Vfo_Dat = Fnc_Eep_Lod4(Osc_Eep);
          if(Vfo_Dat <= 0){
            Vfo_Dat = DEF_OSC;
            Fnc_Eep_Sav4(Vfo_Dat,Osc_Eep);
            }
          Flg_Osc = 1;
          Flg_If = 0;
          Flg_Mul = 0;
          }

        Fnc_Fdsp(Vfo_Dat);
         
        lcd.setCursor(5,1);
        lcd.print("OSC ");
        }
      }
   
    }
    else{
      while(digitalRead(SW_ENT) == LOW){
        delay(500);
        cnt++;

        if(6 <= cnt){                            // Return Parameter cahne mode(3sec)
          lcd.setCursor(5,1);
          lcd.print("    ");
          lcd.setCursor(0,0);
          lcd.print(Byt_Chn);
          Flg_Ent = 0;
          Flg_Vfo = 0;
       
          if(Flg_Osc == 1){
            Fnc_Eep_Sav4(Vfo_Dat,Osc_Eep);
            DDS_CLK = Vfo_Dat;
            Vfo_Dat = Lng_Wk2;
            Flg_Osc = 0;
            Fnc_Fdsp(Vfo_Dat);
            }
         
          if(Flg_If == 1){
            Fnc_Eep_Sav4(Vfo_Dat,If_Eep);
            Vfo_Dat = Lng_Wk2;
            Flg_If = 0;
            Fnc_Fdsp(Vfo_Dat);
            }
         
          EEPROM.write(Vfo_Eep,Byt_Vfo);
          }
          else
            Byt_Ent++;
        }
      }
}

//----------  Function Prameter PROC  ---------

void Fnc_Prm(){
    lcd.setCursor(5,1);

  switch(Byt_Ent){
      case 0:                                        // OSC Set
        if(Flg_Osc == 0){
          Vfo_Dat = Fnc_Eep_Lod4(Osc_Eep);
          Flg_Osc = 1;
          }
        break;

      case 1:                                       // IF Set
        if(Flg_Osc == 1){
          Fnc_Eep_Sav4(Vfo_Dat,Osc_Eep);
          Flg_Osc = 0;
          }
     
        if(Flg_If == 0){
          Vfo_Dat = Fnc_Eep_Lod4(If_Eep);
          if(Vfo_Dat < 0)
            Vfo_Dat = DEF_IF;
          Flg_If = 1;
          }
       
        lcd.print("IF  ");
        break;

      case 2:                                      // DDS mode Set
        if(Flg_If == 1){
          Fnc_Eep_Sav4(Vfo_Dat,If_Eep);
          Vfo_Dat = Lng_Wk2;
          Flg_If = 0;
          Flg_Vfo = 0;
          }

        if(Flg_Vfo == 0){
          Byt_Vfo = EEPROM.read(Vfo_Eep);
          if(Byt_Vfo < 0)
            Byt_Vfo = 0;
          Flg_Vfo = 1;
          }

        lcd.setCursor(10,1);
        switch(Byt_Vfo){
          case 0:
            lcd.print("Roff  ");                  // TX=VFO RX=0
            break;
          case 1:
            lcd.print("TR    ");                  // TX=VFO RX=VFO
            break;
          case 2:
            lcd.print("R+IF  ");                  // TX=VFO RX=VFO+IF
            break;
          case 3:
            lcd.print("TR+IF ");                  // TX=VFO+IF RX=VFO+IF
            break;
          default:
            Byt_Vfo = 0;
            lcd.print("Roff  ");
            break;
          }

        lcd.setCursor(5,1);
        lcd.print("VFO ");
        break;

      default:
        if(Flg_Vfo == 1){
          EEPROM.write(Vfo_Eep,Byt_Vfo);
          lcd.setCursor(10,1);
          lcd.print("JA2GQP");
          Flg_Vfo = 0;
          }
        lcd.setCursor(5,1);
        lcd.print("OSC ");
        Byt_Ent = 0;
        break;
    }
}

//----------  Function CH SW Check  ---------

void Fnc_Chsw(){
  Byt_Chn++;
  while(digitalRead(SW_CH) == LOW)
    ;
  delay(250);
}

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

void Fnc_Eep_Rd(){
  if(Fnc_Eep_Lod4(Frq_Eep0) <= 0){
    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);
        Byt_Chn = 0;
        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);
        Byt_Chn = 0;
        break;
    }
  }
  if(Enc_Stp <= 0){
    Enc_Stp = DEF_STP;
  }
}

//----------  Function Band  ---------

void Fnc_Band(){
  if(Byt_Chn != 0){
    if((Vfo_Dat >= LW_VFO80) && (Vfo_Dat <= HI_VFO80))
      Byt_Mul = 1;
      else if((Vfo_Dat >= LW_VFO40) && (Vfo_Dat <= HI_VFO40))
        Byt_Mul = 1;
        else if((Vfo_Dat >= LW_VFO20) && (Vfo_Dat <= HI_VFO20))
          Byt_Mul = 2;
          else if((Vfo_Dat >= LW_VFO15) && (Vfo_Dat <= HI_VFO15))
            Byt_Mul = 3;
            else if((Vfo_Dat >= LW_VFO10) && (Vfo_Dat <= HI_VFO10))
              Byt_Mul = 4;
              else if((Vfo_Dat >= LW_VFO6) && (Vfo_Dat <= HI_VFO6))
                Byt_Mul = 6;
                else
                  Byt_Mul = 255;
    }
    else
      Byt_Mul = 1;
}

//----------  Function EEPROM Write  ---------

void Fnc_Eep_Wt(byte chn){
    switch(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;
    }
    EEPROM.write(Chn_Eep,Byt_Chn);
}

//----------  Function Multi  ---------

void Fnc_Mul(){
  if(Flg_Ent == 0){
    if(Flg_Mul == 0)
      Flg_Mul = 1;
      else
        Flg_Mul = 0;
    }
    else{
      Byt_Vfo++;
      }
  while(digitalRead(SW_MUL) == LOW)
    ;
  delay(250);
}

2016年3月4日金曜日

QRP 7MHz CW TX/DDS VFO

 2009年7月号 CQ hamradio付録の7MHzQRP送信基板を作った。しかし、適当な水晶発振子の手持ちが無く、DDS VFOと組合わせる事にした。DDS VFOは、2015年9月9日投稿のAD9834を使ったVFOである。 DDSコントロールプログラムは、以前の物を改造した。このVFOは、バンドの概念が無く、全てチャンネルである。この為、全て7MHzに設定することも異なる周波数帯に設定することも出来る。
また、7MHz CW送信機として使う場合、フルブレイクインは出来ない。
DDS発振周波数は、3.5MHzから8.5MHzとした。これで3.5MHzから50MHz(6逓倍すれば)のVFOとなる。周波数設定は、周波数範囲が広いため、STEPに1MHzを追加した。
今回、チャンネルスイッチをプッシュボタンに変更したため、チャンネル切替時全てのチャンネルが、メモリー保存できる様に変更した。 新たにMULスイッチを追加した。MULスイッチで、DDS発振周波数の表示ができる。例えば、50.6MHzの時、MULスイッチ操作した表示が左側の写真である。この状態でエンコーダを回すと、1kHz/6 STEPで変化する。 

回路図である。投稿済のBlogに公開した回路を一部変更とCQ hamradio記事の合体。

出力
3.5MHz       340mW
7MHz         300mW
8.433MHz     260mW







Program

周波数帯毎の運用周波数制限を行っている。範囲外の時、Overと表示。受信時および範囲外エラー時、DDS発振停止(0Hzを指定)。Arduino IDE1.0.6でコンパイルした。


//////////////////////////////////////////////////////////////////////
//  AD9834 DDS VFO program ver.1.0
//    Copyright(C)2016.JA2GQP.All rights reserved.
//
//      Frequency Limitted.
//                                    <<<<< Arduino IDE 1.0.6 >>>>>
//                                                2016/3/3
//                                                  JA2GQP
//--------------------------------------------------------------------
//  Function
//    1.STEP(1M,100k,10k,1k,100,10)
//    2.Channel Memory.Main Channel(Ch0) + 3 Channel(Ch1,Ch2,Ch3)
//    3.Protection Operation At The Time Of Transmission
//
//////////////////////////////////////////////////////////////////////

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <rotary.h>
#include <EEPROM.h>

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

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for
                                   // a 16 chars and 2 line display

//----------  Define Constant Value   ----------
                                             
const byte  ENC_A = 2;                      // Encorder A
const byte  ENC_B = 3;                      //          B
const byte  SDATA = 4;                      // AD9834 SDATA
const byte  SCLK = 5;                       //        SCLK
const byte  FSYNC = 6;                     //        FSYNC
const byte  SW_STEP = 7;                   // STEP SW
const byte  SW_CH = 8;                     // CH SW
const byte  SW_ENT = 9;                    // ENT SW
const byte  SW_MUL = 10;                   // MUL SW
const byte  SW_TX = 13;                    // TX SW

const long  DEF_STP = 1000L;               // Init STEP
const long  LW_VFO80 = 3500000L;           // 3.5MHz Lower Limit
const long  HI_VFO80 = 3575000L;           //        Upper Limit
const long  LW_VFO40 = 7000000L;           // 7MHz   Lower Limit
const long  HI_VFO40 = 7200000L;           //        Upper Limit
const long  LW_VFO20 = 14000000L;          // 14MHz  Lower Limit
const long  HI_VFO20 = 14350000L;          //        Upper Limit
const long  LW_VFO15 = 21000000L;          // 21MHz  Lower Limit
const long  HI_VFO15 = 21450000L;          //        Upper Limit
const long  LW_VFO10 = 28000000L;          // 28MHz  Lower Limit
const long  HI_VFO10 = 29700000L;          //        Upper Limit
const long  LW_VFO6 = 50000000L;           // 50MHz  Lower Limit
const long  HI_VFO6 = 54000000L;           //        Upper Limit

const long  DEF_VFO = 7050000L;            // Vfo Default Frequency

const unsigned long  DDS_CLK = 56000000L;  // AD9834 Clock 56Mhz
const unsigned long  TWO_E28 = 268435456L; // 2^28

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

const byte  Chn_Eep = 0x20;                // Channel

//----------  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 Enc_Stp = 0;                         // STEP
long Lng_Wk1 = 0;                         // Long Work1

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

byte Byt_Chn = 0;                         // Channel SW
byte Byt_Chnb = 0;                        // Channel SW Old
byte Flg_Tx = 0;                          // TX Flag
byte Flg_Mul = 0;                         // Multi Flag
byte Byt_Mul = 0;

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

void setup(){
  lcd.init();                            // initialize the lcd
  lcd.backlight();                       // LCD backlight on

  pinMode(SW_STEP,INPUT_PULLUP);
  pinMode(SW_ENT,INPUT_PULLUP);
  pinMode(SW_MUL,INPUT_PULLUP);
  pinMode(SW_TX,INPUT_PULLUP);
  pinMode(SW_CH,INPUT_PULLUP);

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

  pinMode(FSYNC,OUTPUT);
  pinMode(SCLK,OUTPUT);
  pinMode(SDATA,OUTPUT);

  Flg_Tx = 0;

  lcd.clear();
  Byt_Chn = EEPROM.read(Chn_Eep);
  if((Byt_Chn < 0) || (Byt_Chn > 3))
    Byt_Chn = 0;
  Byt_Chnb = Byt_Chn;
  Fnc_Eep_Rd();                              // EEPROM Read
  Fnc_Band();                                // Band check
}

//----------  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_ENT) == LOW){         // ENT SW On?
      Fnc_Ent();                            //     Yes,ENT proc.
      }
    if(digitalRead(SW_MUL) == LOW){         // MUL SW On?
      Fnc_Mul();                            //     Yes,MUL proc.
      }
    if(digitalRead(SW_CH) == LOW){          // CH SW On?
      Fnc_Chsw();                          
      }
    if(Byt_Chnb != Byt_Chn){                // CH SW OLD != NEW?
      Fnc_Eep_Wt(Byt_Chnb);
      Byt_Chnb = Byt_Chn;
      Fnc_Eep_Rd();
      }
  }

  if(digitalRead(SW_TX) == LOW){            // Tx On?
    Flg_Tx = 1;                             //    Yes,Flg_Tx Set
    Dds_Dat = Vfo_Dat;
    }
    else{                                  
      Flg_Tx = 0;                          //     No,Flg_Tx Reset              
      Dds_Dat = 0;
      }

  Fnc_Band();                              // Band check
  if(Byt_Mul != 255)
    Fnc_Dds(Dds_Dat / Byt_Mul);            // AD9834 DDS Out
    else
      Fnc_Dds(0);    
  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)
        Vfo_Dat = Vfo_Dat + Enc_Stp;
      else
          Vfo_Dat = Vfo_Dat - Enc_Stp;
      }
    }
}

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

void Fnc_Dds(double frquency){
  unsigned long wrk = frquency * TWO_E28 / DDS_CLK;
  unsigned int wrk1,wrk2,wrk3;

  wrk1 = 0x2000;
  wrk2 = wrk & 0x3fff;
  wrk2 = wrk2 | 0x4000;
  wrk3 = wrk >> 14;
  wrk3 = wrk3 & 0x3fff;
  wrk3 = wrk3 | 0x4000;

  digitalWrite(SCLK,HIGH);                    
  digitalWrite(FSYNC,LOW);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk1 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk1);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk2 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk2);

  shiftOut(SDATA,SCLK,MSBFIRST,(wrk3 >> 8));
  shiftOut(SDATA,SCLK,MSBFIRST,wrk3);

  digitalWrite(FSYNC,HIGH);
}

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

void Fnc_Stp(){
  if(Enc_Stp == 10){                      // Step = 10Hz ?
    Enc_Stp = 1000000;                    //   Yes,1MHz 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;
    case 1000000:
      lcd.print("1M  ");
      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();

  lcd.setCursor(5,1);
  if((Flg_Mul == 1) && (Byt_Mul != 255)){
    lcd.print("    ");
    lcd.setCursor(5,1);
    lcd.print("x");
    lcd.print(Byt_Mul);
    Lng_Wk1 = Vfo_Dat / Byt_Mul;
    }else if(Byt_Mul == 255){
      lcd.print("Over");
      Lng_Wk1 = Vfo_Dat;
      }
      else{
        lcd.print("    ");
        Lng_Wk1 = Vfo_Dat;
        }

  Fnc_Dot_Edit(Lcd_Dat,Lng_Wk1);
  lcd.setCursor(1,0);
  lcd.print(":              ");
  lcd.setCursor(3,0);
  lcd.print(Lcd_Dat);
  lcd.print("MHz");

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


//----------  Function ENT  ---------

void Fnc_Ent(){
  Fnc_Eep_Wt(Byt_Chn);
  while(digitalRead(SW_ENT) == LOW)
    ;
  delay(250);
}

//----------  Function Channel SW Check  ---------

void Fnc_Chsw(){
    switch(Byt_Chn){
      case 0:
        Byt_Chn = 1;
        break;
      case 1:
        Byt_Chn = 2;
        break;
      case 2:
        Byt_Chn = 3;
        break;
      case 3:
        Byt_Chn = 0;
        break;
      default:
        Byt_Chn = 0;
        break;
    }
  while(digitalRead(SW_CH) == LOW)
    ;
  delay(100);
}
//----------  Function EEPROM Read  ---------

void Fnc_Eep_Rd(){
  if(Fnc_Eep_Lod4(Frq_Eep0) <= 0){
    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 Band  ---------

void Fnc_Band(){
  if((Vfo_Dat >= LW_VFO80) && (Vfo_Dat <= HI_VFO80))
    Byt_Mul = 1;
    else if((Vfo_Dat >= LW_VFO40) && (Vfo_Dat <= HI_VFO40))
      Byt_Mul = 1;
      else if((Vfo_Dat >= LW_VFO20) && (Vfo_Dat <= HI_VFO20))
        Byt_Mul = 2;
        else if((Vfo_Dat >= LW_VFO15) && (Vfo_Dat <= HI_VFO15))
          Byt_Mul = 3;
          else if((Vfo_Dat >= LW_VFO10) && (Vfo_Dat <= HI_VFO10))
            Byt_Mul = 4;
            else if((Vfo_Dat >= LW_VFO6) && (Vfo_Dat <= HI_VFO6))
              Byt_Mul = 6;
              else
                Byt_Mul = 255;
}

//----------  Function EEPROM Write  ---------

void Fnc_Eep_Wt(byte chn){
    switch(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;
    }
    EEPROM.write(Chn_Eep,Byt_Chn);
}

//----------  Function Multi  ---------

void Fnc_Mul(){
  if(Flg_Mul == 0)
    Flg_Mul = 1;
    else
      Flg_Mul = 0;
  while(digitalRead(SW_MUL) == LOW)
    ;
  delay(250);
}



  

2016年2月1日月曜日

AVR Frequency Counter

 BASCOM AVRで開発した周波数カウンタ。1/128プリスケーラを使い、ゲートタイム1.28secで最少分解能100Hzである。プリスケーラを常時使う様にした為、測定範囲10MHz-500MHz位(これ以上の測定未確認のため)。
部品実装したPCBである。PCBサイズは、LCDと同じ位の大きさに収めた。
回路図である。プリスケーラは、MB505Lが大量に見つかったので使ったが、MB506が回路変更することなく使う事が出来る。 
基板サイズ 79 × 36










Program

BASCOM AVRで開発の為、周波数のピリオド表示を簡単化する為、メガ表示部分を3桁固定。その為、桁数に満たない場合、頭に0(ゼロ)が付く。(3桁を超えると正しく表示されない。)
プリスケーラが1/128の為、ゲートタイム1.28sec固定である。
ヒューズビットもプログラムしてあるので、クロックの設定に悩まなくて良い。

'********************************************************
'ATtiny2313 Frequency Counter
'
'                                       2016/02/01
'                                           JA2GQP
' BASCOM AVR 2.0.7.5(DEMO version) Compiled
'--------------------------------------------------------
'Function
'   1.1/128 prescaler(resolution 100Hz,Gate time 1.28sec)
'   2.Display style 123.456.789MHz
'********************************************************

$regfile = "attiny2313.dat"
$crystal = 12800000
$prog &HFF , &HFF , &HDF , &HFF   ' generated. Take care that the chip supports all fuse bytes.

'---LCD port assign ---

Config Lcdpin = Pin , Db7 = Portb.0 , Db6 = Portb.1
Config Lcdpin = Pin , Db5 = Portb.2 , Db4 = Portb.3
Config Lcdpin = Pin , E = Portb.4 , Rs = Portb.5
Config Lcd = 16 * 2

'--- Timer interrupt assign ---

Config Timer0 = Timer , Prescale = 1
Config Timer1 = Counter , Edge = Rising

'--- define memory ---

Dim Flag As Bit
Dim Over As Byte
Dim Tint As Word
Dim Freq As Long
Dim Str_frq As String * 12
Dim Dsp_frq As String * 12

'--- Initialization ---

Stop Timer0
Stop Timer1
On Timer0 Timer0_int
On Timer1 Timer1_int
Enable Interrupts
Enable Timer0
Enable Timer1

Cls : Cursor Off
Lcd "GQP F.Counter"
Locate 2 , 2

Start Timer0
Start Timer1

'--- Main proc ---

Do
  If Flag = 1 Then
    Freq = Over * 65536
    Freq = Freq + Timer1
    Freq = Freq * 100
    Lcd "               "
    Locate 2 , 2
    Str_frq = Str(freq)
    Str_frq = Format(str_frq , "000.000000")
    Dsp_frq = Left(str_frq , 4) + Mid(str_frq , 5 , 3) + "." + Mid(str_frq , 8 , 3)
    Lcd Dsp_frq ; "MHz"
    Flag = 0
    Over = 0
    Tint = 0
    Timer1 = 0
    Start Timer0
    Start Timer1
  End If
Loop

End

Timer0_int:
  Incr Tint
  If Tint = 64000 Then           'Gate time 1.28sec
    Stop Timer0
    Stop Timer1
    Flag = 1
  End If
Return

Timer1_int:
  Incr Over
Return       

2016年1月17日日曜日

Arduino programmer

ブートローダ書込みをする為に、Arduino nanoを使ってprogrammerを作った。スケッチは、公開されている物をそのまま使っている。ブートローダ書込み以外に他のAVRが簡単に交換できる様、40Pinゼロプレッシャーを使った。この為、ATtiny85など書込みが出来る様な回路とした。プロト版では、ATtiny2313を含めていたが、2kB(or 4kB)程度のメモリーで実用プログラムをArduino IDEで書くことは難しいので、ゼロプレッシャーで選択外とした。(ISP端子からprogram出来るので、問題ない。) ケースは、秋月電子の117に収納可能。

回路図である。
ATtiny85(8Pin)とATmega328P(28Pin) がゼロプレッシャーで書込み出来る構造とした。他のデバイスは、ISP端子経由。 

基板サイズ 85 x 57













デバイスの設定

Arduino IDE 1.0.Xと1.6.Xでデバイス設定方法が異なる。1.0.Xの場合、kosakalabの手順を使う。また、1.6.Xの場合は、highlowtechの手順。
ブートローダが必要ない時、ヒューズビットを正しく設定する為にブートローダ書込み(ダミー書込み)が必要。ブートローダ書込みを行わない場合、デフォルトのヒューズビットのままである。

      

2015年12月24日木曜日

Arduino Dip_Meter

Arduino nanoを使って、周波数カウンターとレベルメータの機能を持たせたディップメータ。秋月のクリアケースに収納し、ケース加工を最小限にした。周波数調整は、アクリル板を回す構造とし、アナログ感覚の操作性を目論んだ。まだコイルを作ってないが、動作範囲1-60MHz。
また、ディップが浅い問題があり、プログラム改修で対応したいと思っている。 
USB接続が出来る様、側面に穴あけ加工した。この事で、プログラムのメンテナンスが容易になった。 
カウンターは、1/10プリスケーラにより、60MHz程の周波数を測定。 

基板サイズ 80x86 



















Program

Arduinoの周波数カウンターサンプルを使用し、13.2MHz基準周波数でキャリブレーションしている。ただ、Arduinoボードの個体差(クロック)があるので、要調整。


/////////////////////////////////////////////////////////////////////////////////
//  Frequency counters and level meter
//
//    Copyright(C)2015.JA2GQP.All rights reserved.
//
//                                                  2015/12/22
//                                                  JA2GQP
//-----------------------------------------------------------------------------
// Arduino Frequency Counter Library
// http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-frequency-counter-library/
//
/////////////////////////////////////////////////////////////////////////////////

#include <LiquidCrystal.h>
#include <FreqCounter.h>

#define LCDCOLS 16

LiquidCrystal lcd(8, 7,  6, 4, 3, 2);

long int frq;
double cal;

byte one[8] = {                                   // Special character 1
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
};

byte two[8] = {                                   // Special character 2
  B10100,
  B10100,
  B10100,
  B10100,
  B10100,
  B10100,
  B10100,
};

byte three[8] = {                                 // Special character 3
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
};

//
//-------------------------------------------- Setup proc ---------------------------------------------------------------------
//

void setup() {
   cal = 13.2 / 13.2799;                          // Calibrat frequency
  lcd.begin(LCDCOLS, 2);
  lcd.clear();
 
  lcd.createChar(1, one);
  lcd.createChar(2, two);
  lcd.createChar(3, three);
 
  analogReference(DEFAULT);

  delay(200);
}


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

void loop() {
  int v;
  static unsigned long t = 0;
 
  FreqCounter::f_comp = 8;                        // Set compensation to 12
  FreqCounter::start(100);                        // Start counting with gatetime of 100ms
  while (FreqCounter::f_ready == 0);              // wait until counter ready
  frq = FreqCounter::f_freq;                      // read result

  lcd.clear();                                       // clear screen(cursol 0,0)
  lcd.print(frq * cal / 10000);                   // Frequency display
  lcd.print("MHz");

  v = analogRead(0);                              // Anarog data get
  printbar(v,16);                                  // Bar display for 16 column

  lcd.setCursor(10, 0);                           // Analog Volt display
  lcd.print(5.0/1023*v);                          // Voltage display
  lcd.print("V");
  delay(80);

}


//
//-------------------------------------------- Bar display for line2 ----------------------------------------------------------
//

void printbar(int ad_value, int disp_digit) {
  int p;
  int s;
  int i;
  int bar;
  int res;
  int bar_value;
 
  bar = disp_digit * 3;
  res = 1023.0 / bar + 0.5;
  bar_value = (float)ad_value / res + 0.5;
  p = bar_value / 3;
  s = bar_value % 3;
  lcd.setCursor(0, 1);

  for (i = 0; i < p; i++)
    lcd.write(3);

  if (s)
    lcd.write(s);
    else
      lcd.print(' ');

  for (i = 0; i < LCDCOLS - p - 1; i++)
    lcd.print(' ');
}




    

2015年11月27日金曜日

Antenna Analyzer 2.2"TFTケース

アンテナアナライザPCBを秋月電子ABS樹脂ケース(112-TS)に収納した。タクトスイッチは、同じく秋月のP-03648に、タクトスイッチキャップを2段重ね、操作部がケース全面より1mm位出る様にした。ケース蓋は、背面側にして、BNCコネクタが蓋に干渉することなく、付ける事が出来た。
 

左側。
中央にUSBコネクタ。

 

下側。
タクトスイッチキャップは2個貼り合わせて高さを調整した。基板とケース固定に使っているスペーサは、17mmに調整。
  


右側。
ケース蓋が背面側に開く。