前回の続きです。
組み立て完了しました。
ケース内部は余裕がありますが、歳をとったのでケースは大きめのほうが加工が楽です。
AH-4との接続ケーブルもDINコネクタにでもすればよかったと後から思いましたが、まあ良しとします。
せっかく CAT 制御可能なので、外部スイッチで以下の制御も実装しました。
1. ブレークインの ON/OFF
2. フィルタ切り替え
3. CWメモリ#1~#3送信
1 と 2 は以前 ICOM 用の CI-V 制御の VFO を作ったときも実装したもので、やはりあると便利。また、FTDX10 はメモリーキーヤーを使う場合、キーヤーボタンを表示しておかなければならず、そうするとウォーターフォールが見えなくなってしまい非常に不便でしたので、3 も必須と思っていました。
ところで、ヤエスの CAT オペレーションリファレンスマニュアルに間違いがあり、少々ハマりました。
ルーフィングフィルタの切り替えコマンドは RG と書いてありますが、RF が正しい。RG は RF Gain のコマンドで全然違う値が返ってくるので当初 ? 状態でした。さらに、
- Answer 項目の 4 は P2 ではなく P3
- Read 項目では RF P1 P3 が戻る
が実際の動作となります。皆様お気をつけくださいー。
外部スイッチはタッパーウェアを使いました。
リグの横に設置。上の TS-130V は飾り、ではなく現役で 7MHz FT-8 で使用しています。7.042MHz 用に水晶を入れて使ってますが、最近この周波数変更の議論が出ていて動向が気になります。
これで AH-4 の操作性は ICOM 機とほとんど同じになりました。ヨカッタ。なお、今回、FTDX-10 を購入したので移動局免許状に加えて固定局の免許を申請し、免許が来ました。しかし、総務省のサイトは移動局の免許しか表示されず 50W のままです。そういうものなのかな?
回路図
アナログポートで複数スイッチを使う方法はしなぷすさんの I/Oピン一つで読めるキーパッドの設計サービス を使用させていただきました。以前作成したエレキーでは外部ボタンに個別に配線していたので 5P のマイクコネクタを使い、ケーブルも太くなってしまいましたが、しなぷすさんの方法は目からウロコでした。ありがとうございます。
Arduino ソース
/* Arduino NANO
* VID:1A86
* PID:7523
*
* 2022/7/30 ver3
* - 電源LED用コード追加
* - External Push SW 用に ResKeypard2.ino を統合
*
* 2022/6/20 ver2
* - Arduino NANO に移植
* (特に変更点なし)
*
* 2022/6/19 ver1
* - pow_mode2.ino を元に作成
* *
* 注意:書き込み時はシリアルポート接続を切ること
* ボード Uno
* VID 2A03
* PID 0043
*/
#include <ResKeypad.h> // キーを読み取るためにResKeypadライブラリを使う
#include <SoftwareSerial.h> // for comms to Rig
#define BAUD_CAT 9600 // CAT serial speed
#define BAUD_PC 9600 // PC debug serial speed
#define Pin_Meter 9 // SWR Meter output
#define Pin_RX 8
#define Pin_TX 7
#define Pin_AH4 6 //to relay
#define Pin_Start 5
#define Pin_LED 4 //show execution
#define Pin_Power_LED 10
#define Power_Tune "PC010;" //RF output power when AH-4 tune
#define Mode_Tune "MD06;" //MODE when AH-4 tune
#define Meter_SWR "RM6;" //RM6=SWR, RM1=S-meter
SoftwareSerial mySerial = SoftwareSerial(Pin_RX, Pin_TX); // (RX, TX)
uint8_t u8state;
unsigned long waitSWR, waitCMD;
const long intSWR=100;
const long intTX=2000;
const long intCMD=500; // 500;
String exPower, exMode;
boolean chkSWR=false;
const int AIN = A0; // キーの読み取りに使用するアナログ入力ピン
const int KeyNum = 5; // 読み取るキーの個数
signed char exKey; //チャタリング検知のため直前のキーを保持
PROGMEM const int threshold[KeyNum] = { // 入力電圧の閾値
// 次の数列は、しなぷすのハード製作記の回路設計サービスで計算して得られたもの
89, 296, 516, 733, 935
};
ResKeypad keypad(AIN, KeyNum, threshold); //以後keypadオブジェクトを使って、スイッチの読み取りができる
void setup()
{
Serial.setTimeout(10);
Serial.begin(BAUD_CAT, SERIAL_8N2);
pinMode(13, OUTPUT); digitalWrite(13, LOW); // force LED (pin 13) to turn off.
pinMode(Pin_RX, INPUT); // serial communication from PC
pinMode(Pin_TX, OUTPUT); // serial communication to PC
pinMode(Pin_AH4, OUTPUT); digitalWrite(Pin_AH4, LOW); //AH4 control
pinMode(Pin_Start, INPUT_PULLUP); // Start button
pinMode(Pin_Meter, OUTPUT); //SWR Meter
pinMode(Pin_LED, OUTPUT); digitalWrite(Pin_LED, LOW); //show execution
pinMode(Pin_Power_LED, OUTPUT); digitalWrite(Pin_Power_LED, HIGH);
mySerial.begin(BAUD_PC);
mySerial.listen(); // only one port can be made to listen with software serial
// see reference https://www.arduino.cc/en/Reference/SoftwareSerialListen
while (mySerial.available()) mySerial.read(); // clean buffer
u8state=0;
waitSWR = millis() + intSWR;
waitCMD = millis() + intCMD;
exKey=127;
mySerial.println("setup() done.");
}
//---------------------------------------------------------------------------------------------
String rig_ctl(String cmd) {
String data;
Serial.write(cmd.c_str());
delay(25); //delay(10) にするとまだ文字がすべて到達していない。
int nbChar = Serial.available();
if (nbChar > 0) {
data=Serial.readString();
}
mySerial.print("sent cmd=");mySerial.print(cmd);
mySerial.print("\trec data=");mySerial.println(data);
return data;
}
String rig_ctl_NM(String cmd) { //No Message output
String data;
Serial.write(cmd.c_str());
delay(25); //delay(10) にするとまだ文字がすべて到達していない。
int nbChar = Serial.available();
if (nbChar > 0) {
data=Serial.readString();
}
return data;
}
void getSWR() {
String s=rig_ctl_NM(Meter_SWR); //RM1 S-meter
long value=s.substring(3,6).toInt();
analogWrite(Pin_Meter, value);
}
void loop() {
String s;
int btn_start;
signed char key;
if (chkSWR&&(millis() > waitSWR)) {
getSWR(); // wait state
waitSWR=millis()+intSWR;
}
key=keypad.GetKeyState();
switch( u8state ) {
case 0:
if (key<0) {
exKey=127; //キーが連続して押されなかったので前回キーをリセット
btn_start=digitalRead(Pin_Start);
if (btn_start==LOW) {
u8state=2;
waitCMD=millis()+intCMD;
}
} else {
if (key!=exKey) {
u8state=key+100;
}
exKey=key;
}
break;
case 1:
/* getSWR() */
u8state=0;
break;
case 2:
mySerial.println("--- start ---");
digitalWrite(Pin_LED, HIGH);
//read power
exPower=rig_ctl("PC;");
u8state++; // wait state
break;
case 3:
if (millis() > waitCMD) {
waitCMD=millis()+intCMD;
//set power
s=rig_ctl(Power_Tune);
u8state++; // wait state
}
break;
case 4:
if (millis() < waitCMD) break;
waitCMD=millis()+intCMD;
//read mode
exMode=rig_ctl("MD0;");
//set mode
s=rig_ctl(Mode_Tune);
u8state++; // wait state
break;
case 5:
if (millis() < waitCMD) break;
waitCMD=millis()+intCMD;
//verify power before TX
s=rig_ctl("PC;");
if (!s.equals(Power_Tune)) {
mySerial.println("CAT [PC] command response is invalid.");
digitalWrite(Pin_LED, LOW);
u8state=0;
break;
}
//tx on
chkSWR=true;
//mySerial.println("tx on");
s=rig_ctl("TX1;");
u8state++; // wait state
break;
case 6:
if (millis() < waitCMD) break;
waitCMD=millis()+intCMD;
//AH-4 tune start
digitalWrite(Pin_AH4, HIGH);
mySerial.println("AH4 on");
u8state++; // wait state
break;
case 7:
if (millis() < waitCMD) break;
waitCMD=millis()+intTX; //next TX
digitalWrite(Pin_AH4, LOW);
mySerial.println("AH4 off");
u8state++;
break;
case 8:
if (millis() < waitCMD) break;
waitCMD=millis()+intCMD;
//tx off
mySerial.println("tx off");
s=rig_ctl("TX0;");
chkSWR=false;
//restore original
s=rig_ctl(exPower);
s=rig_ctl(exMode);
mySerial.println("original value restored");
digitalWrite(Pin_LED, LOW);
u8state = 0;
break;
case 100: //Memory Keyer 1
s=rig_ctl("KY6;");
u8state = 0;
break;
case 101: //Memory Keyer 2
s=rig_ctl("KY7;");
u8state = 0;
break;
case 102: //Memory Keyer 3
s=rig_ctl("KY8;");
u8state = 0;
break;
case 103: //Filter (マニュアルは間違えている Set/Read で値が変わるので注意)
s=rig_ctl("RF0;");
if (s.equals("RF06;")) {
rig_ctl("RF02;");
} else if (s.equals("RF07;")) {
rig_ctl("RF04;");
} else if (s.equals("RF09;")) {
rig_ctl("RF01;"); //300Hz filter を買ったら RF05 にする
} else if (s.equals("RF0A;")) {
rig_ctl("RF01;");
}
u8state = 0;
break;
case 104: //Break-in (設定可能状態でないとコマンドエラーになる。例: モードがCW以外など)
s=rig_ctl("BI;");
if (s.equals("BI0;")) {
rig_ctl("BI1;");
} else {
rig_ctl("BI0;");
}
// delay(500);
u8state = 0;
break;
} //end switch()
}