VFOの主な仕様
1)8チャンネルメモリー
2)メモリー自動書き込み
3)BPF、LPF切替
4)周波数範囲チェック
5)自動モード切替
6)STEP 100Hz、1k、10k、100k、
1M
回路図
回路図である。I2Cデバイスのアドレスが判る様に記入した。EXTスイッチは、拡張用に割り付けたが未使用。TD62083のOut1からOut8は、リレー駆動用。
スケッチ
Arduino IDE1.8.8でコンパイルした。ライブラリの相性善し悪しで、I2Cデバイス動作が左右される。その為、スケッチのフォルダーにsrcフォルダーを作り、ライブラリを入れた。必要なファイルは、JA2GQP's Download siteのafpsnフォルダーからダウンロード可能。バンドの概念が無いので、どのチャンネルにどんなバンド帯でも設定が出来るが、設定したチャンネル番号でBPF、LPFを切替えているので注意。
//////////////////////////////////////////////////////////////////////
// si5351a PLL AFPSN VFO program ver.1.0
// Copyright(C)2019.JA2GQP.All rights reserved.
//
// 2019/1/22
// JA2GQP
//--------------------------------------------------------------------
// Function
// 1.STEP(1M,100k,10k,1k,100)
// 2.Memory Channel ch0 - ch7(8ch)
// 3.Protection Operation At The Time Of Transmission
//////////////////////////////////////////////////////////////////////
// PCF8574 https://github.com/xreef/PCF8574_library
#include "src/si5351.h" // Ver2,1,0
#include "src/LiquidCrystal_I2C.h" // 1.1.2
#include "src/Rotary.h"
#include <EEPROM.h>
#include "src/PCF8574.h"
//---------- Set I/O Device ---------------------
PCF8574 pcf8574(0x20); // Set i2c address
LiquidCrystal_I2C lcd(0x27,16,2); // address 0x27, display 16x2
Si5351 si5351;
Rotary r = Rotary(2,3); // 2 = Encorder A, 3 = Encorder B
//---------- Define Constant Value ----------
const byte SW_STEP = 4; // STEP SW
const byte SW_CH = 5; // CH SW
const byte SW_TX = 9; // TX SW
const byte OUT_MODE = 13; // OUTPUT Mode
////////////////////////////////
// Limited range
////////////////////////////////
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
////////////////////////////////
// default value
////////////////////////////////
const long DEF_FRQ = 7050000L; // Default Vfo(7.05MHz)
const long DEF_STP = 1000L; // Init STEP(1kHz)
////////////////////////////////
// etc
////////////////////////////////
const byte Max_Chn = 3; // Max Channel(8ch)
const byte Int_End = 73; // Initial end code
const char *CALL = "JA2GQP"; // Display Call sign
//---------- EEPROM Memory Address -----------------------
const byte Frq_Eep = 0x00; // Frequency(4byte*10)
const byte Stp_Eep = 0x30; // STEP(4byte*10)
const byte Chn_Eep = 0x60; // Channel(1byte*1)
const byte Vfo_Eep = 0x62; // Vfo mode(1byte*1)
const byte Eep_Int = 0x6e; // Eep Init(1byte*1)
//---------- Memory Assign -------------------
unsigned long Vfo_Dat = 0; // VFO Data
unsigned long Vfo_Datb = 0; // old
unsigned long Enc_Stp = 0; // STEP
long timepassed; // int to hold the arduino miilis since startup
char *Lcd_Dat = " "; // Lcd Display Buffer
char *Mode = " "; // Mode display
byte Byt_Chn = 0; // Channel SW
byte Byt_Chnb = 0; // Channel SW Old
byte Flg_Tx = 0; // TX Flag
byte Flg_eepWT = 0; // EEP Write Flag
byte Flg_Mode = 0; // Mode Flag
char Flg_Over; // Over Flag
byte Flg_Vfo = 0; // DDS Flag
byte Byt_Vfo = 0; // VFO Mode
//---------- Initialization Program ---------------
void setup(){
pcf8574.pinMode(P0,OUTPUT); // PCF8574 Set pinMode to OUTPUT
pcf8574.pinMode(P1,OUTPUT);
pcf8574.pinMode(P2,OUTPUT);
pcf8574.pinMode(P3,OUTPUT);
pcf8574.pinMode(P4,OUTPUT);
pcf8574.pinMode(P5,OUTPUT);
pcf8574.pinMode(P6,OUTPUT);
pcf8574.pinMode(P7,OUTPUT);
pcf8574.begin();
pcf8574.digitalWrite(P0,LOW);
pcf8574.digitalWrite(P1,LOW);
pcf8574.digitalWrite(P2,LOW);
pcf8574.digitalWrite(P3,LOW);
pcf8574.digitalWrite(P4,LOW);
pcf8574.digitalWrite(P5,LOW);
pcf8574.digitalWrite(P6,LOW);
pcf8574.digitalWrite(P7,LOW);
si5351.init(SI5351_CRYSTAL_LOAD_8PF,0,0);//initialize the Si5351
si5351.set_freq(0,SI5351_CLK0); // Dummy Frequency data
si5351.output_enable(SI5351_CLK0,0); // CLK0 disable
lcd.begin();
lcd.backlight();
pinMode(SW_STEP,INPUT_PULLUP);
pinMode(SW_TX,INPUT_PULLUP);
pinMode(SW_CH,INPUT_PULLUP);
pinMode(OUT_MODE,OUTPUT);
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei(); // INT Enable
Flg_Tx = 0; // Flag Initialization
Flg_Vfo = 0;
lcd.clear();
if(EEPROM.read(Eep_Int) != Int_End){ // Eep initialaz
delay(10);
Fnc_Eep_Int();
}
Byt_Chn = EEPROM.read(Chn_Eep); // Channel
pcf8574.digitalWrite(Byt_Chn,HIGH);
Byt_Chnb = Byt_Chn;
Fnc_Eep_Rd(); // VFO & STEP
}
//---------- Main program ---------------
void loop() {
if(Flg_Tx == 0){ // TX off?
if(digitalRead(SW_STEP) == LOW) // STEP SW On?
Fnc_Stp();
if((digitalRead(SW_CH) == LOW)) // SEL SW On?
Fnc_Chsw();
if(Byt_Chnb != Byt_Chn){ // CH SW OLD != NEW?
Fnc_Eep_Wt(Byt_Chnb);
pcf8574.digitalWrite(Byt_Chnb,LOW);
Byt_Chnb = Byt_Chn;
Fnc_Eep_Rd();
}
}
if(digitalRead(SW_TX) == LOW){ // Tx On?
Flg_Tx = 1; // Yes,Flg_Tx Set
si5351.output_enable(SI5351_CLK0, 1); // VFO enable
}
else{
Flg_Tx = 0; // No,Flg_Tx Reset
si5351.output_enable(SI5351_CLK0, 0); // VFO disable
}
Fnc_Band(); // Band check
if(Vfo_Dat != Vfo_Datb){ // Frequency update?
si5351.set_freq((Vfo_Dat * SI5351_FREQ_MULT) * 2,SI5351_CLK0);
Fnc_Fdsp(Vfo_Dat);
Vfo_Datb = Vfo_Dat;
timepassed = millis();
Flg_eepWT = 1;
}
Fnc_Lcd(); // LCD Display
if(Flg_eepWT == 1){ // EEPROM auto Write
if(timepassed+2000 < millis()){
Fnc_Eep_Wt(Byt_Chn);
Flg_eepWT = 0;
}
}
}
//---------- 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 Mode -------------------
void Fnc_Mode(){
lcd.setCursor(5,1);
if(Flg_Mode == 0){ // LSB ?
digitalWrite(OUT_MODE, HIGH);
lcd.print("LSB ");
}
else if(Flg_Mode == 1){ // USB ?
digitalWrite(OUT_MODE, LOW);
lcd.print("USB ");
}
}
//---------- Function Encorder STEP ---------
void Fnc_Stp(){
if(Enc_Stp == 100) // Step = 100Hz ?
Enc_Stp = 1000000; // Yes,1MHz set
else
Enc_Stp = Enc_Stp / 10; // Step down 1 digit
Fnc_Step_Disp();
Fnc_Lcd();
while(digitalRead(SW_STEP) == LOW)
;
}
//---------- Function STEP Display ----------
void Fnc_Step_Disp(){
lcd.setCursor(0,1);
switch(Enc_Stp){
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 Write EEPROM 4byte ---------
void Fnc_Eep_Write(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 Read EEPROM 4byte ---------
long Fnc_Eep_Read(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{
lcd.print(Byt_Chn);
pcf8574.digitalWrite(Byt_Chn,HIGH);
}
Fnc_Step_Disp();
if(Flg_Over == -1){
Fnc_Fdsp(Vfo_Dat);
lcd.setCursor(5,1);
lcd.print("Over");
}
else
Fnc_Fdsp(Vfo_Dat);
if(Flg_Over == 0){
Fnc_Mode();
lcd.setCursor(10,1);
lcd.print(CALL);
}
}
//---------- Function Frequency Display ---------
void Fnc_Fdsp(long f_disp){
Fnc_Dot_Edit(Lcd_Dat,f_disp);
lcd.setCursor(1,0);
lcd.print(": ");
lcd.print(Lcd_Dat);
lcd.print("Hz");
}
//---------- Function CH SW Check ---------
void Fnc_Chsw(){
byte cnt = 0;
Byt_Chn++;
while(digitalRead(SW_CH) == LOW){
delay(500);
cnt++;
if(6 <= cnt){ // Eep Initial start(3sec)?
lcd.setCursor(5,1);
lcd.print("Init");
Fnc_Eep_Int(); // Initialization
Byt_Chn = EEPROM.read(Chn_Eep); // Channel Read
Byt_Chnb = Byt_Chn;
Fnc_Eep_Rd(); // EEPROM Read
}
}
}
//---------- Function Eeprom Initialization -----------------
void Fnc_Eep_Int(){
int i;
for (i=0;i<160;i++) // 0 clear(160byte)
EEPROM.write(i, 0);
for(i=0;i<Max_Chn;i++){
Fnc_Eep_Write(DEF_FRQ,Frq_Eep+i*4); // Frequency(7.05MHz)
Fnc_Eep_Write(DEF_STP,Stp_Eep+i*4); // Step(1kHz)
}
EEPROM.write(Eep_Int,Int_End); // Init end set(73)
}
//---------- Function EEPROM Read ---------
void Fnc_Eep_Rd(){
if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
Vfo_Dat = Fnc_Eep_Read(Frq_Eep+Byt_Chn*4);
else{
Vfo_Dat = Fnc_Eep_Read(Frq_Eep+0*4);
Byt_Chn = 0;
}
if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
Enc_Stp = Fnc_Eep_Read(Stp_Eep+Byt_Chn*4);
else
Enc_Stp = Fnc_Eep_Read(Stp_Eep+0*4);
Byt_Vfo = EEPROM.read(Vfo_Eep);
}
//---------- Function EEPROM Write ---------
void Fnc_Eep_Wt(byte chn){
if((0 <= chn) && (chn < Max_Chn)){
Fnc_Eep_Write(Vfo_Dat,Frq_Eep+chn*4);
Fnc_Eep_Write(Enc_Stp,Stp_Eep+chn*4);
}
EEPROM.write(Chn_Eep,chn);
}
//---------- Function Band ---------
void Fnc_Band(){
if((Vfo_Dat >= LW_VFO80) && (Vfo_Dat <= HI_VFO80)){ // 3.5MHz
Flg_Mode = 0; // LSB(0=LSB, 1=USB)
Flg_Over = 0;
}
else if((Vfo_Dat >= LW_VFO40) && (Vfo_Dat <= HI_VFO40)){ // 7MHz
Flg_Mode = 0; // LSB(0=LSB, 1=USB)
Flg_Over = 0;
}
else if((Vfo_Dat >= LW_VFO20) && (Vfo_Dat <= HI_VFO20)){ // 14MHz
Flg_Mode = 1; // USB(0=LSB, 1=USB)
Flg_Over = 0;
}
else if((Vfo_Dat >= LW_VFO15) && (Vfo_Dat <= HI_VFO15)){ // 21MHz
Flg_Mode = 1; // USB(0=LSB, 1=USB)
Flg_Over = 0;
}
else if((Vfo_Dat >= LW_VFO10) && (Vfo_Dat <= HI_VFO10)){ // 28MHz
Flg_Mode = 1; // USB(0=LSB, 1=USB)
Flg_Over = 0;
}
else if((Vfo_Dat >= LW_VFO6) && (Vfo_Dat <= HI_VFO6)){ // 50MHz
Flg_Mode = 1; // USB(0=LSB, 1=USB)
Flg_Over = 0;
}
else
Flg_Over = -1;
}