2017年6月17日土曜日

stm32VFO 6mAM

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






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












スケッチ

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

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

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

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

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

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

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

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

uint16 Status;
uint16 Data;

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

int Flg_eepWT = 0;                                // EEP Wite Flag

char Lcd_data[10];

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


2 件のコメント:

Felipe さんのコメント...

boa tarde, sou Felipe ps7oi, gostaria de saber se esse sistema é um transceptor ou só receptor?

JA2GQP さんのコメント...

Esta é uma amostra usando stm32. No caso do transceptor AM, será assim.