周波数カウンタでCLK0出力周波数を表示している様子。
無線機の製作記録の全てを公開してます。 https://sites.google.com/view/ja2gqpから必要なファイルをダウンロードできます。 このBlogは、詳細な説明は一切行っておらず、ある程度のスキルが要求されます。 質問に応じますが、カスタマイズは対応しません。尚、コメントは誰でも出来る様に変更しました。
2017年11月27日月曜日
stm32版si5351a VFO周波数校正
9月にsi5351a VFOに周波数校正機能を追加したが、機能をTwitterで紹介した程度であったので、機能説明をする。周波数校正機能の起動は、RITスイッチを約1秒長押する。周波数カウンタをCLK0周波数が10MHzとなる様、エンコーダで調整する。(LCDは、基準水晶発振子の周波数表示。)調整後、 再びRITスイッチを約1秒長押しすると疑似EEPROMに書き込まれる。
周波数カウンタでCLK0出力周波数を表示している様子。
周波数カウンタでCLK0出力周波数を表示している様子。
2017年11月2日木曜日
7.2MHz Knobless Wonder Filter
自作仲間JA2NKD 、JH8SST/7、Kさん でKnobless Wonderを試験している。ここで問題になっているのは、水晶発振子である。価格が安く、多く流通している物が使えれば好ましい。Knobless Wonderサイト、Knobless Wonderサイトに7.2MHz水晶発振子の紹介がある。そこで、日本国内で7.2MHz水晶発振子を使う場合、オフバンドが危惧されるので、バンド内に収まる様なフィルタを試験した。
試験した回路図である。7.2MHz以下に収める必要があるので、多少余裕を見てこの定数とした。試験回路をユニバーサル基板で作った。
FRMSで抵抗マッチング(680Ω)により測定した。一般的に-3dBにおける帯域幅をフィルタ帯域と言っているが、4ポールのシャープファクタの低いフィルタの為、-20dB(一般的なキャリアポイントの位置)でフィルタ定数を決めた。
cf(中心周波数) 7.1979MHz
cp(LSBキャリアポイント)7.1990MHz
試作した結果から、7.2MHzの水晶発振子をフィルタとして使える。ただし、最終的な回路を組み立て、実機検証する必要がある。
試験した回路図である。7.2MHz以下に収める必要があるので、多少余裕を見てこの定数とした。試験回路をユニバーサル基板で作った。
cf(中心周波数) 7.1979MHz
cp(LSBキャリアポイント)7.1990MHz
試作した結果から、7.2MHzの水晶発振子をフィルタとして使える。ただし、最終的な回路を組み立て、実機検証する必要がある。
参考データ
コンデンサを47pとした場合のデータである。今後の課題
ユニバーサル基板で試作した為、リード線の浮遊容量が大きい。この回路方式の場合、浮遊インダクタンスの影響を大きく受けるので、最終的な姿で回路定数を決め検証する。2017年9月16日土曜日
stm32 si5351a VFO(With BFO)
このVFOは、JA2NKD OMのマルチバンドVFO にBFOを付加した物で、stm32F103c8t6+si5351aで構成している。特徴は、BFOが簡単に変更出来る様にした事と、光学エンコーダの採用でアナログ感覚のVFO操作である。BFO変更は、Modeスイッチを長押し(約1秒間スイッチを押す)エンコーダで周波数を調整後、再び、Modeスイッチを長押し(約1秒間)で書換を行う。
光学エンコーダは、中華製400P/R($10位)を使ったため、エンコーダのコントロールSTEPは、1Hz、10Hz、100Hzにした。
回路図である。光学エンコーダの電源は省略してある。stm32への書込みは、シリアルとした。理由は、省メモリとシリアルモニタが使える環境にした。開発環境にST-LINK V2を使った場合、I/O割付に制限がある様なので変更(9/17)した。
///////////////////////////////////////////////////////////////////////////////////
// stm32 + si5351a VFO(With BFO) Ver1.01
// (Based on 'JAN2KD 2016.10.19 Multi Band DDS VFO Ver3.1')
//
// 2017/9/16
// JA2GQP
///////////////////////////////////////////////////////////////////////////////////
//---------- Library include ----------
#include "si5351a2.h"
#include <SPI.h>
#include <EEPROM.h>
#include <Rotary.h>
#include "src/Ucglib.h"
//---------- Encorder setting ---------------
#define ENC_A PB12 // Rotary encoder A
#define ENC_B PB13 // Rotary encoder B
Rotary r=Rotary(ENC_A,ENC_B);
//---------- TFT setting -------------------
#define __CS PB10 // CS
#define __DC PB0 // D/C
#define __RST PB1 // RESET
Ucglib_ILI9341_18x240x320_HWSPI ucg(__DC, __CS, __RST);
//---------- CW Tone -------------------
#define CW_TONE 700 // 700Hz
//---------- I/O Assign -------------------
#define MODE_OUT1 PB15 // 2017/9/17
#define MODE_OUT2 PA8 // 2017/9/17
#define BAND_OUT1 PB3
#define BAND_OUT2 PB4
#define BAND_OUT3 PB5
#define SW_BAND PA0
#define SW_MODE PC14
#define SW_STEP PB14
#define SW_RIT PC15
#define SW_TX PC13
#define METER PA1
#define EEP_BAND 0x00 // EEPROM BAND Adress
#define EEP_INIT 0x0e // INIT end Adress
//---------- Variable setting ----------
long romf[4]; // EEPROM freq copy buffer
long freq = 7100000;
long freqmax = 7200000;
long freqmin = 7000000;
long freqold = 0;
long freqrit = 0;
String freqt=String(freq); // Frequency text
long ifshift = 0;
long ifshiftb;
long romb[5]; // EEPROM bfo copy buffer
long vfofreq = 0;
long vfofreqb;
char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;
int rit = 0;
int fstep = 100;
uint16 steprom = 1;
uint16 fmode = 3;
uint16 fmodeb = 3;
int fmodeold = 1;
int flagrit = 0;
int fritold = 0;
int flagmode = 0;
int meterval1 = 0;
int tmeterval = 0;
int romadd = 0;
int rombadd = 0;
int analogdata = 0;
uint16 band = 0; // 3.5MHz
int bandmax = 6; // 6band
uint16 Status;
uint16 Data;
unsigned long eep_freq[4];
int eep_romadd;
int eep_fstep;
int eep_fmode;
unsigned long eep_bfo[6];
int eep_rombadd;
int_fast32_t timepassed; // int to hold the arduino miilis since startup
int flg_frqwt = 0; // Frequency data Wite Flag(EEPROM)
int flg_bfowt = 0; // BFO Wite Flag(EEPROM)
int flg_bfochg = 0; // BFO Wite Flag(EEPROM)
//---------- Initialization Program ----------------------
void setup() {
timepassed = millis();
afio_cfg_debug_ports(AFIO_DEBUG_NONE); // ST-LINK(PB3,PB4,PA15,PA12,PA11) Can be used
Wire.begin();
pinMode( ENC_A,INPUT_PULLUP); // PC13 pull up
pinMode( ENC_B,INPUT_PULLUP); // PC14
attachInterrupt( ENC_A, Rotaly_enc, CHANGE); // Encorder A
attachInterrupt( ENC_B, Rotaly_enc, CHANGE); // B
delay(100);
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.clearScreen();
ucg.setRotate270();
pinMode(SW_BAND,INPUT_PULLUP);
pinMode(SW_MODE,INPUT_PULLUP);
pinMode(SW_STEP,INPUT_PULLUP);
pinMode(SW_RIT,INPUT_PULLUP);
pinMode(SW_TX,INPUT_PULLUP);
pinMode(ENC_A,INPUT_PULLUP); // pull up encorede A
pinMode(ENC_B,INPUT_PULLUP); // encorder B
pinMode (BAND_OUT1,OUTPUT);
pinMode (BAND_OUT2,OUTPUT);
pinMode (BAND_OUT3,OUTPUT);
pinMode(SW_TX,INPUT_PULLUP);
pinMode(MODE_OUT1,OUTPUT);
pinMode(MODE_OUT2,OUTPUT);
Fnc_eepINIT();
delay(100);
band2eep();
delay(100);
Status = EEPROM.read(EEP_BAND,&band); // EEPROM read(frequency)
romadd=0x010+(band*0x10);
for (int i=0; i<3;i++){
romf[i]=Fnc_eepRD((romadd+4*i));
}
freq = romf[0];
freqmin = romf[1];
freqmax = romf[2];
Status = EEPROM.read(romadd+12,&fmode);
Status = EEPROM.read(romadd+14,&steprom);
eep_rombadd=0x090; // EEPROM read(BFO)
for (int i=0; i<4;i++){
romb[i]=Fnc_eepRD((eep_rombadd+(4*i)));
eep_bfo[i] = romb[i];
}
if (steprom==1){fstep=1;} // STEP set
if (steprom==2){fstep=10;}
if (steprom==3){fstep=100;}
banddataout();
screen01();
chlcd();
modeset();
steplcd();
freqt=String(freq);
freqlcd();
}
//---------- Main program ---------------------------------
void loop() {
if(digitalRead(SW_STEP) == LOW) // STEP sw check
setstep();
else if(digitalRead(SW_MODE) == LOW) // MODE sw check
modesw();
else if(digitalRead(SW_RIT) == LOW) // RIT sw check
setrit();
else if(digitalRead(SW_BAND) == LOW) // BAND sw check
bandcall();
if (digitalRead(SW_TX)==LOW) // TX sw check
txset();
if (flagrit==1){
if (freqrit == fritold){
meter();
}
if (freqrit!=fritold){
PLL_write();
ritlcd();
fritold=freqrit;
}
}
else{
if (freq == freqold){
meter();
}
PLL_write();
freqt=String(freq);
freqlcd();
freqold=freq;
}
if((flg_frqwt == 1) && (flg_bfochg == 0)){ // EEPROM auto save 2sec
if(timepassed+1000 < millis()){
bandwrite();
flg_frqwt = 0;
}
}
}
//---------- EEPROM Data initialization ---------------
void band2eep(){
Status = EEPROM.read(EEP_INIT,&Data);
if(Data != 73){ // Iinitialization check
Status = EEPROM.write(EEP_BAND,1);
eep_romadd=0x010; // BAND:0 ROMadd:0x010
eep_freq[0]=3500000;
eep_freq[1]=3500000;
eep_freq[2]=3800000;
eep_fmode=0;
eep_fstep=2;
band2write();
eep_romadd=0x020; // BAND:1 ROMadd:0x020
eep_freq[0]=7000000;
eep_freq[1]=7000000;
eep_freq[2]=7200000;
eep_fmode=0;
eep_fstep=2;
band2write();
eep_romadd=0x030; // BAND:2 ROMadd:0x030
eep_freq[0]=10100000;
eep_freq[1]=10100000;
eep_freq[2]=10150000;
eep_fmode=2;
eep_fstep=1;
band2write();
eep_romadd=0x040; // BAND:3 ROMadd:0x040
eep_freq[0]=14000000;
eep_freq[1]=14000000;
eep_freq[2]=14350000;
eep_fmode=1;
eep_fstep=2;
band2write();
eep_romadd=0x050; // BAND:4 ROMadd:0x050
eep_freq[0]=21000000;
eep_freq[1]=21000000;
eep_freq[2]=21450000;
eep_fmode=1;
eep_fstep=2;
band2write();
eep_romadd=0x060; // BAND:5 ROMadd:0x060
eep_freq[0]=28000000;
eep_freq[1]=28000000;
eep_freq[2]=29700000;
eep_fmode=1;
eep_fstep=2;
band2write();
eep_rombadd=0x090; // BFO ROMadd:0x090
eep_bfo[0]=7999600; // LSB
eep_bfo[1]=8002600; // USB
eep_bfo[2]=8000400; // CW
eep_bfo[3]=8001100; // AM
for (int i=0;i<4;i++){
Fnc_eepWT(eep_bfo[i],(eep_rombadd+4*i));
}
Status = EEPROM.write(EEP_INIT,73); // Initialyzed End code
}
}
//---------- Function Band Write to EEPROM ---------------
void band2write(){
for (int i=0;i<3;i++){
Fnc_eepWT(eep_freq[i],(eep_romadd+4*i));
}
Status = EEPROM.write(eep_romadd+12,eep_fmode);
Status = EEPROM.write(eep_romadd+14,eep_fstep);
}
//---------- PLL write ---------------------------
void PLL_write(){
if(flg_bfochg == 0){
if (flagrit==0)
vfofreq=freq+ifshift;
else
vfofreq=freq+ifshift+freqrit;
Vfo_out(vfofreq); // DDS out 2016/10/24 JA2GQP
Bfo_out(ifshift); // BFO
}
else{
ifshift = freq;
Bfo_out(ifshift); // BFO
freq = ifshift;
}
}
//---------- VFO out ---------------
void Vfo_out(long frequency){
if(vfofreq != vfofreqb){
si5351aSetFrequency(frequency);
flg_frqwt = 1; // EEP Wite Flag
timepassed = millis();
vfofreqb = vfofreq;
}
}
//---------- BFO out ---------------
void Bfo_out(long frequency){
if(ifshift != ifshiftb){
si5351aSetFrequency2(frequency);
flg_bfowt = 1; // EEP Wite Flag
ifshiftb = ifshift;
}
}
//---------- meter --------------------------
void meter(){
meterval1=analogRead(METER);
// meterval1=meterval1/50; // old
meterval1=meterval1/200;
if (meterval1>15){meterval1=15;}
int sx1=sx1+(meterval1*17);
sx1=sx1+41;
int sx2=0;
sx2=sx2+(40+((15-meterval1)*17));
ucg.setFont(ucg_font_fub35_tr);
ucg.setColor(0,0,0);
ucg.drawBox(sx1,180,sx2,16);
ucg.setPrintPos(40,200);
for(int i=1;i<=meterval1;i++){
if (i<=9){
ucg.setColor(0,255,255);
ucg.print("-");
}
else{
ucg.setColor(255,0,0);
ucg.print("-");
}
}
}
//---------- Encoder Interrupt -----------------------
void Rotaly_enc(){
if (flagrit==1){
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freqrit=freqrit+fstep;
if (freqrit>=10000){
freqrit=10000;
}
}
else{
freqrit=freqrit-fstep;
if (freqrit<=-10000){
freqrit=-10000;
}
}
}
}
else{
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freq=freq+fstep;
if((flg_bfochg == 0) && (freq>=freqmax)){freq=freqmax;}
}
else{
freq=freq-fstep;
if((flg_bfochg == 0) && (freq<=freqmin)){freq=freqmin;}
}
}
}
}
//------------ On Air -----------------------------
void txset(){
if(fmode == 2) // CW?
Vfo_out(vfofreq + CW_TONE); // Vfofreq+700Hz
else
Vfo_out(vfofreq); // vfo out
ucg.setPrintPos(110,140);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,0,0);
ucg.print("ON AIR");
while(digitalRead(SW_TX) == LOW){
meter();
}
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(0,0,0);
ucg.drawBox(100,120,250,30); //45
}
//------------- Mode set(LSB-USB-CW-AM) ------------
void modeset(){
ucg.setFont(ucg_font_fub17_tr);
ucg.setPrintPos(82,82);
ucg.setColor(0,0,0);
ucg.print("USB");
ucg.setPrintPos(12,82);
ucg.print("LSB");
ucg.setPrintPos(82,112);
ucg.print("A M");
ucg.setPrintPos(12,112);
ucg.print("C W");
switch(fmode){
case 0: // LSB
ifshift = eep_bfo[0];
ucg.setPrintPos(12,82);
ucg.setColor(255,255,0);
ucg.print("LSB");
digitalWrite(MODE_OUT1,LOW);
digitalWrite(MODE_OUT2,LOW);
break;
case 1: // USB
ifshift = eep_bfo[1];
ucg.setColor(255,255,0);
ucg.setPrintPos(82,82);
ucg.print("USB");
digitalWrite(MODE_OUT1,HIGH);
digitalWrite(MODE_OUT2,LOW);
break;
case 2: // CW
ifshift = eep_bfo[2];
ucg.setPrintPos(12,112);
ucg.setColor(255,255,0);
ucg.print("C W");
digitalWrite(MODE_OUT1,LOW);
digitalWrite(MODE_OUT2,HIGH);
break;
case 3: // AM
ifshift = eep_bfo[3];
ucg.setPrintPos(82,112);
ucg.setColor(255,255,0);
ucg.print("A M");
digitalWrite(MODE_OUT1,HIGH);
digitalWrite(MODE_OUT2,HIGH);
break;
default:
ifshift = eep_bfo[0];
ucg.setPrintPos(12,82);
ucg.setColor(255,255,0);
ucg.print("LSB");
digitalWrite(MODE_OUT1,LOW);
digitalWrite(MODE_OUT2,LOW);
fmode = 0;
break;
}
}
//------------- Mode set SW ------------
void modesw(){
int cnt = 0;
if(flg_bfochg == 0){
while(digitalRead(SW_MODE) == LOW){
delay(100);
cnt++;
if(10 <= cnt){ // BFO data change mode(1sec)
romadd=0x010+(band*0x10);
romf[0]=Fnc_eepRD(romadd);
freq = Fnc_eepRD(0x090+(fmode * 4));
freqt=String(freq);
freqlcd();
ucg.setPrintPos(110,140);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,255,0);
ucg.print("BFO ADJ");
fmodeb = fmode;
flg_bfochg = 1;
break;
}
}
}
else{
while(digitalRead(SW_MODE) == LOW){
delay(100);
cnt++;
if(10 <= cnt){ // BFO data update(1sec)
ifshift = freq;
Fnc_eepWT(ifshift,0x090+(fmode * 4)); // data write
eep_bfo[fmode] = ifshift;
freq = romf[0];
freqt=String(freq);
freqlcd();
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(0,0,0);
ucg.drawBox(100,120,250,30); //45
flg_bfochg = 0;
fmode--;
break;
}
}
}
if(flg_bfochg == 0)
fmode++;
modeset();
PLL_write();
while(digitalRead(SW_MODE) == LOW);
}
//------------ Rit SET ------------------------------
void setrit(){
if(flagrit==0){
flagrit=1;
ucg.setFont(ucg_font_fub11_tr);
ucg.setPrintPos(190,110);
ucg.setColor(255,0,0);
ucg.print("RIT");
ritlcd();
}
else {
flagrit=0;
vfofreq=freq+ifshift;
Vfo_out(vfofreq); // DDS Out 2016/10/23 JA2GQP
freqt=String(freq);
ucg.setFont(ucg_font_fub11_tr);
ucg.setPrintPos(190,110);
ucg.setColor(255,255,255);
ucg.print("RIT");
ucg.setColor(0,0,0);
ucg.drawRBox(222,92,91,21,3);
freqrit=0;
}
while(digitalRead(SW_RIT) == LOW);
}
//----------- Rit screen ----------------------
void ritlcd(){
ucg.setColor(0,0,0);
ucg.drawBox(222,92,91,21);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,255,255);
ucg.setPrintPos(230,110);
ucg.print(freqrit);
}
//-------------- encorder frequency step set -----------
void setstep(){
if (fstep==100){
fstep=1;
}
else{
fstep=fstep * 10;
}
steplcd();
while(digitalRead(SW_STEP) == LOW);
}
//------------- Step Screen ---------------------------
void steplcd(){
ucg.setColor(0,0,0);
ucg.drawRBox(221,61,93,23,3);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,255,255);
ucg.setPrintPos(220,80);
if (fstep==1){ucg.print(" 1Hz");}
if (fstep==10){ucg.print(" 10Hz");}
if (fstep==100){ucg.print(" 100Hz");}
}
//----------- Main frequency screen -------------------
void freqlcd(){
ucg.setFont(ucg_font_fub35_tn);
int mojisuu=(freqt.length());
if(freq<100){
ucg.setColor(0,0,0);
ucg.drawBox(217,9,28,36);
}
if(f10 !=(freqt.charAt(mojisuu-2))){
ucg.setColor(0,0,0);
ucg.drawBox(245,9,28,36);
ucg.setPrintPos(245,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-2));
f10 = (freqt.charAt(mojisuu-2));
}
if(freq<10){
ucg.setColor(0,0,0);
ucg.drawBox(245,9,28,36);
}
if(f1 !=(freqt.charAt(mojisuu-1))){
ucg.setColor(0,0,0);
ucg.drawBox(273,9,28,36);
ucg.setPrintPos(273,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-1));
f1 = (freqt.charAt(mojisuu-1));
}
if(freq<1000){
ucg.setColor(0,0,0);
ucg.drawBox(202,9,15,36);
}
if(f100 !=(freqt.charAt(mojisuu-3))){
ucg.setColor(0,0,0);
ucg.drawBox(217,9,28,36);
ucg.setPrintPos(217,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-3));
f100 = (freqt.charAt(mojisuu-3));
}
if(freq>=1000){
ucg.setPrintPos(202,45);
ucg.setColor(0,255,0);
ucg.print(".");
}
if(freq<10000){
ucg.setColor(0,0,0);
ucg.drawBox(146,9,28,36);
}
if(f1k !=(freqt.charAt(mojisuu-4))){
ucg.setColor(0,0,0);
ucg.drawBox(174,9,28,36);
ucg.setPrintPos(174,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-4));
f1k = (freqt.charAt(mojisuu-4));
}
if(freq<100000){
ucg.setColor(0,0,0);
ucg.drawBox(118,9,28,36);
}
if(f10k !=(freqt.charAt(mojisuu-5))){
ucg.setColor(0,0,0);
ucg.drawBox(146,9,28,36);
ucg.setPrintPos(146,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-5));
f10k = (freqt.charAt(mojisuu-5));
}
if(freq<1000000){
ucg.setColor(0,0,0);
ucg.drawBox(103,9,15,36);
}
if(f100k !=(freqt.charAt(mojisuu-6))){
ucg.setColor(0,0,0);
ucg.drawBox(118,9,28,36);
ucg.setPrintPos(118,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-6));
f100k = (freqt.charAt(mojisuu-6));
}
if(freq>=1000000){
ucg.setPrintPos(103,45);
ucg.setColor(0,255,0);
ucg.print(".");
}
if(freq<10000000){
ucg.setColor(0,0,0);
ucg.drawBox(47,9,28,36);
}
if(fmega !=(freqt.charAt(mojisuu-7))){
ucg.setColor(0,0,0);
ucg.drawBox(75,9,28,36);
ucg .setPrintPos(75,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-7));
fmega = (freqt.charAt(mojisuu-7));
}
if(freq<100000000){
ucg.setColor(0,0,0);
ucg.drawBox(19,9,28,36);
}
if (f10m !=(freqt.charAt(mojisuu-8))){
ucg.setColor(0,0,0);
ucg.drawBox(47,9,28,36);
ucg .setPrintPos(47,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-8));
f10m = (freqt.charAt(mojisuu-8));
}
}
//----------- Basic Screen -------------------------
void screen01(){
ucg.setColor(255,255,255);
ucg.drawRFrame(1,1,314,55,5);
ucg.drawRFrame(2,2,312,53,5);
ucg.setColor(50,50,50);
ucg.drawRBox(5,60,60,25,3);
ucg.drawRBox(75,60,60,25,3);
ucg.drawRBox(5,90,60,25,3);
ucg.drawRBox(75,90,60,25,3);
ucg.setFont(ucg_font_fub17_tr);
ucg.setPrintPos(12,82);
ucg.setColor(0,0,0);
ucg.print("LSB");
ucg.setPrintPos(82,82);
ucg.print("USB");
ucg.setPrintPos(12,112);
ucg.print("C W");
ucg.setPrintPos(82,112);
ucg.print("A M");
ucg.setColor(255,255,255);
ucg.drawRFrame(220,60,95,25,3);
ucg.drawRFrame(220,90,95,25,3);
ucg.setFont(ucg_font_fub11_tr);
ucg.setColor(255,255,255);
ucg.setPrintPos(175,80);
ucg.print("STEP");
ucg.setPrintPos(190,110);
ucg.setColor(255,255,255);
ucg.print("RIT");
ucg.setColor(100,100,100);
ucg.setPrintPos(10,210);
ucg.print(" S: 1-----3-------6-------9---Over--------");
ucg.setPrintPos(10,177);
ucg.print(" P: 1-----3-----5-----------10--------------");
ucg.setPrintPos(10,230);
ucg.setColor(235,0,200);
ucg.print( "stm32 VFO(with BFO) Ver1.0 JA2GQP");
ucg.setFont(ucg_font_fub35_tr);
ucg.setColor(0,255,0);
ucg.setPrintPos(273,45);
ucg.print("0");
}
//---------- Band data call from eeprom ----------
void bandcall(){
band=band+1;
if (band>(bandmax-1)){band=0;}
romadd=0x010+(band*0x010);
for (int i=0; i<3;i++){
romf[i]=Fnc_eepRD((romadd+4*i));
}
freq = romf[0];
freqmin = romf[1];
freqmax = romf[2];
Status = EEPROM.read(romadd+12,&fmode);
Status = EEPROM.read(romadd+14,&steprom);
if (steprom==1){fstep=1;}
if (steprom==2){fstep=10;}
if (steprom==3){fstep=100;}
modeset();
steplcd();
freqt=String(freq);
freqlcd();
banddataout();
chlcd();
while(digitalRead(SW_BAND) == LOW);
}
//---------- Band data write to eeprom ----------
void bandwrite(){
romadd=0x010+(band*0x010);
Fnc_eepWT(freq,romadd);
Status = EEPROM.write(EEP_BAND,band);
Status = EEPROM.write(romadd+12,fmode);
if (fstep==1){steprom=1;}
if (fstep==10){steprom=2;}
if (fstep==100){steprom=3;}
Status = EEPROM.write(romadd+14,steprom);
}
//---------- 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);
}
//---------- Band data output I/O ----------
void banddataout(){
digitalWrite(BAND_OUT1,LOW);
digitalWrite(BAND_OUT2,LOW);
digitalWrite(BAND_OUT3,LOW);
if (band==0){}
if (band==1){
digitalWrite( BAND_OUT1,HIGH);
}
if (band==2){
digitalWrite(BAND_OUT2,HIGH);
}
if (band==3){
digitalWrite(BAND_OUT1,HIGH);
digitalWrite(BAND_OUT2,HIGH);
}
if (band==4){
digitalWrite(BAND_OUT3,HIGH);
}
if (band==5){
digitalWrite(BAND_OUT1,HIGH);
digitalWrite(BAND_OUT3,HIGH);
}
if (band==6){
digitalWrite(BAND_OUT2,HIGH);
digitalWrite(BAND_OUT3,HIGH);
}
if (band==7){
digitalWrite(BAND_OUT1,HIGH);
digitalWrite(BAND_OUT2,HIGH);
digitalWrite(BAND_OUT3,HIGH);
}
}
//---------- Band No.(Chanel No.) write to LCD ----------
void chlcd(){
ucg.setColor(0,0,0);
ucg.drawBox(5,120,80,20);
ucg.setFont(ucg_font_fub11_tr);
ucg.setPrintPos(12,137);
ucg.setColor(255,255,255);
ucg.print("CH: ");
ucg.print(band+1);
}
光学エンコーダは、中華製400P/R($10位)を使ったため、エンコーダのコントロールSTEPは、1Hz、10Hz、100Hzにした。
スケッチ
JA2NKD OMのオリジナルVFOは、max 8 Bandであるが6 Bandに変更している。VFO周波数は、周波数変化が2秒以上なければ、疑似EEPROMに保存する機能を追加した。si5351a2.hは、オリジナルの物を使っている。ただ、Ucglib.hは私のPC環境で複数のライブラリが参照されるため、参照場所の明確化をした。スケッチと関係ファイルは、download siteのstm32フォルダからダウンロード可能。///////////////////////////////////////////////////////////////////////////////////
// stm32 + si5351a VFO(With BFO) Ver1.01
// (Based on 'JAN2KD 2016.10.19 Multi Band DDS VFO Ver3.1')
//
// 2017/9/16
// JA2GQP
///////////////////////////////////////////////////////////////////////////////////
//---------- Library include ----------
#include "si5351a2.h"
#include <SPI.h>
#include <EEPROM.h>
#include <Rotary.h>
#include "src/Ucglib.h"
//---------- Encorder setting ---------------
#define ENC_A PB12 // Rotary encoder A
#define ENC_B PB13 // Rotary encoder B
Rotary r=Rotary(ENC_A,ENC_B);
//---------- TFT setting -------------------
#define __CS PB10 // CS
#define __DC PB0 // D/C
#define __RST PB1 // RESET
Ucglib_ILI9341_18x240x320_HWSPI ucg(__DC, __CS, __RST);
//---------- CW Tone -------------------
#define CW_TONE 700 // 700Hz
//---------- I/O Assign -------------------
#define MODE_OUT1 PB15 // 2017/9/17
#define MODE_OUT2 PA8 // 2017/9/17
#define BAND_OUT1 PB3
#define BAND_OUT2 PB4
#define BAND_OUT3 PB5
#define SW_BAND PA0
#define SW_MODE PC14
#define SW_STEP PB14
#define SW_RIT PC15
#define SW_TX PC13
#define METER PA1
#define EEP_BAND 0x00 // EEPROM BAND Adress
#define EEP_INIT 0x0e // INIT end Adress
//---------- Variable setting ----------
long romf[4]; // EEPROM freq copy buffer
long freq = 7100000;
long freqmax = 7200000;
long freqmin = 7000000;
long freqold = 0;
long freqrit = 0;
String freqt=String(freq); // Frequency text
long ifshift = 0;
long ifshiftb;
long romb[5]; // EEPROM bfo copy buffer
long vfofreq = 0;
long vfofreqb;
char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;
int rit = 0;
int fstep = 100;
uint16 steprom = 1;
uint16 fmode = 3;
uint16 fmodeb = 3;
int fmodeold = 1;
int flagrit = 0;
int fritold = 0;
int flagmode = 0;
int meterval1 = 0;
int tmeterval = 0;
int romadd = 0;
int rombadd = 0;
int analogdata = 0;
uint16 band = 0; // 3.5MHz
int bandmax = 6; // 6band
uint16 Status;
uint16 Data;
unsigned long eep_freq[4];
int eep_romadd;
int eep_fstep;
int eep_fmode;
unsigned long eep_bfo[6];
int eep_rombadd;
int_fast32_t timepassed; // int to hold the arduino miilis since startup
int flg_frqwt = 0; // Frequency data Wite Flag(EEPROM)
int flg_bfowt = 0; // BFO Wite Flag(EEPROM)
int flg_bfochg = 0; // BFO Wite Flag(EEPROM)
//---------- Initialization Program ----------------------
void setup() {
timepassed = millis();
afio_cfg_debug_ports(AFIO_DEBUG_NONE); // ST-LINK(PB3,PB4,PA15,PA12,PA11) Can be used
Wire.begin();
pinMode( ENC_A,INPUT_PULLUP); // PC13 pull up
pinMode( ENC_B,INPUT_PULLUP); // PC14
attachInterrupt( ENC_A, Rotaly_enc, CHANGE); // Encorder A
attachInterrupt( ENC_B, Rotaly_enc, CHANGE); // B
delay(100);
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.clearScreen();
ucg.setRotate270();
pinMode(SW_BAND,INPUT_PULLUP);
pinMode(SW_MODE,INPUT_PULLUP);
pinMode(SW_STEP,INPUT_PULLUP);
pinMode(SW_RIT,INPUT_PULLUP);
pinMode(SW_TX,INPUT_PULLUP);
pinMode(ENC_A,INPUT_PULLUP); // pull up encorede A
pinMode(ENC_B,INPUT_PULLUP); // encorder B
pinMode (BAND_OUT1,OUTPUT);
pinMode (BAND_OUT2,OUTPUT);
pinMode (BAND_OUT3,OUTPUT);
pinMode(SW_TX,INPUT_PULLUP);
pinMode(MODE_OUT1,OUTPUT);
pinMode(MODE_OUT2,OUTPUT);
Fnc_eepINIT();
delay(100);
band2eep();
delay(100);
Status = EEPROM.read(EEP_BAND,&band); // EEPROM read(frequency)
romadd=0x010+(band*0x10);
for (int i=0; i<3;i++){
romf[i]=Fnc_eepRD((romadd+4*i));
}
freq = romf[0];
freqmin = romf[1];
freqmax = romf[2];
Status = EEPROM.read(romadd+12,&fmode);
Status = EEPROM.read(romadd+14,&steprom);
eep_rombadd=0x090; // EEPROM read(BFO)
for (int i=0; i<4;i++){
romb[i]=Fnc_eepRD((eep_rombadd+(4*i)));
eep_bfo[i] = romb[i];
}
if (steprom==1){fstep=1;} // STEP set
if (steprom==2){fstep=10;}
if (steprom==3){fstep=100;}
banddataout();
screen01();
chlcd();
modeset();
steplcd();
freqt=String(freq);
freqlcd();
}
//---------- Main program ---------------------------------
void loop() {
if(digitalRead(SW_STEP) == LOW) // STEP sw check
setstep();
else if(digitalRead(SW_MODE) == LOW) // MODE sw check
modesw();
else if(digitalRead(SW_RIT) == LOW) // RIT sw check
setrit();
else if(digitalRead(SW_BAND) == LOW) // BAND sw check
bandcall();
if (digitalRead(SW_TX)==LOW) // TX sw check
txset();
if (flagrit==1){
if (freqrit == fritold){
meter();
}
if (freqrit!=fritold){
PLL_write();
ritlcd();
fritold=freqrit;
}
}
else{
if (freq == freqold){
meter();
}
PLL_write();
freqt=String(freq);
freqlcd();
freqold=freq;
}
if((flg_frqwt == 1) && (flg_bfochg == 0)){ // EEPROM auto save 2sec
if(timepassed+1000 < millis()){
bandwrite();
flg_frqwt = 0;
}
}
}
//---------- EEPROM Data initialization ---------------
void band2eep(){
Status = EEPROM.read(EEP_INIT,&Data);
if(Data != 73){ // Iinitialization check
Status = EEPROM.write(EEP_BAND,1);
eep_romadd=0x010; // BAND:0 ROMadd:0x010
eep_freq[0]=3500000;
eep_freq[1]=3500000;
eep_freq[2]=3800000;
eep_fmode=0;
eep_fstep=2;
band2write();
eep_romadd=0x020; // BAND:1 ROMadd:0x020
eep_freq[0]=7000000;
eep_freq[1]=7000000;
eep_freq[2]=7200000;
eep_fmode=0;
eep_fstep=2;
band2write();
eep_romadd=0x030; // BAND:2 ROMadd:0x030
eep_freq[0]=10100000;
eep_freq[1]=10100000;
eep_freq[2]=10150000;
eep_fmode=2;
eep_fstep=1;
band2write();
eep_romadd=0x040; // BAND:3 ROMadd:0x040
eep_freq[0]=14000000;
eep_freq[1]=14000000;
eep_freq[2]=14350000;
eep_fmode=1;
eep_fstep=2;
band2write();
eep_romadd=0x050; // BAND:4 ROMadd:0x050
eep_freq[0]=21000000;
eep_freq[1]=21000000;
eep_freq[2]=21450000;
eep_fmode=1;
eep_fstep=2;
band2write();
eep_romadd=0x060; // BAND:5 ROMadd:0x060
eep_freq[0]=28000000;
eep_freq[1]=28000000;
eep_freq[2]=29700000;
eep_fmode=1;
eep_fstep=2;
band2write();
eep_rombadd=0x090; // BFO ROMadd:0x090
eep_bfo[0]=7999600; // LSB
eep_bfo[1]=8002600; // USB
eep_bfo[2]=8000400; // CW
eep_bfo[3]=8001100; // AM
for (int i=0;i<4;i++){
Fnc_eepWT(eep_bfo[i],(eep_rombadd+4*i));
}
Status = EEPROM.write(EEP_INIT,73); // Initialyzed End code
}
}
//---------- Function Band Write to EEPROM ---------------
void band2write(){
for (int i=0;i<3;i++){
Fnc_eepWT(eep_freq[i],(eep_romadd+4*i));
}
Status = EEPROM.write(eep_romadd+12,eep_fmode);
Status = EEPROM.write(eep_romadd+14,eep_fstep);
}
//---------- PLL write ---------------------------
void PLL_write(){
if(flg_bfochg == 0){
if (flagrit==0)
vfofreq=freq+ifshift;
else
vfofreq=freq+ifshift+freqrit;
Vfo_out(vfofreq); // DDS out 2016/10/24 JA2GQP
Bfo_out(ifshift); // BFO
}
else{
ifshift = freq;
Bfo_out(ifshift); // BFO
freq = ifshift;
}
}
//---------- VFO out ---------------
void Vfo_out(long frequency){
if(vfofreq != vfofreqb){
si5351aSetFrequency(frequency);
flg_frqwt = 1; // EEP Wite Flag
timepassed = millis();
vfofreqb = vfofreq;
}
}
//---------- BFO out ---------------
void Bfo_out(long frequency){
if(ifshift != ifshiftb){
si5351aSetFrequency2(frequency);
flg_bfowt = 1; // EEP Wite Flag
ifshiftb = ifshift;
}
}
//---------- meter --------------------------
void meter(){
meterval1=analogRead(METER);
// meterval1=meterval1/50; // old
meterval1=meterval1/200;
if (meterval1>15){meterval1=15;}
int sx1=sx1+(meterval1*17);
sx1=sx1+41;
int sx2=0;
sx2=sx2+(40+((15-meterval1)*17));
ucg.setFont(ucg_font_fub35_tr);
ucg.setColor(0,0,0);
ucg.drawBox(sx1,180,sx2,16);
ucg.setPrintPos(40,200);
for(int i=1;i<=meterval1;i++){
if (i<=9){
ucg.setColor(0,255,255);
ucg.print("-");
}
else{
ucg.setColor(255,0,0);
ucg.print("-");
}
}
}
//---------- Encoder Interrupt -----------------------
void Rotaly_enc(){
if (flagrit==1){
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freqrit=freqrit+fstep;
if (freqrit>=10000){
freqrit=10000;
}
}
else{
freqrit=freqrit-fstep;
if (freqrit<=-10000){
freqrit=-10000;
}
}
}
}
else{
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freq=freq+fstep;
if((flg_bfochg == 0) && (freq>=freqmax)){freq=freqmax;}
}
else{
freq=freq-fstep;
if((flg_bfochg == 0) && (freq<=freqmin)){freq=freqmin;}
}
}
}
}
//------------ On Air -----------------------------
void txset(){
if(fmode == 2) // CW?
Vfo_out(vfofreq + CW_TONE); // Vfofreq+700Hz
else
Vfo_out(vfofreq); // vfo out
ucg.setPrintPos(110,140);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,0,0);
ucg.print("ON AIR");
while(digitalRead(SW_TX) == LOW){
meter();
}
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(0,0,0);
ucg.drawBox(100,120,250,30); //45
}
//------------- Mode set(LSB-USB-CW-AM) ------------
void modeset(){
ucg.setFont(ucg_font_fub17_tr);
ucg.setPrintPos(82,82);
ucg.setColor(0,0,0);
ucg.print("USB");
ucg.setPrintPos(12,82);
ucg.print("LSB");
ucg.setPrintPos(82,112);
ucg.print("A M");
ucg.setPrintPos(12,112);
ucg.print("C W");
switch(fmode){
case 0: // LSB
ifshift = eep_bfo[0];
ucg.setPrintPos(12,82);
ucg.setColor(255,255,0);
ucg.print("LSB");
digitalWrite(MODE_OUT1,LOW);
digitalWrite(MODE_OUT2,LOW);
break;
case 1: // USB
ifshift = eep_bfo[1];
ucg.setColor(255,255,0);
ucg.setPrintPos(82,82);
ucg.print("USB");
digitalWrite(MODE_OUT1,HIGH);
digitalWrite(MODE_OUT2,LOW);
break;
case 2: // CW
ifshift = eep_bfo[2];
ucg.setPrintPos(12,112);
ucg.setColor(255,255,0);
ucg.print("C W");
digitalWrite(MODE_OUT1,LOW);
digitalWrite(MODE_OUT2,HIGH);
break;
case 3: // AM
ifshift = eep_bfo[3];
ucg.setPrintPos(82,112);
ucg.setColor(255,255,0);
ucg.print("A M");
digitalWrite(MODE_OUT1,HIGH);
digitalWrite(MODE_OUT2,HIGH);
break;
default:
ifshift = eep_bfo[0];
ucg.setPrintPos(12,82);
ucg.setColor(255,255,0);
ucg.print("LSB");
digitalWrite(MODE_OUT1,LOW);
digitalWrite(MODE_OUT2,LOW);
fmode = 0;
break;
}
}
//------------- Mode set SW ------------
void modesw(){
int cnt = 0;
if(flg_bfochg == 0){
while(digitalRead(SW_MODE) == LOW){
delay(100);
cnt++;
if(10 <= cnt){ // BFO data change mode(1sec)
romadd=0x010+(band*0x10);
romf[0]=Fnc_eepRD(romadd);
freq = Fnc_eepRD(0x090+(fmode * 4));
freqt=String(freq);
freqlcd();
ucg.setPrintPos(110,140);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,255,0);
ucg.print("BFO ADJ");
fmodeb = fmode;
flg_bfochg = 1;
break;
}
}
}
else{
while(digitalRead(SW_MODE) == LOW){
delay(100);
cnt++;
if(10 <= cnt){ // BFO data update(1sec)
ifshift = freq;
Fnc_eepWT(ifshift,0x090+(fmode * 4)); // data write
eep_bfo[fmode] = ifshift;
freq = romf[0];
freqt=String(freq);
freqlcd();
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(0,0,0);
ucg.drawBox(100,120,250,30); //45
flg_bfochg = 0;
fmode--;
break;
}
}
}
if(flg_bfochg == 0)
fmode++;
modeset();
PLL_write();
while(digitalRead(SW_MODE) == LOW);
}
//------------ Rit SET ------------------------------
void setrit(){
if(flagrit==0){
flagrit=1;
ucg.setFont(ucg_font_fub11_tr);
ucg.setPrintPos(190,110);
ucg.setColor(255,0,0);
ucg.print("RIT");
ritlcd();
}
else {
flagrit=0;
vfofreq=freq+ifshift;
Vfo_out(vfofreq); // DDS Out 2016/10/23 JA2GQP
freqt=String(freq);
ucg.setFont(ucg_font_fub11_tr);
ucg.setPrintPos(190,110);
ucg.setColor(255,255,255);
ucg.print("RIT");
ucg.setColor(0,0,0);
ucg.drawRBox(222,92,91,21,3);
freqrit=0;
}
while(digitalRead(SW_RIT) == LOW);
}
//----------- Rit screen ----------------------
void ritlcd(){
ucg.setColor(0,0,0);
ucg.drawBox(222,92,91,21);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,255,255);
ucg.setPrintPos(230,110);
ucg.print(freqrit);
}
//-------------- encorder frequency step set -----------
void setstep(){
if (fstep==100){
fstep=1;
}
else{
fstep=fstep * 10;
}
steplcd();
while(digitalRead(SW_STEP) == LOW);
}
//------------- Step Screen ---------------------------
void steplcd(){
ucg.setColor(0,0,0);
ucg.drawRBox(221,61,93,23,3);
ucg.setFont(ucg_font_fub17_tr);
ucg.setColor(255,255,255);
ucg.setPrintPos(220,80);
if (fstep==1){ucg.print(" 1Hz");}
if (fstep==10){ucg.print(" 10Hz");}
if (fstep==100){ucg.print(" 100Hz");}
}
//----------- Main frequency screen -------------------
void freqlcd(){
ucg.setFont(ucg_font_fub35_tn);
int mojisuu=(freqt.length());
if(freq<100){
ucg.setColor(0,0,0);
ucg.drawBox(217,9,28,36);
}
if(f10 !=(freqt.charAt(mojisuu-2))){
ucg.setColor(0,0,0);
ucg.drawBox(245,9,28,36);
ucg.setPrintPos(245,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-2));
f10 = (freqt.charAt(mojisuu-2));
}
if(freq<10){
ucg.setColor(0,0,0);
ucg.drawBox(245,9,28,36);
}
if(f1 !=(freqt.charAt(mojisuu-1))){
ucg.setColor(0,0,0);
ucg.drawBox(273,9,28,36);
ucg.setPrintPos(273,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-1));
f1 = (freqt.charAt(mojisuu-1));
}
if(freq<1000){
ucg.setColor(0,0,0);
ucg.drawBox(202,9,15,36);
}
if(f100 !=(freqt.charAt(mojisuu-3))){
ucg.setColor(0,0,0);
ucg.drawBox(217,9,28,36);
ucg.setPrintPos(217,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-3));
f100 = (freqt.charAt(mojisuu-3));
}
if(freq>=1000){
ucg.setPrintPos(202,45);
ucg.setColor(0,255,0);
ucg.print(".");
}
if(freq<10000){
ucg.setColor(0,0,0);
ucg.drawBox(146,9,28,36);
}
if(f1k !=(freqt.charAt(mojisuu-4))){
ucg.setColor(0,0,0);
ucg.drawBox(174,9,28,36);
ucg.setPrintPos(174,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-4));
f1k = (freqt.charAt(mojisuu-4));
}
if(freq<100000){
ucg.setColor(0,0,0);
ucg.drawBox(118,9,28,36);
}
if(f10k !=(freqt.charAt(mojisuu-5))){
ucg.setColor(0,0,0);
ucg.drawBox(146,9,28,36);
ucg.setPrintPos(146,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-5));
f10k = (freqt.charAt(mojisuu-5));
}
if(freq<1000000){
ucg.setColor(0,0,0);
ucg.drawBox(103,9,15,36);
}
if(f100k !=(freqt.charAt(mojisuu-6))){
ucg.setColor(0,0,0);
ucg.drawBox(118,9,28,36);
ucg.setPrintPos(118,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-6));
f100k = (freqt.charAt(mojisuu-6));
}
if(freq>=1000000){
ucg.setPrintPos(103,45);
ucg.setColor(0,255,0);
ucg.print(".");
}
if(freq<10000000){
ucg.setColor(0,0,0);
ucg.drawBox(47,9,28,36);
}
if(fmega !=(freqt.charAt(mojisuu-7))){
ucg.setColor(0,0,0);
ucg.drawBox(75,9,28,36);
ucg .setPrintPos(75,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-7));
fmega = (freqt.charAt(mojisuu-7));
}
if(freq<100000000){
ucg.setColor(0,0,0);
ucg.drawBox(19,9,28,36);
}
if (f10m !=(freqt.charAt(mojisuu-8))){
ucg.setColor(0,0,0);
ucg.drawBox(47,9,28,36);
ucg .setPrintPos(47,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-8));
f10m = (freqt.charAt(mojisuu-8));
}
}
//----------- Basic Screen -------------------------
void screen01(){
ucg.setColor(255,255,255);
ucg.drawRFrame(1,1,314,55,5);
ucg.drawRFrame(2,2,312,53,5);
ucg.setColor(50,50,50);
ucg.drawRBox(5,60,60,25,3);
ucg.drawRBox(75,60,60,25,3);
ucg.drawRBox(5,90,60,25,3);
ucg.drawRBox(75,90,60,25,3);
ucg.setFont(ucg_font_fub17_tr);
ucg.setPrintPos(12,82);
ucg.setColor(0,0,0);
ucg.print("LSB");
ucg.setPrintPos(82,82);
ucg.print("USB");
ucg.setPrintPos(12,112);
ucg.print("C W");
ucg.setPrintPos(82,112);
ucg.print("A M");
ucg.setColor(255,255,255);
ucg.drawRFrame(220,60,95,25,3);
ucg.drawRFrame(220,90,95,25,3);
ucg.setFont(ucg_font_fub11_tr);
ucg.setColor(255,255,255);
ucg.setPrintPos(175,80);
ucg.print("STEP");
ucg.setPrintPos(190,110);
ucg.setColor(255,255,255);
ucg.print("RIT");
ucg.setColor(100,100,100);
ucg.setPrintPos(10,210);
ucg.print(" S: 1-----3-------6-------9---Over--------");
ucg.setPrintPos(10,177);
ucg.print(" P: 1-----3-----5-----------10--------------");
ucg.setPrintPos(10,230);
ucg.setColor(235,0,200);
ucg.print( "stm32 VFO(with BFO) Ver1.0 JA2GQP");
ucg.setFont(ucg_font_fub35_tr);
ucg.setColor(0,255,0);
ucg.setPrintPos(273,45);
ucg.print("0");
}
//---------- Band data call from eeprom ----------
void bandcall(){
band=band+1;
if (band>(bandmax-1)){band=0;}
romadd=0x010+(band*0x010);
for (int i=0; i<3;i++){
romf[i]=Fnc_eepRD((romadd+4*i));
}
freq = romf[0];
freqmin = romf[1];
freqmax = romf[2];
Status = EEPROM.read(romadd+12,&fmode);
Status = EEPROM.read(romadd+14,&steprom);
if (steprom==1){fstep=1;}
if (steprom==2){fstep=10;}
if (steprom==3){fstep=100;}
modeset();
steplcd();
freqt=String(freq);
freqlcd();
banddataout();
chlcd();
while(digitalRead(SW_BAND) == LOW);
}
//---------- Band data write to eeprom ----------
void bandwrite(){
romadd=0x010+(band*0x010);
Fnc_eepWT(freq,romadd);
Status = EEPROM.write(EEP_BAND,band);
Status = EEPROM.write(romadd+12,fmode);
if (fstep==1){steprom=1;}
if (fstep==10){steprom=2;}
if (fstep==100){steprom=3;}
Status = EEPROM.write(romadd+14,steprom);
}
//---------- 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);
}
//---------- Band data output I/O ----------
void banddataout(){
digitalWrite(BAND_OUT1,LOW);
digitalWrite(BAND_OUT2,LOW);
digitalWrite(BAND_OUT3,LOW);
if (band==0){}
if (band==1){
digitalWrite( BAND_OUT1,HIGH);
}
if (band==2){
digitalWrite(BAND_OUT2,HIGH);
}
if (band==3){
digitalWrite(BAND_OUT1,HIGH);
digitalWrite(BAND_OUT2,HIGH);
}
if (band==4){
digitalWrite(BAND_OUT3,HIGH);
}
if (band==5){
digitalWrite(BAND_OUT1,HIGH);
digitalWrite(BAND_OUT3,HIGH);
}
if (band==6){
digitalWrite(BAND_OUT2,HIGH);
digitalWrite(BAND_OUT3,HIGH);
}
if (band==7){
digitalWrite(BAND_OUT1,HIGH);
digitalWrite(BAND_OUT2,HIGH);
digitalWrite(BAND_OUT3,HIGH);
}
}
//---------- Band No.(Chanel No.) write to LCD ----------
void chlcd(){
ucg.setColor(0,0,0);
ucg.drawBox(5,120,80,20);
ucg.setFont(ucg_font_fub11_tr);
ucg.setPrintPos(12,137);
ucg.setColor(255,255,255);
ucg.print("CH: ");
ucg.print(band+1);
}
2017年7月31日月曜日
K4GC VFO
何時もお世話になっているKさんから、K4GC VFOスケッチについて相談を受けた。エンコーダ操作で周波数調整が困難との事であった。スケッチを見ると割込み処理を行わずに、エンコーダ読取りが行われており、取りこぼしが原因と思われる。今回問題が有ったエンコーダ処理とLCD表示を変更した。
回路図である。
ダイレクトコンバージョン受信機と組合わせた40m CW QRP機で、フルブレイクイン動作する。オリジナルからkey paddleとエンコーダのIO割付のみ変更。
/**************************************************************************
DIRECT CONVERSION CW TRANSCEIVER CONTROLLER WITH IAMBIC KEYER FOR ARDUINO
Uses SI5351 clock generator shild from Adafruit for VFO
Uses NT7S SI5351 library for Arduino on github:
https://github.com/etherkit/Si5351Arduino
2 x 16 LCD display for frequency, offset, and tuning rate
Has an iambic keyer with dot/dash memories
Arduino Pro Mini pin assignments:
2) Encoder A input
3) Encoder B input
4) STEP SW
5) Iambic paddle DSH input
6) Iambic paddle DIT input
7)
8) Transmit/mute output
9) Sidetone output
10) LCD RS output
11) LCD E output
12) LCD D4 output
13) LCD D5 output
A0) LCD D6 output
A1) LCD D7 output
A2)
A3)
A4) si5351 SDA
A5) si5351 SCL
A6) Offset voltage input
A7) Keyer speed voltage input
***************************************************************************/
#include <si5351.h>
#include "Wire.h"
#include <Rotary.h>
#include "src/LiquidCrystal.h" // use Arduino LCD library.
//---------- PLL setting --------------------
Si5351 si5351;
//---------- LCD setting --------------------
LiquidCrystal lcd(10, 11, 12, 13, A0, A1); // RS,E,D4,D5,D6,D7
//---------- Encorder setting ---------------
#define ENC_A 2 // Encorder A
#define ENC_B 3 // Encoeder B
Rotary r=Rotary(ENC_A,ENC_B);
////////////////////////ENCODER SETUP///////////////////////////////////////
#define SW_STEP 4
#define Pad_Dah 5
#define Pad_Dit 6
#define XMIT 8
#define TONE 9
#define LW_FRQ 7000000L
#define HI_FRQ 7200000L
long Vfo_Dat = 7030000L; //Start up frequency <<<2017/6/27>>>
long Vfo_Datb = 0; // <<<2017/6/27>>>
int Enc_Stp = 10; // STEP=10Hz
int rateindicator = 5;
char Lcd_data[17] = " ";
int Flg_Set0 = 1;
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////RIT SETUP//////////////////////////////////////
int rit = A6;
int ritvoltage = 0;
int oldritvoltage = 0;
int modulo = 0;
int ritcenter = 512;
int rittune = 0;
int rittuneb = rittune;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////IAMBIC KEYER////////////////////////////////////
int count = 0;
int dit = 1;
int dah = 1;
int sidetone = 700;
int ditmem = 0;
int dahmem = 0;
int sspeed = 50;
int speedinput = A7;
/////////////////////////////////////////////////////////////////////////////
//---------- Setup ---------------
void setup(){
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
lcd.begin(16, 2);
pinMode(Pad_Dah, INPUT_PULLUP); // Dah
pinMode(Pad_Dit, INPUT_PULLUP); // Dit
pinMode(SW_STEP, INPUT_PULLUP); // STEP
pinMode(TONE, OUTPUT);
pinMode(XMIT, OUTPUT);
digitalWrite(XMIT, HIGH);
PCICR |=(1<<PCIE2);
PCMSK2 |=(1 << PCINT18) | (1 << PCINT19);
sei();
Fnc_Step_Disp();
}
//---------- Main loop --------
void loop() {
if(digitalRead(SW_STEP) == LOW) // STEP SW On?
Fnc_Stp();
setclock0();
ritvoltage = analogRead(A6);
rittune = ritvoltage - ritcenter;
rittune = rittune * 5;
if (ritvoltage != oldritvoltage){
ritune();
}
if (ditmem == 1) makedit();
if (dahmem == 1) makedah();
sspeed = analogRead(speedinput);
sspeed = sspeed / 6.5;
if (sspeed < 24) sspeed = 24;
count = 0;
checkpaddle();
}
//---------- Encorder procedure(INT) ---------------
ISR(PCINT2_vect) {
unsigned char result = r.process();
if(result) {
if(result == DIR_CW)
Vfo_Dat = Vfo_Dat + Enc_Stp;
else
Vfo_Dat = Vfo_Dat - Enc_Stp;
Vfo_Dat = constrain(Vfo_Dat,LW_FRQ,HI_FRQ);
}
Flg_Set0 = 1;
}
//---------- Set Clock0 ---------------
void setclock0() { //function to set the SI5351 clock frequency
if(Flg_Set0 == 1){
lcd.setCursor(2, 0);
Fnc_Dot_Edit(Lcd_data,Vfo_Dat);
lcd.print(Lcd_data);
lcd.print(" MHz");
si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
}
Flg_Set0 = 0;
}
//---------- RIT proc ---------------
void ritune() { //function to determine RIT offset frequency
modulo = 0;
oldritvoltage = ritvoltage;
rittune = ritvoltage - ritcenter;
rittune = rittune * 5; //RIT steps in 5 Hz increments
if (rittune > 30) { //Keep a dead zone near 0 offset
rittune = rittune;
}
else if (rittune < -30) {
rittune = rittune; //Keep a dead zone near 0 offset
}
else {
rittune = 0;
}
lcd.setCursor(8, 1);
lcd.print(" ");
lcd.setCursor(8, 1);
lcd.print("Rit");
if (rittune > 0) {
lcd.print("+");
}
lcd.print(rittune);
Flg_Set0 = 1;
setclock0();
}
//---------- Check Paddle ---------------
void checkpaddle() { //function for checking iambic paddle status
dit = digitalRead(Pad_Dit);
dah = digitalRead(Pad_Dah);
if (!dit) makedit();
if (!dah) makedah();
}
//---------- Dit make proc ---------------
void makedit() { //function to make dits
count = 0;
ditmem = 0;
si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
digitalWrite(XMIT, 0);
tone(TONE, sidetone);
while (count < sspeed) {
dah = digitalRead(Pad_Dah);
if (!dah) dahmem = 1;
delay(1);
++count;
}
count = 0;
noTone(TONE);
digitalWrite(XMIT, 1);
si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
while (count < sspeed) {
dah = digitalRead(Pad_Dah);
delay(1);
++count;
}
}
//---------- Dah make proc ---------------
void makedah(){ //function to make dahs
count = 0;
dahmem = 0;
si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
digitalWrite(XMIT, 0);
tone(TONE, sidetone);
while (count < (sspeed * 3)){
dit = digitalRead(Pad_Dit);
if (!dit) ditmem = 1;
delay(1);
++count;
}
count = 0;
noTone(TONE);
digitalWrite(XMIT, 1);
si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
while (count < sspeed) {
dit = digitalRead(Pad_Dit);
if (!dit) ditmem = 1;
delay(1);
++count;
}
}
//---------- 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 Encorder STEP ---------
void Fnc_Stp(){
if(Enc_Stp == 10000) // Step = 10kHz ?
Enc_Stp = 10; // Yes,100khz set
else
Enc_Stp = Enc_Stp * 10; // Step up 1 digit
Fnc_Step_Disp();
while(digitalRead(SW_STEP) == LOW)
;
delay(50);
}
//---------- Function STEP Display ----------
void Fnc_Step_Disp(){
lcd.setCursor(0,1);
switch(Enc_Stp){
case 10:
lcd.print("Step10 ");
break;
case 100:
lcd.print("Step100");
break;
case 1000:
lcd.print("Step1k ");
break;
case 10000:
lcd.print("Step10k");
break;
default:
lcd.print("Step10 ");
Enc_Stp = 10;
break;
}
}
回路図である。
ダイレクトコンバージョン受信機と組合わせた40m CW QRP機で、フルブレイクイン動作する。オリジナルからkey paddleとエンコーダのIO割付のみ変更。
スケッチ
基本的な処理は、オリジナルを継承している。RIT処理がアナログ処理で行われており、参考になる所もある。スケッチは、ダウンロードサイトのsi5351aフォルダ。/**************************************************************************
DIRECT CONVERSION CW TRANSCEIVER CONTROLLER WITH IAMBIC KEYER FOR ARDUINO
Uses SI5351 clock generator shild from Adafruit for VFO
Uses NT7S SI5351 library for Arduino on github:
https://github.com/etherkit/Si5351Arduino
2 x 16 LCD display for frequency, offset, and tuning rate
Has an iambic keyer with dot/dash memories
Arduino Pro Mini pin assignments:
2) Encoder A input
3) Encoder B input
4) STEP SW
5) Iambic paddle DSH input
6) Iambic paddle DIT input
7)
8) Transmit/mute output
9) Sidetone output
10) LCD RS output
11) LCD E output
12) LCD D4 output
13) LCD D5 output
A0) LCD D6 output
A1) LCD D7 output
A2)
A3)
A4) si5351 SDA
A5) si5351 SCL
A6) Offset voltage input
A7) Keyer speed voltage input
***************************************************************************/
#include <si5351.h>
#include "Wire.h"
#include <Rotary.h>
#include "src/LiquidCrystal.h" // use Arduino LCD library.
//---------- PLL setting --------------------
Si5351 si5351;
//---------- LCD setting --------------------
LiquidCrystal lcd(10, 11, 12, 13, A0, A1); // RS,E,D4,D5,D6,D7
//---------- Encorder setting ---------------
#define ENC_A 2 // Encorder A
#define ENC_B 3 // Encoeder B
Rotary r=Rotary(ENC_A,ENC_B);
////////////////////////ENCODER SETUP///////////////////////////////////////
#define SW_STEP 4
#define Pad_Dah 5
#define Pad_Dit 6
#define XMIT 8
#define TONE 9
#define LW_FRQ 7000000L
#define HI_FRQ 7200000L
long Vfo_Dat = 7030000L; //Start up frequency <<<2017/6/27>>>
long Vfo_Datb = 0; // <<<2017/6/27>>>
int Enc_Stp = 10; // STEP=10Hz
int rateindicator = 5;
char Lcd_data[17] = " ";
int Flg_Set0 = 1;
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////RIT SETUP//////////////////////////////////////
int rit = A6;
int ritvoltage = 0;
int oldritvoltage = 0;
int modulo = 0;
int ritcenter = 512;
int rittune = 0;
int rittuneb = rittune;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////IAMBIC KEYER////////////////////////////////////
int count = 0;
int dit = 1;
int dah = 1;
int sidetone = 700;
int ditmem = 0;
int dahmem = 0;
int sspeed = 50;
int speedinput = A7;
/////////////////////////////////////////////////////////////////////////////
//---------- Setup ---------------
void setup(){
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
lcd.begin(16, 2);
pinMode(Pad_Dah, INPUT_PULLUP); // Dah
pinMode(Pad_Dit, INPUT_PULLUP); // Dit
pinMode(SW_STEP, INPUT_PULLUP); // STEP
pinMode(TONE, OUTPUT);
pinMode(XMIT, OUTPUT);
digitalWrite(XMIT, HIGH);
PCICR |=(1<<PCIE2);
PCMSK2 |=(1 << PCINT18) | (1 << PCINT19);
sei();
Fnc_Step_Disp();
}
//---------- Main loop --------
void loop() {
if(digitalRead(SW_STEP) == LOW) // STEP SW On?
Fnc_Stp();
setclock0();
ritvoltage = analogRead(A6);
rittune = ritvoltage - ritcenter;
rittune = rittune * 5;
if (ritvoltage != oldritvoltage){
ritune();
}
if (ditmem == 1) makedit();
if (dahmem == 1) makedah();
sspeed = analogRead(speedinput);
sspeed = sspeed / 6.5;
if (sspeed < 24) sspeed = 24;
count = 0;
checkpaddle();
}
//---------- Encorder procedure(INT) ---------------
ISR(PCINT2_vect) {
unsigned char result = r.process();
if(result) {
if(result == DIR_CW)
Vfo_Dat = Vfo_Dat + Enc_Stp;
else
Vfo_Dat = Vfo_Dat - Enc_Stp;
Vfo_Dat = constrain(Vfo_Dat,LW_FRQ,HI_FRQ);
}
Flg_Set0 = 1;
}
//---------- Set Clock0 ---------------
void setclock0() { //function to set the SI5351 clock frequency
if(Flg_Set0 == 1){
lcd.setCursor(2, 0);
Fnc_Dot_Edit(Lcd_data,Vfo_Dat);
lcd.print(Lcd_data);
lcd.print(" MHz");
si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
}
Flg_Set0 = 0;
}
//---------- RIT proc ---------------
void ritune() { //function to determine RIT offset frequency
modulo = 0;
oldritvoltage = ritvoltage;
rittune = ritvoltage - ritcenter;
rittune = rittune * 5; //RIT steps in 5 Hz increments
if (rittune > 30) { //Keep a dead zone near 0 offset
rittune = rittune;
}
else if (rittune < -30) {
rittune = rittune; //Keep a dead zone near 0 offset
}
else {
rittune = 0;
}
lcd.setCursor(8, 1);
lcd.print(" ");
lcd.setCursor(8, 1);
lcd.print("Rit");
if (rittune > 0) {
lcd.print("+");
}
lcd.print(rittune);
Flg_Set0 = 1;
setclock0();
}
//---------- Check Paddle ---------------
void checkpaddle() { //function for checking iambic paddle status
dit = digitalRead(Pad_Dit);
dah = digitalRead(Pad_Dah);
if (!dit) makedit();
if (!dah) makedah();
}
//---------- Dit make proc ---------------
void makedit() { //function to make dits
count = 0;
ditmem = 0;
si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
digitalWrite(XMIT, 0);
tone(TONE, sidetone);
while (count < sspeed) {
dah = digitalRead(Pad_Dah);
if (!dah) dahmem = 1;
delay(1);
++count;
}
count = 0;
noTone(TONE);
digitalWrite(XMIT, 1);
si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
while (count < sspeed) {
dah = digitalRead(Pad_Dah);
delay(1);
++count;
}
}
//---------- Dah make proc ---------------
void makedah(){ //function to make dahs
count = 0;
dahmem = 0;
si5351.set_freq(Vfo_Dat * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
digitalWrite(XMIT, 0);
tone(TONE, sidetone);
while (count < (sspeed * 3)){
dit = digitalRead(Pad_Dit);
if (!dit) ditmem = 1;
delay(1);
++count;
}
count = 0;
noTone(TONE);
digitalWrite(XMIT, 1);
si5351.set_freq((Vfo_Dat + rittune) * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
while (count < sspeed) {
dit = digitalRead(Pad_Dit);
if (!dit) ditmem = 1;
delay(1);
++count;
}
}
//---------- 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 Encorder STEP ---------
void Fnc_Stp(){
if(Enc_Stp == 10000) // Step = 10kHz ?
Enc_Stp = 10; // Yes,100khz set
else
Enc_Stp = Enc_Stp * 10; // Step up 1 digit
Fnc_Step_Disp();
while(digitalRead(SW_STEP) == LOW)
;
delay(50);
}
//---------- Function STEP Display ----------
void Fnc_Step_Disp(){
lcd.setCursor(0,1);
switch(Enc_Stp){
case 10:
lcd.print("Step10 ");
break;
case 100:
lcd.print("Step100");
break;
case 1000:
lcd.print("Step1k ");
break;
case 10000:
lcd.print("Step10k");
break;
default:
lcd.print("Step10 ");
Enc_Stp = 10;
break;
}
}
2017年6月17日土曜日
stm32VFO 6mAM
stm32f103c8t6とsi5351aを使って、50MHzAM用VFOを作った。周波数は50MHzから51MHzまでとし、STEPは1Khz、10kHzとした。電源off時の周波数とSTEPを電源on時に復帰させるメモリ機能を付加したVFOである。資料は、Download siteのstm32フォルダに保存してある。
stm32BaseBordから不要な部分を除いた、回路図である。
///////////////////////////////////////////////////////////////////
// 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);
}
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);
}
2017年6月12日月曜日
stm32f103c8t6 Base Bord
stm32f103c8t6のスケッチを開発するにあたり、プロトタイプのベースボードを作った。同時に、このボードのI/O割付に修正したスケッチサンプルを作った。このサンプルを使えば、VFOを簡単に作る事が出来るであろう。
ベースボードの回路図である。スケッチ書込みポートは、シリアルのコネクタを設けてあり、USBアダプタ(CH340G)を直接繋ぐ事ができる。表示器は、0.96"OLED、1.8"TFT、nokia5110を繋ぐ事ができる。si5351a取付コネクタを設けてあるので、このままVFO開発が可能。
ベースボードの回路図である。スケッチ書込みポートは、シリアルのコネクタを設けてあり、USBアダプタ(CH340G)を直接繋ぐ事ができる。表示器は、0.96"OLED、1.8"TFT、nokia5110を繋ぐ事ができる。si5351a取付コネクタを設けてあるので、このままVFO開発が可能。
サンプルスケッチ
全てのサンプルは、先に紹介した回路図に対応する様、I/O割付を変更済である。回路図通り接続し、即、スケッチが実行可能。このサンプルスケッチは、JA2GQP's Download siteのstm32フォルダ。・Blink
LEDのブリンク。・encorder
stm32f103c8t6の割込み処理は自由度がある。どのポートに割付しても、割込み処理で動作させる事ができる。・si5351a
PLL出力(clk0、clk2)の出力サンプル。
・noki5110
nokia5110液晶文字表示サンプル。・oled(ssd1306)
oledグラフィック表示サンプル。
・メモリ記憶
エンコーダと組合わせた、メモリ記憶のサンプル。・Ucglib(ili9341、st7735)
TFT液晶の表示サンプル。
VFO製作例
サンプルスケッチを基にして作ったVFO。
2017年6月3日土曜日
si5351a TFT VFO Ver.1.1
2.2"TFTが入手難の為、1.8"TFTにダウンサイジングを行った。今回の移植作業と合わせ、機能追加を行う事にした。追加変更内容は、Lowerヘテロダイン対応とBFO追加である。理由は、BITX40がLowerヘテロダインである事と、si5351aのマルチ出力が生かされて無かったからである。
回路図、スケッチはダウンロードサイトsi5351a TFTフォルダに2種類有ります。
si5351_TFT18.zip,si5351_TFT181.zip
回路図である。si5351aモジュールのclk2からBFO出力を行っている。
si5351a2.hの内容。
////////////////////////////////////////////////////////////////////////
// Author: Hans Summers, 2015
// Website: http://www.hanssummers.com
//
// A very very simple Si5351a demonstration
// using the Si5351a module kit http://www.hanssummers.com/synth
// Please also refer to SiLabs AN619 which describes all the registers to use
//----------------------------------------------------------------------
// Modifications: JA2GQP,2017/5/20
// 1)Output is CLK0 and CLK2.
// 2)Arduino and stm32duino Operable.
////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define MSNA_ADDR 26
#define MSNB_ADDR 34
#define MS0_ADDR 42
#define MS1_ADDR 50
#define MS2_ADDR 58
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define R_DIV_2 0b00010000
#define R_DIV_4 0b00100000
#define R_DIV_8 0b00110000
#define R_DIV_16 0b01000000
#define R_DIV_32 0b01010000
#define R_DIV_64 0b01100000
#define R_DIV_128 0b01110000
#define Si5351A_ADDR 0x60
#define CLK_SRC_PLL_A 0b00000000
#define CLK_SRC_PLL_B 0b00100000
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
////////////////////////////////////////////////////////////////////////
// I2C write
////////////////////////////////////////////////////////////////////////
void Si5351_write(byte Reg , byte Data){
Wire.beginTransmission(Si5351A_ADDR);
Wire.write(Reg);
Wire.write(Data);
Wire.endTransmission();
}
////////////////////////////////////////////////////////////////////////
// Set up specified PLL with mult, num and denom
// mult is 15..90
// num is 0..1,048,575 (0xFFFFF)
// denom is 0..1,048,575 (0xFFFFF)
///////////////////////////////////////////////////////////////////////
void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom){
uint32_t P1; // PLL config register P1
uint32_t P2; // PLL config register P2
uint32_t P3; // PLL config register P3
P1 = (uint32_t)(128 * ((float)num / (float)denom));
P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
P2 = (uint32_t)(128 * ((float)num / (float)denom));
P2 = (uint32_t)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
////////////////////////////////////////////////////////////////////////
// Set up MultiSynth with integer divider and R divider
// R divider is the bit value which is OR'ed onto the appropriate
// register, it is a #define in si5351a.h
////////////////////////////////////////////////////////////////////////
void setupMultisynth(uint8_t synth, uint32_t divider, uint8_t rDiv){
uint32_t P1; // Synth config register P1
uint32_t P2; // Synth config register P2
uint32_t P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
////////////////////////////////////////////////////////////////////////
// Switches off Si5351a output
// Example: si5351aOutputOff(CLK0_CTRL);
// will switch off output CLK0
////////////////////////////////////////////////////////////////////////
void si5351aOutputOff(uint8_t clk){
Si5351_write(clk, 0x80); // Refer to SiLabs AN619 to see
//bit values - 0x80 turns off the output stage
}
////////////////////////////////////////////////////////////////////////
// Set CLK0 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL A
// and MultiSynth 0
// and produces the output on CLK0
////////////////////////////////////////////////////////////////////////
void si5351aSetFrequency(uint32_t frequency){
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
// Reset the PLL. This causes a glitch in the output. For small changes to
// the parameters, you don't need to reset the PLL, and there is no glitch
// Si5351_write(PLL_RESET, 0x20);
// Finally switch on the CLK0 output (0x4F)
// and set the MultiSynth0 input to be PLL A
Si5351_write(CLK0_CTRL, 0x4F | CLK_SRC_PLL_A); // Strength 8mA
}
////////////////////////////////////////////////////////////////////////
// Set CLK1 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency2(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL B
// and MultiSynth 1
// and produces the output on CLK1
////////////////////////////////////////////////////////////////////////
void si5351aSetFrequency2(uint32_t frequency){
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL B with the calculated multiplication ratio
setupPLL(MSNB_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS2_ADDR, divider, R_DIV_1);
// Reset the PLL. This causes a glitch in the output. For small changes to
// the parameters, you don't need to reset the PLL, and there is no glitch
// Si5351_write(PLL_RESET, 0x80);
// Finally switch on the CLK1 output
// and set the MultiSynth0 input to be PLL B
Si5351_write(CLK2_CTRL, 0x6F | CLK_SRC_PLL_B); // Strength 8mA
}
//////////////////////////////////////////////////////////////////////////////
// Copyright©2016.JA2GQP.All rights reserved.
// si5351a PLL VFO Ver1.101 << JA2NKD sketch is based >>
// 2017/6/3
// JA2GQP
// << Aruduino IDE 1.8.2 >>
//
//----------------------------------------------------------------------------
// Function
// 1.RIT Operation(-10kHZ to 10kHZ)
// 2.STEP(10,100,1k,10k)
// 3.Memory Operation is Push RIT
// 4.Protection Operation At The Time Of Transmission
// 5.Memory 4ch(LSB,USB.CW,AM)
// 6.IF shift
//----------------------------------------------------------------------------
// Library
// <Rotary.h> https://github.com/brianlow/Rotary
// "Ucglib.h" https://github.com/olikraus/ucglib
//
//////////////////////////////////////////////////////////////////////////////
//---------- include Files ---------------
#include "si5351a2.h"
#include <SPI.h>
#include <Rotary.h>
#include <EEPROM.h>
#include "Ucglib.h"
//---------- TFT setting ---------------
Ucglib_ST7735_18x128x160_HWSPI ucg(/*sclk= 13, data= 11, */ /*cd=*/ 9 , /*cs=*/ 10, /*reset=*/ 8);
//---------- Encorder setting ---------------
#define ENC_A 2 // Encorder A
#define ENC_B 3 // Encoeder B
Rotary r=Rotary(ENC_A,ENC_B);
//---------- I/O setting -------------------
#define modeout1 7 // DIO7
#define modeout2 12 // DIO12
#define modesw 6 // DIO6
#define stepsw 4 // DIO4
#define ritsw 5 // DIO5
#define txsw A3 // A3
#define s_meter A0 // A0
#define t_meter A1 // A1
//---------- EEPROM Memory Address ----------
#define Frq_Eep 0x00 // Frequency(4byte*4)
#define Stp_Eep 0x10 // STEP(4byte*4)
#define Chn_Eep 0x20 // Channel(1byte*1)
#define Mode_Eep 0x22 // Mode(1byte*1)
#define Eep_Int 0x2e // Eep Init(1byte*1)
#define Max_Chn 4 // Max Channel(4ch)
#define Int_End 73 // Initial end code
//----------- Default Frequency Value --------------------
#define UPPER 0 // Upoper heterodyne
#define LOWER 1 // Lower heterodyne
////////////////////////////////////////////////////////////////
// BITX40 Setting example(Upper heterodyne) No.1
////////////////////////////////////////////////////////////////
#define DEF_FRQ 7050000L // Init Frequency
#define DEF_FMAX 7200000L // Frequency Max
#define DEF_FMIN 7000000L // Min
#define DEF_RLSB 10698500L // RX IF Shift LSB
#define DEF_RUSB 10701500L // USB
#define DEF_RCW 10699200L // CW
#define DEF_RAM 10700000L // AM
#define DEF_TLSB 10698500L // TX IF Shift LSB
#define DEF_TUSB 10701500L // USB
#define DEF_TCW 10700000L // CW
#define DEF_TAM 10700000L // AM
byte hetero = UPPER; // Lower heterodyne set
////////////////////////////////////////////////////////////////
// BITX40 Setting example(Lower heterodyne) No.2
////////////////////////////////////////////////////////////////
/*
#define DEF_FRQ 7050000L // Init Frequency
#define DEF_FMAX 7200000L // Frequency Max
#define DEF_FMIN 7000000L // Min
#define DEF_RLSB 11998500L // RX IF Shift LSB
#define DEF_RUSB 12001500L // USB
#define DEF_RCW 11999400L // CW
#define DEF_RAM 12000000L // AM
#define DEF_TLSB 11998500L // TX IF Shift LSB
#define DEF_TUSB 12001500L // USB
#define DEF_TCW 12000000L // CW
#define DEF_TAM 12000000L // AM
byte hetero = LOWER; // Lower heterodyne set
*/
//----------- Default ETC. Value --------------------
#define DEF_STP 100L // Init STEP
#define DEF_Mode 0 // 0=LSB 1=USB 2=CW 3=AM
//---------- Memory Assign ------------------
long freq = DEF_FRQ; // Frequency data
long freqb; // old data
long freqmax = DEF_FMAX; // VFO Upper Limit
long freqmin = DEF_FMIN; // Lower Limit
long freqold = 0;
long freqrit = 0;
String freqt=String(freq);
long ifshift = 0;
long ifshiftb;
long ifshiftLSB = DEF_RLSB; // RX IF Shift LSB
long ifshiftUSB = DEF_RUSB; // USB
long ifshiftCW = DEF_RCW; // CW
long ifshiftAM = DEF_RAM; // AM
long txshiftLSB = DEF_TLSB; // TX IF Shift LSB
long txshiftUSB = DEF_TUSB; // USB
long txshiftCW = DEF_TCW; // CW
long txshiftAM = DEF_TAM; // AM
long vfofreq = 0; // VFO data
long vfofreqb; // old
char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;
int vfostep=2;
int rit=0;
int fstep = DEF_STP; // Default Step
int fmode;
int fmodeold=1;
int flagrit=0;
int fritold=0;
int flagmode=0;
int smeterval1=0;
int tmeterval=0;
byte Byt_Chn; // Channel SW
byte Byt_Chnb; // Old
//---------- Initialization Program ----------------------
void setup() {
Wire.begin();
delay(100);
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.clearScreen();
ucg.setRotate90();
pinMode (stepsw,INPUT_PULLUP);
pinMode (ritsw,INPUT_PULLUP);
pinMode(txsw,INPUT_PULLUP);
pinMode(modesw,INPUT_PULLUP);
pinMode(modeout1,OUTPUT);
pinMode(modeout2,OUTPUT);
PCICR |=(1<<PCIE2);
PCMSK2 |=(1 << PCINT18) | (1 << PCINT19);
sei();
screen01();
if(EEPROM.read(Eep_Int) != Int_End){ // Eep initialaz
delay(10);
Fnc_Eep_Int();
}
Byt_Chn = EEPROM.read(Chn_Eep); // Channel
Byt_Chnb = Byt_Chn; //
Fnc_Eep_Rd(); // EEPROM Read
modeset(); // modeset * 4 times
modeset();
modeset();
modeset();
steplcd();
freqt=String(freq);
freqlcd();
}
//---------- Main program ---------------------------------
void loop() {
if (digitalRead(stepsw)==LOW){setstep();}
if (digitalRead(modesw)==LOW){modeset();}
if (digitalRead(ritsw)==LOW){setrit();Fnc_Eep_Wt(Byt_Chn);}
if (digitalRead(txsw)==LOW){txset();}
if(Byt_Chnb != Byt_Chn){ // CH SW OLD != NEW?
Fnc_Eep_Wt(Byt_Chnb);
Byt_Chnb = Byt_Chn;
Fnc_Eep_Rd();
steplcd();
}
if (flagrit==1){
if (freqrit == fritold){
smeter();
}
if (freqrit!=fritold){
Vfo_write();
ritlcd();
fritold=freqrit;
}
}
else{
if (freq == freqold){
smeter();
}
Vfo_write();
freqt=String(freq);
freqlcd();
freqold=freq;
}
}
//---------- Function Eeprom Initialization ------------
void Fnc_Eep_Int(){
int i;
for (i=0;i<48;i++) // 0 clear(48byte)
EEPROM.write(i, 0);
for(i=0;i<Max_Chn;i++){
Fnc_Eep_Sav4(DEF_FRQ,Frq_Eep+i*4); // Frequency(7.10MHz)
Fnc_Eep_Sav4(DEF_STP,Stp_Eep+i*4); // Step(100Hz)
}
EEPROM.write(Chn_Eep,0);
EEPROM.write(Mode_Eep,DEF_Mode);
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))
freq = Fnc_Eep_Lod4(Frq_Eep+Byt_Chn*4);
else{
freq = Fnc_Eep_Lod4(Frq_Eep+0);
Byt_Chn = 0;
}
if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
fstep = Fnc_Eep_Lod4(Stp_Eep+Byt_Chn*4);
else
fstep = Fnc_Eep_Lod4(Stp_Eep+0);
fmode = EEPROM.read(Mode_Eep);
}
//---------- Function EEPROM Write -------------------
void Fnc_Eep_Wt(byte chn){
if((0 <= chn) && (chn < Max_Chn)){
Fnc_Eep_Sav4(freq,Frq_Eep+chn*4);
Fnc_Eep_Sav4(fstep,Stp_Eep+chn*4);
}
EEPROM.write(Chn_Eep,Byt_Chn);
EEPROM.write(Mode_Eep,fmode);
}
//---------- 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 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;
}
//---------- VFO out ---------------
void Vfo_out(long frequency){
if(vfofreq != vfofreqb){
si5351aSetFrequency(frequency);
vfofreqb = vfofreq;
}
}
//---------- BFO out ---------------
void Bfo_out(long frequency){
if(ifshift != ifshiftb){
si5351aSetFrequency2(frequency);
ifshiftb = ifshift;
}
}
//---------- S-meter --------------------------
void smeter(){
smeterval1=analogRead(s_meter);
smeterval1=smeterval1/50;
if (smeterval1>14){smeterval1=14;} //15
int sx1=sx1+(smeterval1*9); //16
sx1=sx1+21; //41
int sx2=0;
sx2=sx2+(40+((15-smeterval1)*9)); //ucg_font_6x10_mf
ucg.setFont(ucg_font_fub20_tn); //ucg_font_fub35_tn
ucg.setColor(0,0,0); // BLACK
ucg.drawBox(sx1,99,sx2,8);
ucg.setPrintPos(20,109); //40,200
for(int i=1;i<=smeterval1;i++){
if (i<=8){
ucg.setColor(0,255,255);
ucg.print("-");
}
else{
ucg.setColor(255,0,0);
ucg.print("-");
}
}
}
//---------- Transmission Power meter ------------------
void tmeter(){
ucg.setColor(0,0,0); // BLACK
ucg.drawBox(20,99,135,8); //41,180,270,16
tmeterval=analogRead(t_meter);
tmeterval=tmeterval/50;
if (tmeterval>14){tmeterval=14;}
int sx1=sx1+(tmeterval*9);
sx1=sx1+21;
int sx2=0;
sx2=sx2+(40+((15-tmeterval)*9));
ucg.setFont(ucg_font_fub20_tn); //35ucg_font_fub20_tn
ucg.setColor(0,0,0); //BLACK
ucg.drawBox(sx1,78,sx2,8);
ucg.setPrintPos(20,90); //85(40,165)
for(int i=1;i<=tmeterval;i++){
if (i<=9){
ucg.setColor(250,80,0);
ucg.print("-");
}
else{
ucg.setColor(250,0,0);
ucg.print("-");
}
}
}
//---------- Encoder Interrupt -----------------------
ISR(PCINT2_vect) {
if (flagrit==1){
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freqrit=freqrit+fstep;
if (freqrit>=10000){
freqrit=10000;
}
}
else{
freqrit=freqrit-fstep;
if (freqrit<=-10000){
freqrit=-10000;
}
}
}
}
else{
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freq=freq+fstep;
if (freq>=freqmax){freq=freqmax;}
}
else{
freq=freq-fstep;
if (freq<=freqmin){freq=freqmin;}
}
}
}
}
//------------ On Air -----------------------------
void txset(){
long vfofreq_RX = vfofreq;;
long ifshift_RX = ifshift;;
// noInterrupts();
if(hetero == UPPER){ // Upper heterodyne
if (flagmode==0){ifshift=txshiftLSB;}
if (flagmode==1){ifshift=txshiftUSB;}
if (flagmode==2){ifshift=txshiftCW;}
if (flagmode==3){ifshift=txshiftAM;}
vfofreq=freq+ifshift;
}
else{ // Lower heterodyne
if (flagmode==0){ifshift=txshiftLSB;}
if (flagmode==1){ifshift=txshiftUSB;}
if (flagmode==2){ifshift=txshiftCW;}
if (flagmode==3){ifshift=txshiftAM;}
vfofreq=ifshift-freq;
}
Vfo_out(vfofreq); // vfo out
Bfo_out(ifshift); // BFO out
ucg.setPrintPos(70,75); //140,140
ucg.setFont(ucg_font_6x10_mf); //17ucg_font_fub11_tn
ucg.setColor(255,0,0);
ucg.print("ON AIR");
while(digitalRead(txsw) == LOW){
tmeter();
}
vfofreq = vfofreq_RX;
ifshift = ifshift_RX;
ucg.setColor(0,0,0);
ucg.drawBox(15,63,95,15); //30,120,250,30 // ON AIR Erase
Vfo_write();
ucg.drawBox(20,80,135,8); //41,145,270,16 // Level Erase
// interrupts();
}
//------------- Mode change(LSB-USB-CW-AM) ------------
void modeset(){
ucg.setFont(ucg_font_6x10_mf); //17ucg_font_fub11_tn
// if (fmode==0){
if (fmode==1){ // 2016/8/3
ifshift=ifshiftUSB;
flagmode = 1; // 2016/8/3
ucg.setColor(255,255,0); //Black?
ucg.setPrintPos(44,43); //(82,82
ucg.print("USB");
ucg.setPrintPos(9,43); //12,82
ucg.setColor(0,0,0); //Black Yellow
ucg.print("LSB");
digitalWrite(modeout1,HIGH);
digitalWrite(modeout2,LOW);
}
// if(fmode==1){
if(fmode==2){ // 2016/8/3
ifshift=ifshiftCW;
flagmode = 2; // 2016/8/3
ucg.setPrintPos(9,60); //12,112
ucg.setColor(255,255,0); //Yellow
ucg.print("C W");
ucg.setPrintPos(44,43); //82,82
ucg.setColor(0,0,0); //Black
ucg.print("USB");
digitalWrite(modeout1,LOW);
digitalWrite(modeout2,HIGH);
}
// if (fmode==2){
if (fmode==3){ // 2016/8/3
ifshift=ifshiftAM;
flagmode = 3; // 2016/8/3
ucg.setPrintPos(44,60); //82,112
ucg.setColor(255,255,0); //Yellow
ucg.print("A M");
ucg.setColor(0,0,0); //Black
ucg.setPrintPos(9,60); //12,112
ucg.print("C W");
digitalWrite(modeout1,HIGH);
digitalWrite(modeout2,HIGH);
}
// if (fmode==3){
if (fmode==0){ // 2016/8/3
ifshift=ifshiftLSB;
flagmode = 0; // 2016/8/3
ucg.setPrintPos(9,43); //12,82
ucg.setColor(255,255,0); //Yellow
ucg.print("LSB");
ucg.setPrintPos(44,60); //82,112
ucg.setColor(0,0,0); //Black
ucg.print("A M");
digitalWrite(modeout1,LOW);
digitalWrite(modeout2,LOW);
}
fmode=fmode+1;
Byt_Chn++;
if(Byt_Chn > 3)
Byt_Chn = 0;
if (fmode==4){fmode=0;}
Vfo_write();
while(digitalRead(modesw) == LOW);
}
//------------ Rit SET ------------------------------
void setrit(){
if(flagrit==0){
flagrit=1;
ucg.setFont(ucg_font_6x10_mf); //11ucg_font_fub11_tn
ucg.setPrintPos(95,55); //190,110
ucg.setColor(255,0,0);
// freqrit=0;
ritlcd();
}
else {
flagrit=0;
if(hetero == UPPER)
vfofreq=freq+ifshift;
else
vfofreq=ifshift-freq;
Vfo_out(vfofreq); // vfo Out
freqt=String(freq);
ucg.setFont(ucg_font_6x10_mf); //11ucg_font_fub11_tn
ucg.setPrintPos(95,55); //190,110
ucg.setColor(255,255,255);
// ucg.print("RIT");
ucg.setColor(0,0,0);
ucg.drawRBox(112,52,44,10,1); //222,92,91,21,3
freqrit=0;
}
while(digitalRead(ritsw) == LOW);
}
//----------- Rit screen ----------------------
void ritlcd(){
noInterrupts();
ucg.setColor(0,0,0);
ucg.drawBox(111,51,45,13); //222,92,91,21 110,50,47,15,
ucg.setFont(ucg_font_6x10_mf); //17 ucg_font_fub11_tn
ucg.setColor(0,255,255);
ucg.setPrintPos(115,61); //230,110
ucg.print(freqrit);
interrupts();
}
//-------------- encorder frequency step set -----------
void setstep(){
noInterrupts();
if (fstep==10000){
fstep=10;
}
else{
fstep=fstep * 10;
}
steplcd();
while(digitalRead(stepsw) == LOW);
interrupts();
}
//------------- Step Screen ---------------------------
void steplcd(){
ucg.setColor(0,0,0); //0,0,0
ucg.drawRBox(111,33,45,11,1); //221,61,93,23,3
ucg.setFont(ucg_font_6x10_mf); //17ucg_font_fub11_tn
ucg.setColor(255,255,255);
ucg.setPrintPos(110,43); //220,80
if (fstep==10000){ucg.print(" 10KHz");}
if (fstep==1000){ucg.print(" 1KHz");}
if (fstep==100){ucg.print(" 100Hz");}
if (fstep==10){ucg.print(" 10Hz");}
}
//----------- Main frequency screen -------------------
void freqlcd(){
ucg.setFont(ucg_font_osr18_tn); //35 ucg_font_fub20_tn
int mojisuu=(freqt.length());
if(freq<1000000){
ucg.setColor(0,0,0);
ucg.drawBox(52,7,9,20); //103,9,15,36
}
if(f100k !=(freqt.charAt(mojisuu-6))){
ucg.setColor(0,0,0);
ucg.drawBox(59,7,15,20); //118,9,28,36
ucg.setPrintPos(59,24); //118,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-6));
f100k = (freqt.charAt(mojisuu-6));
}
if(freq<100000){
ucg.setColor(0,0,0);
ucg.drawBox(59,7,15,20); //118,9,28,36
}
if(f10k !=(freqt.charAt(mojisuu-5))){
ucg.setColor(0,0,0);
ucg.drawBox(73,6,15,20); //146,9,28,36
ucg.setPrintPos(73,24); //146,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-5));
f10k = (freqt.charAt(mojisuu-5));
}
if(freq<10000){
ucg.setColor(0,0,0);
ucg.drawBox(73,6,14,19); //146,9,28,36
}
if(f1k !=(freqt.charAt(mojisuu-4))){
ucg.setColor(0,0,0);
ucg.drawBox(87,6,14,19); //174,9,28,36
ucg.setPrintPos(87,24); //(174,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-4));
f1k = (freqt.charAt(mojisuu-4));
}
if(freq>=1000){
ucg.setPrintPos(101,24); //202,45
ucg.setColor(0,255,0);
ucg.print(".");
}
if(freq<1000){
ucg.setColor(0,0,0);
ucg.drawBox(101,6,8,19); // (202,9,15,36
}
if(f100 !=(freqt.charAt(mojisuu-3))){
ucg.setColor(0,0,0);
ucg.drawBox(109,6,14,19); //217,9,28,36
ucg.setPrintPos(108,24); //(215,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-3));
f100 = (freqt.charAt(mojisuu-3));
}
if(freq<100){
ucg.setColor(0,0,0);
ucg.drawBox(109,6,14,19); //217,9,28,36
}
if(f10 !=(freqt.charAt(mojisuu-2))){
ucg.setColor(0,0,0);
ucg.drawBox(123,6,14,19); //245,9,28,36
ucg.setPrintPos(123,24); //(245,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-2));
f10 = (freqt.charAt(mojisuu-2));
}
/*
if(freq<10){
ucg.setColor(0,0,0);
ucg.drawBox(245,9,28,36);
}
if(f1 !=(freqt.charAt(mojisuu-1))){
ucg.setColor(0,0,0);
ucg.drawBox(273,9,28,36);
ucg.setPrintPos(273,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-1));
f1 = (freqt.charAt(mojisuu-1));
}
*/
}
//----------- Basic Screen -------------------------
void screen01(){
ucg.setColor(255,255,255); //
ucg.drawRFrame(0,0,160,28,3); //0,0,320,55,5 OUTside
//ucg.drawRFrame(0,0,159,27,2); //1,1,318,53,5 INside
ucg.setColor(0,128,255); //FILL COLOR for MODE back
ucg.drawRBox(2,33,30,12,1); //5,60,60,25,3 LSB
ucg.drawRBox(37,33,30,12,1); //75,60,60,25,3 USB
ucg.drawRBox(2,50,30,12,1); //5,90,60,25,3 CW
ucg.drawRBox(37,50,30,12,1); //(75,90,60,25,3 AM
ucg.setFont(ucg_font_6x10_mf); //17
ucg.setPrintPos(9,43); //12,82
ucg.setColor(0,0,0);
ucg.print("LSB");
ucg.setPrintPos(44,43); //82,82
ucg.print("USB");
ucg.setPrintPos(9,60); //12,112
ucg.print("C W");
ucg.setPrintPos(44,60); //(82,112
ucg.print("A M");
ucg.setColor(255,255,255);
ucg.drawRFrame(110,32,47,15,1); //220,60,95,25,3 STEP frame
ucg.drawRFrame(110,50,47,15,1); //220,90,95,25,3 RIT frame
ucg.setColor(255,255,100); //100,100,100
ucg.setPrintPos(7,105); //15,200
ucg.print("S:");
ucg.setPrintPos(7,85); //15,165
ucg.print("P:");
ucg.setFont(ucg_font_6x10_mf); //11ucg_font_fub11_tn
ucg.setColor(250,255,0);
ucg.setPrintPos(80,43); //175,80
ucg.print("STEP");
ucg.setPrintPos(80,60); //190,110
ucg.setColor(255,255,0);
ucg.print("RIT");
ucg.setColor(255,255,255); //100,100,100
ucg.setPrintPos(20,115); //40,210
ucg.print("1--3---6---9--Over---");
ucg.setPrintPos(20,95); //40,175
ucg.print("1--3---5-----10------");
ucg.setPrintPos(5,127); //10,230
ucg.setColor(235,0,200);
ucg.print("si5351a VFO Ver1.1 JA2GQP" );
ucg.setFont(ucg_font_osr18_tn); //35 ucg_font_fub20_tf???
ucg .setPrintPos(37,24); //75,45
ucg.setColor(0,255,0);
ucg.print("7"); //Frequency
ucg.setPrintPos(51,24); //103,45
ucg.print(".");
ucg.setPrintPos(138,24); //273,45
ucg.print("0"); //Frequency end
}
//--------------- VFO Write -------------------------------
void Vfo_write(){
if (flagrit==0){
if(hetero == UPPER)
vfofreq=freq+ifshift;
else
vfofreq=ifshift-freq;
Vfo_out(vfofreq); // DDS out
}
if(flagrit==1){
if(hetero == UPPER)
vfofreq=freq+ifshift+freqrit;
else
vfofreq=ifshift-freqrit-freq;
Vfo_out(vfofreq); // DDS out
}
Bfo_out(ifshift); // BFO
}
回路図、スケッチはダウンロードサイトsi5351a TFTフォルダに2種類有ります。
si5351_TFT18.zip,si5351_TFT181.zip
回路図である。si5351aモジュールのclk2からBFO出力を行っている。
インクルードファイル
si5351aの制御は、ライブラリを使わずに、インクルードファイルで行っている。このファイルをスケッチと同じフォルダーに保存して使う。周波数が変わる毎に発生するクリック低減のため、PLLリセットを行わない事(コメントアウトしてある)とした。但し、位相制御などタイミングを重視する場合、PLLリセットを行う必要が有るであろう。si5351a2.hの内容。
////////////////////////////////////////////////////////////////////////
// Author: Hans Summers, 2015
// Website: http://www.hanssummers.com
//
// A very very simple Si5351a demonstration
// using the Si5351a module kit http://www.hanssummers.com/synth
// Please also refer to SiLabs AN619 which describes all the registers to use
//----------------------------------------------------------------------
// Modifications: JA2GQP,2017/5/20
// 1)Output is CLK0 and CLK2.
// 2)Arduino and stm32duino Operable.
////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#define CLK0_CTRL 16 // Register definitions
#define CLK1_CTRL 17
#define CLK2_CTRL 18
#define MSNA_ADDR 26
#define MSNB_ADDR 34
#define MS0_ADDR 42
#define MS1_ADDR 50
#define MS2_ADDR 58
#define PLL_RESET 177
#define XTAL_LOAD_C 183
#define R_DIV_1 0b00000000 // R-division ratio definitions
#define R_DIV_2 0b00010000
#define R_DIV_4 0b00100000
#define R_DIV_8 0b00110000
#define R_DIV_16 0b01000000
#define R_DIV_32 0b01010000
#define R_DIV_64 0b01100000
#define R_DIV_128 0b01110000
#define Si5351A_ADDR 0x60
#define CLK_SRC_PLL_A 0b00000000
#define CLK_SRC_PLL_B 0b00100000
#define XTAL_FREQ 25000000 // Crystal frequency for Hans' board
////////////////////////////////////////////////////////////////////////
// I2C write
////////////////////////////////////////////////////////////////////////
void Si5351_write(byte Reg , byte Data){
Wire.beginTransmission(Si5351A_ADDR);
Wire.write(Reg);
Wire.write(Data);
Wire.endTransmission();
}
////////////////////////////////////////////////////////////////////////
// Set up specified PLL with mult, num and denom
// mult is 15..90
// num is 0..1,048,575 (0xFFFFF)
// denom is 0..1,048,575 (0xFFFFF)
///////////////////////////////////////////////////////////////////////
void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom){
uint32_t P1; // PLL config register P1
uint32_t P2; // PLL config register P2
uint32_t P3; // PLL config register P3
P1 = (uint32_t)(128 * ((float)num / (float)denom));
P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512);
P2 = (uint32_t)(128 * ((float)num / (float)denom));
P2 = (uint32_t)(128 * num - denom * P2);
P3 = denom;
Si5351_write(pll + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(pll + 1, (P3 & 0x000000FF));
Si5351_write(pll + 2, (P1 & 0x00030000) >> 16);
Si5351_write(pll + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(pll + 4, (P1 & 0x000000FF));
Si5351_write(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(pll + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(pll + 7, (P2 & 0x000000FF));
}
////////////////////////////////////////////////////////////////////////
// Set up MultiSynth with integer divider and R divider
// R divider is the bit value which is OR'ed onto the appropriate
// register, it is a #define in si5351a.h
////////////////////////////////////////////////////////////////////////
void setupMultisynth(uint8_t synth, uint32_t divider, uint8_t rDiv){
uint32_t P1; // Synth config register P1
uint32_t P2; // Synth config register P2
uint32_t P3; // Synth config register P3
P1 = 128 * divider - 512;
P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider
P3 = 1;
Si5351_write(synth + 0, (P3 & 0x0000FF00) >> 8);
Si5351_write(synth + 1, (P3 & 0x000000FF));
Si5351_write(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv);
Si5351_write(synth + 3, (P1 & 0x0000FF00) >> 8);
Si5351_write(synth + 4, (P1 & 0x000000FF));
Si5351_write(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16));
Si5351_write(synth + 6, (P2 & 0x0000FF00) >> 8);
Si5351_write(synth + 7, (P2 & 0x000000FF));
}
////////////////////////////////////////////////////////////////////////
// Switches off Si5351a output
// Example: si5351aOutputOff(CLK0_CTRL);
// will switch off output CLK0
////////////////////////////////////////////////////////////////////////
void si5351aOutputOff(uint8_t clk){
Si5351_write(clk, 0x80); // Refer to SiLabs AN619 to see
//bit values - 0x80 turns off the output stage
}
////////////////////////////////////////////////////////////////////////
// Set CLK0 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL A
// and MultiSynth 0
// and produces the output on CLK0
////////////////////////////////////////////////////////////////////////
void si5351aSetFrequency(uint32_t frequency){
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL A with the calculated multiplication ratio
setupPLL(MSNA_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS0_ADDR, divider, R_DIV_1);
// Reset the PLL. This causes a glitch in the output. For small changes to
// the parameters, you don't need to reset the PLL, and there is no glitch
// Si5351_write(PLL_RESET, 0x20);
// Finally switch on the CLK0 output (0x4F)
// and set the MultiSynth0 input to be PLL A
Si5351_write(CLK0_CTRL, 0x4F | CLK_SRC_PLL_A); // Strength 8mA
}
////////////////////////////////////////////////////////////////////////
// Set CLK1 output ON and to the specified frequency
// Frequency is in the range 1MHz to 150MHz
// Example: si5351aSetFrequency2(10000000);
// will set output CLK0 to 10MHz
//
// This example sets up PLL B
// and MultiSynth 1
// and produces the output on CLK1
////////////////////////////////////////////////////////////////////////
void si5351aSetFrequency2(uint32_t frequency){
uint32_t pllFreq;
uint32_t xtalFreq = XTAL_FREQ;
uint32_t l;
float f;
uint8_t mult;
uint32_t num;
uint32_t denom;
uint32_t divider;
divider = 900000000 / frequency; // Calculate the division ratio. 900,000,000 is the maximum internal
// PLL frequency: 900MHz
if (divider % 2) divider--; // Ensure an even integer
//division ratio
pllFreq = divider * frequency; // Calculate the pllFrequency:
//the divider * desired output frequency
mult = pllFreq / xtalFreq; // Determine the multiplier to
//get to the required pllFrequency
l = pllFreq % xtalFreq; // It has three parts:
f = l; // mult is an integer that must be in the range 15..90
f *= 1048575; // num and denom are the fractional parts, the numerator and denominator
f /= xtalFreq; // each is 20 bits (range 0..1048575)
num = f; // the actual multiplier is mult + num / denom
denom = 1048575; // For simplicity we set the denominator to the maximum 1048575
// Set up PLL B with the calculated multiplication ratio
setupPLL(MSNB_ADDR, mult, num, denom);
// Set up MultiSynth divider 0, with the calculated divider.
// The final R division stage can divide by a power of two, from 1..128.
// reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file)
// If you want to output frequencies below 1MHz, you have to use the
// final R division stage
setupMultisynth(MS2_ADDR, divider, R_DIV_1);
// Reset the PLL. This causes a glitch in the output. For small changes to
// the parameters, you don't need to reset the PLL, and there is no glitch
// Si5351_write(PLL_RESET, 0x80);
// Finally switch on the CLK1 output
// and set the MultiSynth0 input to be PLL B
Si5351_write(CLK2_CTRL, 0x6F | CLK_SRC_PLL_B); // Strength 8mA
}
スケッチ
BFO出力とLOwerヘテロダインに対応。BITX40の設定は、仕様周波数で記述してあるので必要であれば、実周波数に変更する程度で良いだろう。ただ、BITX40実機を持ってないので未確認。//////////////////////////////////////////////////////////////////////////////
// Copyright©2016.JA2GQP.All rights reserved.
// si5351a PLL VFO Ver1.101 << JA2NKD sketch is based >>
// 2017/6/3
// JA2GQP
// << Aruduino IDE 1.8.2 >>
//
//----------------------------------------------------------------------------
// Function
// 1.RIT Operation(-10kHZ to 10kHZ)
// 2.STEP(10,100,1k,10k)
// 3.Memory Operation is Push RIT
// 4.Protection Operation At The Time Of Transmission
// 5.Memory 4ch(LSB,USB.CW,AM)
// 6.IF shift
//----------------------------------------------------------------------------
// Library
// <Rotary.h> https://github.com/brianlow/Rotary
// "Ucglib.h" https://github.com/olikraus/ucglib
//
//////////////////////////////////////////////////////////////////////////////
//---------- include Files ---------------
#include "si5351a2.h"
#include <SPI.h>
#include <Rotary.h>
#include <EEPROM.h>
#include "Ucglib.h"
//---------- TFT setting ---------------
Ucglib_ST7735_18x128x160_HWSPI ucg(/*sclk= 13, data= 11, */ /*cd=*/ 9 , /*cs=*/ 10, /*reset=*/ 8);
//---------- Encorder setting ---------------
#define ENC_A 2 // Encorder A
#define ENC_B 3 // Encoeder B
Rotary r=Rotary(ENC_A,ENC_B);
//---------- I/O setting -------------------
#define modeout1 7 // DIO7
#define modeout2 12 // DIO12
#define modesw 6 // DIO6
#define stepsw 4 // DIO4
#define ritsw 5 // DIO5
#define txsw A3 // A3
#define s_meter A0 // A0
#define t_meter A1 // A1
//---------- EEPROM Memory Address ----------
#define Frq_Eep 0x00 // Frequency(4byte*4)
#define Stp_Eep 0x10 // STEP(4byte*4)
#define Chn_Eep 0x20 // Channel(1byte*1)
#define Mode_Eep 0x22 // Mode(1byte*1)
#define Eep_Int 0x2e // Eep Init(1byte*1)
#define Max_Chn 4 // Max Channel(4ch)
#define Int_End 73 // Initial end code
//----------- Default Frequency Value --------------------
#define UPPER 0 // Upoper heterodyne
#define LOWER 1 // Lower heterodyne
////////////////////////////////////////////////////////////////
// BITX40 Setting example(Upper heterodyne) No.1
////////////////////////////////////////////////////////////////
#define DEF_FRQ 7050000L // Init Frequency
#define DEF_FMAX 7200000L // Frequency Max
#define DEF_FMIN 7000000L // Min
#define DEF_RLSB 10698500L // RX IF Shift LSB
#define DEF_RUSB 10701500L // USB
#define DEF_RCW 10699200L // CW
#define DEF_RAM 10700000L // AM
#define DEF_TLSB 10698500L // TX IF Shift LSB
#define DEF_TUSB 10701500L // USB
#define DEF_TCW 10700000L // CW
#define DEF_TAM 10700000L // AM
byte hetero = UPPER; // Lower heterodyne set
////////////////////////////////////////////////////////////////
// BITX40 Setting example(Lower heterodyne) No.2
////////////////////////////////////////////////////////////////
/*
#define DEF_FRQ 7050000L // Init Frequency
#define DEF_FMAX 7200000L // Frequency Max
#define DEF_FMIN 7000000L // Min
#define DEF_RLSB 11998500L // RX IF Shift LSB
#define DEF_RUSB 12001500L // USB
#define DEF_RCW 11999400L // CW
#define DEF_RAM 12000000L // AM
#define DEF_TLSB 11998500L // TX IF Shift LSB
#define DEF_TUSB 12001500L // USB
#define DEF_TCW 12000000L // CW
#define DEF_TAM 12000000L // AM
byte hetero = LOWER; // Lower heterodyne set
*/
//----------- Default ETC. Value --------------------
#define DEF_STP 100L // Init STEP
#define DEF_Mode 0 // 0=LSB 1=USB 2=CW 3=AM
//---------- Memory Assign ------------------
long freq = DEF_FRQ; // Frequency data
long freqb; // old data
long freqmax = DEF_FMAX; // VFO Upper Limit
long freqmin = DEF_FMIN; // Lower Limit
long freqold = 0;
long freqrit = 0;
String freqt=String(freq);
long ifshift = 0;
long ifshiftb;
long ifshiftLSB = DEF_RLSB; // RX IF Shift LSB
long ifshiftUSB = DEF_RUSB; // USB
long ifshiftCW = DEF_RCW; // CW
long ifshiftAM = DEF_RAM; // AM
long txshiftLSB = DEF_TLSB; // TX IF Shift LSB
long txshiftUSB = DEF_TUSB; // USB
long txshiftCW = DEF_TCW; // CW
long txshiftAM = DEF_TAM; // AM
long vfofreq = 0; // VFO data
long vfofreqb; // old
char f100m,f10m,fmega,f100k,f10k,f1k,f100,f10,f1;
int vfostep=2;
int rit=0;
int fstep = DEF_STP; // Default Step
int fmode;
int fmodeold=1;
int flagrit=0;
int fritold=0;
int flagmode=0;
int smeterval1=0;
int tmeterval=0;
byte Byt_Chn; // Channel SW
byte Byt_Chnb; // Old
//---------- Initialization Program ----------------------
void setup() {
Wire.begin();
delay(100);
ucg.begin(UCG_FONT_MODE_TRANSPARENT);
ucg.clearScreen();
ucg.setRotate90();
pinMode (stepsw,INPUT_PULLUP);
pinMode (ritsw,INPUT_PULLUP);
pinMode(txsw,INPUT_PULLUP);
pinMode(modesw,INPUT_PULLUP);
pinMode(modeout1,OUTPUT);
pinMode(modeout2,OUTPUT);
PCICR |=(1<<PCIE2);
PCMSK2 |=(1 << PCINT18) | (1 << PCINT19);
sei();
screen01();
if(EEPROM.read(Eep_Int) != Int_End){ // Eep initialaz
delay(10);
Fnc_Eep_Int();
}
Byt_Chn = EEPROM.read(Chn_Eep); // Channel
Byt_Chnb = Byt_Chn; //
Fnc_Eep_Rd(); // EEPROM Read
modeset(); // modeset * 4 times
modeset();
modeset();
modeset();
steplcd();
freqt=String(freq);
freqlcd();
}
//---------- Main program ---------------------------------
void loop() {
if (digitalRead(stepsw)==LOW){setstep();}
if (digitalRead(modesw)==LOW){modeset();}
if (digitalRead(ritsw)==LOW){setrit();Fnc_Eep_Wt(Byt_Chn);}
if (digitalRead(txsw)==LOW){txset();}
if(Byt_Chnb != Byt_Chn){ // CH SW OLD != NEW?
Fnc_Eep_Wt(Byt_Chnb);
Byt_Chnb = Byt_Chn;
Fnc_Eep_Rd();
steplcd();
}
if (flagrit==1){
if (freqrit == fritold){
smeter();
}
if (freqrit!=fritold){
Vfo_write();
ritlcd();
fritold=freqrit;
}
}
else{
if (freq == freqold){
smeter();
}
Vfo_write();
freqt=String(freq);
freqlcd();
freqold=freq;
}
}
//---------- Function Eeprom Initialization ------------
void Fnc_Eep_Int(){
int i;
for (i=0;i<48;i++) // 0 clear(48byte)
EEPROM.write(i, 0);
for(i=0;i<Max_Chn;i++){
Fnc_Eep_Sav4(DEF_FRQ,Frq_Eep+i*4); // Frequency(7.10MHz)
Fnc_Eep_Sav4(DEF_STP,Stp_Eep+i*4); // Step(100Hz)
}
EEPROM.write(Chn_Eep,0);
EEPROM.write(Mode_Eep,DEF_Mode);
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))
freq = Fnc_Eep_Lod4(Frq_Eep+Byt_Chn*4);
else{
freq = Fnc_Eep_Lod4(Frq_Eep+0);
Byt_Chn = 0;
}
if((0 <= Byt_Chn) && (Byt_Chn < Max_Chn))
fstep = Fnc_Eep_Lod4(Stp_Eep+Byt_Chn*4);
else
fstep = Fnc_Eep_Lod4(Stp_Eep+0);
fmode = EEPROM.read(Mode_Eep);
}
//---------- Function EEPROM Write -------------------
void Fnc_Eep_Wt(byte chn){
if((0 <= chn) && (chn < Max_Chn)){
Fnc_Eep_Sav4(freq,Frq_Eep+chn*4);
Fnc_Eep_Sav4(fstep,Stp_Eep+chn*4);
}
EEPROM.write(Chn_Eep,Byt_Chn);
EEPROM.write(Mode_Eep,fmode);
}
//---------- 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 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;
}
//---------- VFO out ---------------
void Vfo_out(long frequency){
if(vfofreq != vfofreqb){
si5351aSetFrequency(frequency);
vfofreqb = vfofreq;
}
}
//---------- BFO out ---------------
void Bfo_out(long frequency){
if(ifshift != ifshiftb){
si5351aSetFrequency2(frequency);
ifshiftb = ifshift;
}
}
//---------- S-meter --------------------------
void smeter(){
smeterval1=analogRead(s_meter);
smeterval1=smeterval1/50;
if (smeterval1>14){smeterval1=14;} //15
int sx1=sx1+(smeterval1*9); //16
sx1=sx1+21; //41
int sx2=0;
sx2=sx2+(40+((15-smeterval1)*9)); //ucg_font_6x10_mf
ucg.setFont(ucg_font_fub20_tn); //ucg_font_fub35_tn
ucg.setColor(0,0,0); // BLACK
ucg.drawBox(sx1,99,sx2,8);
ucg.setPrintPos(20,109); //40,200
for(int i=1;i<=smeterval1;i++){
if (i<=8){
ucg.setColor(0,255,255);
ucg.print("-");
}
else{
ucg.setColor(255,0,0);
ucg.print("-");
}
}
}
//---------- Transmission Power meter ------------------
void tmeter(){
ucg.setColor(0,0,0); // BLACK
ucg.drawBox(20,99,135,8); //41,180,270,16
tmeterval=analogRead(t_meter);
tmeterval=tmeterval/50;
if (tmeterval>14){tmeterval=14;}
int sx1=sx1+(tmeterval*9);
sx1=sx1+21;
int sx2=0;
sx2=sx2+(40+((15-tmeterval)*9));
ucg.setFont(ucg_font_fub20_tn); //35ucg_font_fub20_tn
ucg.setColor(0,0,0); //BLACK
ucg.drawBox(sx1,78,sx2,8);
ucg.setPrintPos(20,90); //85(40,165)
for(int i=1;i<=tmeterval;i++){
if (i<=9){
ucg.setColor(250,80,0);
ucg.print("-");
}
else{
ucg.setColor(250,0,0);
ucg.print("-");
}
}
}
//---------- Encoder Interrupt -----------------------
ISR(PCINT2_vect) {
if (flagrit==1){
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freqrit=freqrit+fstep;
if (freqrit>=10000){
freqrit=10000;
}
}
else{
freqrit=freqrit-fstep;
if (freqrit<=-10000){
freqrit=-10000;
}
}
}
}
else{
unsigned char result = r.process();
if(result) {
if(result == DIR_CW){
freq=freq+fstep;
if (freq>=freqmax){freq=freqmax;}
}
else{
freq=freq-fstep;
if (freq<=freqmin){freq=freqmin;}
}
}
}
}
//------------ On Air -----------------------------
void txset(){
long vfofreq_RX = vfofreq;;
long ifshift_RX = ifshift;;
// noInterrupts();
if(hetero == UPPER){ // Upper heterodyne
if (flagmode==0){ifshift=txshiftLSB;}
if (flagmode==1){ifshift=txshiftUSB;}
if (flagmode==2){ifshift=txshiftCW;}
if (flagmode==3){ifshift=txshiftAM;}
vfofreq=freq+ifshift;
}
else{ // Lower heterodyne
if (flagmode==0){ifshift=txshiftLSB;}
if (flagmode==1){ifshift=txshiftUSB;}
if (flagmode==2){ifshift=txshiftCW;}
if (flagmode==3){ifshift=txshiftAM;}
vfofreq=ifshift-freq;
}
Vfo_out(vfofreq); // vfo out
Bfo_out(ifshift); // BFO out
ucg.setPrintPos(70,75); //140,140
ucg.setFont(ucg_font_6x10_mf); //17ucg_font_fub11_tn
ucg.setColor(255,0,0);
ucg.print("ON AIR");
while(digitalRead(txsw) == LOW){
tmeter();
}
vfofreq = vfofreq_RX;
ifshift = ifshift_RX;
ucg.drawBox(15,63,95,15); //30,120,250,30 // ON AIR Erase
Vfo_write();
ucg.drawBox(20,80,135,8); //41,145,270,16 // Level Erase
// interrupts();
}
//------------- Mode change(LSB-USB-CW-AM) ------------
void modeset(){
ucg.setFont(ucg_font_6x10_mf); //17ucg_font_fub11_tn
// if (fmode==0){
if (fmode==1){ // 2016/8/3
ifshift=ifshiftUSB;
flagmode = 1; // 2016/8/3
ucg.setColor(255,255,0); //Black?
ucg.setPrintPos(44,43); //(82,82
ucg.print("USB");
ucg.setPrintPos(9,43); //12,82
ucg.setColor(0,0,0); //Black Yellow
ucg.print("LSB");
digitalWrite(modeout1,HIGH);
digitalWrite(modeout2,LOW);
}
// if(fmode==1){
if(fmode==2){ // 2016/8/3
ifshift=ifshiftCW;
flagmode = 2; // 2016/8/3
ucg.setPrintPos(9,60); //12,112
ucg.setColor(255,255,0); //Yellow
ucg.print("C W");
ucg.setPrintPos(44,43); //82,82
ucg.setColor(0,0,0); //Black
ucg.print("USB");
digitalWrite(modeout1,LOW);
digitalWrite(modeout2,HIGH);
}
// if (fmode==2){
if (fmode==3){ // 2016/8/3
ifshift=ifshiftAM;
flagmode = 3; // 2016/8/3
ucg.setPrintPos(44,60); //82,112
ucg.setColor(255,255,0); //Yellow
ucg.print("A M");
ucg.setColor(0,0,0); //Black
ucg.setPrintPos(9,60); //12,112
ucg.print("C W");
digitalWrite(modeout1,HIGH);
digitalWrite(modeout2,HIGH);
}
// if (fmode==3){
if (fmode==0){ // 2016/8/3
ifshift=ifshiftLSB;
flagmode = 0; // 2016/8/3
ucg.setPrintPos(9,43); //12,82
ucg.setColor(255,255,0); //Yellow
ucg.print("LSB");
ucg.setPrintPos(44,60); //82,112
ucg.setColor(0,0,0); //Black
ucg.print("A M");
digitalWrite(modeout1,LOW);
digitalWrite(modeout2,LOW);
}
fmode=fmode+1;
Byt_Chn++;
if(Byt_Chn > 3)
Byt_Chn = 0;
if (fmode==4){fmode=0;}
Vfo_write();
while(digitalRead(modesw) == LOW);
}
//------------ Rit SET ------------------------------
void setrit(){
if(flagrit==0){
flagrit=1;
ucg.setFont(ucg_font_6x10_mf); //11ucg_font_fub11_tn
ucg.setPrintPos(95,55); //190,110
ucg.setColor(255,0,0);
// freqrit=0;
ritlcd();
}
else {
flagrit=0;
if(hetero == UPPER)
vfofreq=freq+ifshift;
else
vfofreq=ifshift-freq;
Vfo_out(vfofreq); // vfo Out
freqt=String(freq);
ucg.setFont(ucg_font_6x10_mf); //11ucg_font_fub11_tn
ucg.setPrintPos(95,55); //190,110
ucg.setColor(255,255,255);
// ucg.print("RIT");
ucg.setColor(0,0,0);
ucg.drawRBox(112,52,44,10,1); //222,92,91,21,3
freqrit=0;
}
while(digitalRead(ritsw) == LOW);
}
//----------- Rit screen ----------------------
void ritlcd(){
noInterrupts();
ucg.setColor(0,0,0);
ucg.drawBox(111,51,45,13); //222,92,91,21 110,50,47,15,
ucg.setFont(ucg_font_6x10_mf); //17 ucg_font_fub11_tn
ucg.setColor(0,255,255);
ucg.setPrintPos(115,61); //230,110
ucg.print(freqrit);
interrupts();
}
//-------------- encorder frequency step set -----------
void setstep(){
noInterrupts();
if (fstep==10000){
fstep=10;
}
else{
fstep=fstep * 10;
}
steplcd();
while(digitalRead(stepsw) == LOW);
interrupts();
}
//------------- Step Screen ---------------------------
void steplcd(){
ucg.setColor(0,0,0); //0,0,0
ucg.drawRBox(111,33,45,11,1); //221,61,93,23,3
ucg.setFont(ucg_font_6x10_mf); //17ucg_font_fub11_tn
ucg.setColor(255,255,255);
ucg.setPrintPos(110,43); //220,80
if (fstep==10000){ucg.print(" 10KHz");}
if (fstep==1000){ucg.print(" 1KHz");}
if (fstep==100){ucg.print(" 100Hz");}
if (fstep==10){ucg.print(" 10Hz");}
}
//----------- Main frequency screen -------------------
void freqlcd(){
ucg.setFont(ucg_font_osr18_tn); //35 ucg_font_fub20_tn
int mojisuu=(freqt.length());
if(freq<1000000){
ucg.setColor(0,0,0);
ucg.drawBox(52,7,9,20); //103,9,15,36
}
if(f100k !=(freqt.charAt(mojisuu-6))){
ucg.setColor(0,0,0);
ucg.drawBox(59,7,15,20); //118,9,28,36
ucg.setPrintPos(59,24); //118,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-6));
f100k = (freqt.charAt(mojisuu-6));
}
if(freq<100000){
ucg.setColor(0,0,0);
ucg.drawBox(59,7,15,20); //118,9,28,36
}
if(f10k !=(freqt.charAt(mojisuu-5))){
ucg.setColor(0,0,0);
ucg.drawBox(73,6,15,20); //146,9,28,36
ucg.setPrintPos(73,24); //146,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-5));
f10k = (freqt.charAt(mojisuu-5));
}
if(freq<10000){
ucg.setColor(0,0,0);
ucg.drawBox(73,6,14,19); //146,9,28,36
}
if(f1k !=(freqt.charAt(mojisuu-4))){
ucg.setColor(0,0,0);
ucg.drawBox(87,6,14,19); //174,9,28,36
ucg.setPrintPos(87,24); //(174,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-4));
f1k = (freqt.charAt(mojisuu-4));
}
if(freq>=1000){
ucg.setPrintPos(101,24); //202,45
ucg.setColor(0,255,0);
ucg.print(".");
}
if(freq<1000){
ucg.setColor(0,0,0);
ucg.drawBox(101,6,8,19); // (202,9,15,36
}
if(f100 !=(freqt.charAt(mojisuu-3))){
ucg.setColor(0,0,0);
ucg.drawBox(109,6,14,19); //217,9,28,36
ucg.setPrintPos(108,24); //(215,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-3));
f100 = (freqt.charAt(mojisuu-3));
}
if(freq<100){
ucg.setColor(0,0,0);
ucg.drawBox(109,6,14,19); //217,9,28,36
}
if(f10 !=(freqt.charAt(mojisuu-2))){
ucg.setColor(0,0,0);
ucg.drawBox(123,6,14,19); //245,9,28,36
ucg.setPrintPos(123,24); //(245,45
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-2));
f10 = (freqt.charAt(mojisuu-2));
}
/*
if(freq<10){
ucg.setColor(0,0,0);
ucg.drawBox(245,9,28,36);
}
if(f1 !=(freqt.charAt(mojisuu-1))){
ucg.setColor(0,0,0);
ucg.drawBox(273,9,28,36);
ucg.setPrintPos(273,45);
ucg.setColor(0,255,0);
ucg.print(freqt.charAt(mojisuu-1));
f1 = (freqt.charAt(mojisuu-1));
}
*/
}
//----------- Basic Screen -------------------------
void screen01(){
ucg.setColor(255,255,255); //
ucg.drawRFrame(0,0,160,28,3); //0,0,320,55,5 OUTside
//ucg.drawRFrame(0,0,159,27,2); //1,1,318,53,5 INside
ucg.setColor(0,128,255); //FILL COLOR for MODE back
ucg.drawRBox(2,33,30,12,1); //5,60,60,25,3 LSB
ucg.drawRBox(37,33,30,12,1); //75,60,60,25,3 USB
ucg.drawRBox(2,50,30,12,1); //5,90,60,25,3 CW
ucg.drawRBox(37,50,30,12,1); //(75,90,60,25,3 AM
ucg.setFont(ucg_font_6x10_mf); //17
ucg.setPrintPos(9,43); //12,82
ucg.setColor(0,0,0);
ucg.print("LSB");
ucg.setPrintPos(44,43); //82,82
ucg.print("USB");
ucg.setPrintPos(9,60); //12,112
ucg.print("C W");
ucg.setPrintPos(44,60); //(82,112
ucg.print("A M");
ucg.setColor(255,255,255);
ucg.drawRFrame(110,32,47,15,1); //220,60,95,25,3 STEP frame
ucg.drawRFrame(110,50,47,15,1); //220,90,95,25,3 RIT frame
ucg.setColor(255,255,100); //100,100,100
ucg.setPrintPos(7,105); //15,200
ucg.print("S:");
ucg.setPrintPos(7,85); //15,165
ucg.print("P:");
ucg.setFont(ucg_font_6x10_mf); //11ucg_font_fub11_tn
ucg.setColor(250,255,0);
ucg.setPrintPos(80,43); //175,80
ucg.print("STEP");
ucg.setPrintPos(80,60); //190,110
ucg.setColor(255,255,0);
ucg.print("RIT");
ucg.setColor(255,255,255); //100,100,100
ucg.setPrintPos(20,115); //40,210
ucg.print("1--3---6---9--Over---");
ucg.setPrintPos(20,95); //40,175
ucg.print("1--3---5-----10------");
ucg.setPrintPos(5,127); //10,230
ucg.setColor(235,0,200);
ucg.print("si5351a VFO Ver1.1 JA2GQP" );
ucg.setFont(ucg_font_osr18_tn); //35 ucg_font_fub20_tf???
ucg .setPrintPos(37,24); //75,45
ucg.setColor(0,255,0);
ucg.print("7"); //Frequency
ucg.setPrintPos(51,24); //103,45
ucg.print(".");
ucg.setPrintPos(138,24); //273,45
ucg.print("0"); //Frequency end
}
//--------------- VFO Write -------------------------------
void Vfo_write(){
if (flagrit==0){
if(hetero == UPPER)
vfofreq=freq+ifshift;
else
vfofreq=ifshift-freq;
Vfo_out(vfofreq); // DDS out
}
if(flagrit==1){
if(hetero == UPPER)
vfofreq=freq+ifshift+freqrit;
else
vfofreq=ifshift-freqrit-freq;
Vfo_out(vfofreq); // DDS out
}
Bfo_out(ifshift); // BFO
}
登録:
投稿 (Atom)








