パラメータの変更は、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);
}
2 件のコメント:
JF1PTLさん
DDSには、最少STEP10HZのため1HZ台表示を0HZ以外表示しない筈です。Arduino IDEのバグ(1.6.Xは誤表示する事が有ります)での誤表示または、何か他の変数を表示させているのかも知れません。LCD接続は、パラレルのみ試験済みです。I2CのLCD接続は、未確認なので判りません。
DDSなしで試験しましたが、誤表示なし。未確認であったI2Cも、DDS有り/無しで確認しましたが問題ありません。
コメントを投稿