回路図である。
ダイレクトコンバージョン受信機と組合わせた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;
}
}