トリオ TS-120/TS-130シリーズで電波を出そうの会
Day34 - TS-120S専用PLL VFOを作る(5)
最終更新:
ts-120s
-
view
せっかくだから、CWモードでの実用性もアップさせましょう。
https://w.atwiki.jp/ts-120s/pages/21.html
上記のおさらいですが、TS-120SのCWモードにおける周波数シフトはVFO自体に任されており、「送信時(+700Hz)の周波数」が、世間に出回る大多数の無線機でCWのダイアルを合わせたときの周波数です。
上記のおさらいですが、TS-120SのCWモードにおける周波数シフトはVFO自体に任されており、「送信時(+700Hz)の周波数」が、世間に出回る大多数の無線機でCWのダイアルを合わせたときの周波数です。
さすがにTS-120S自体の周波数表示を現代準拠に変えるのはややこしいですが、とりあえずPLL VFOを少し改良し、CWで送信する際に+700Hz周波数をシフトするようにしましょう。
基本戦略。
- TS-120SのDIN 8pinには、CWモードの送信時に限り、PIN4にCW TX +9Vが出力されます。本来外部VFO(VFO-120)のTXシフトを実現するためのものですが、これを2.0~3.3Vぐらいに落として、GPIOをhighにすることにしました。(*1)
- Pi picoにはGPIO12ピンに入れることにしました。抵抗の分圧で落とすもよしですが、レギュレータを使った方が簡易なので、手持ちの低ドロップタイプ三端子レギュレータ(3.3V 100mA) LP2950L-3.3を介してぶっこみましょう。(*2)
- Pythonコードは、GPIOがhighになったら、VFOの周波数に+700Hzシフトを掛けるように小変更ですね。
実装前にDIN PIN4を確認する。
状態 | PIN4 出力電圧 |
SSB RX時 | -1.9V |
CW RX時 | -1.9V |
CW TX時 | +9.0V |
絶対こういうのは確認したほうがいいですね。受信中はマイナス電圧がかかるようです。
入力に直列にシリコン整流ダイオードを加えて、(電圧はドロップしますが)逆電圧がかからないようにします。
僕は接続ケーブルのコネクタの中に10D1的なものを仕込んじゃいました。
入力に直列にシリコン整流ダイオードを加えて、(電圧はドロップしますが)逆電圧がかからないようにします。
僕は接続ケーブルのコネクタの中に10D1的なものを仕込んじゃいました。

というわけで、ミニステレオジャックまわりに三端などを実装します。
ここで、Python 3分クッキング(謎)のお時間です。
CW送信時の700Hzシフトも加えちゃいましょう。
GPIO12がhighになった時に700Hzを足すようにコードをちょいと変更です。
GPIO12がhighになった時に700Hzを足すようにコードをちょいと変更です。
from machine import Pin, I2C, Timer
from time import sleep, ticks_ms, ticks_diff
# --------------------------
# SI5351 クラス定義
# --------------------------
class SI5351:
SI5351_ADDRESS = 0x60
def __init__(self, i2c):
self.i2c = i2c
def write_register(self, register, data):
self.i2c.writeto_mem(self.SI5351_ADDRESS, register, bytes([data]))
def write_bulk(self, register, data_list):
self.i2c.writeto_mem(self.SI5351_ADDRESS, register, bytes(data_list))
def init(self):
self.write_register(3, 0xFF) # Disable all outputs
self.write_register(16, 0x80) # Power down CLK0
self.write_register(177, 0xAC) # Crystal load = 10pF
def gcd(self, a, b):
while b:
a, b = b, a % b
return a
def approximate_fraction(self, num, denom, max_denominator=1_048_575):
if num == 0:
return 0, 1
g = self.gcd(num, denom)
num //= g
denom //= g
if denom > max_denominator:
scale = denom // max_denominator + 1
denom //= scale
num //= scale
return num, denom
def set_freq(self, freq_hz, clk=0):
XTAL_FREQ = 24_999_497
PLL_FREQ = 900_000_000
MULT = PLL_FREQ // XTAL_FREQ
num = PLL_FREQ % XTAL_FREQ
denom = XTAL_FREQ
num, denom = self.approximate_fraction(num, denom)
pll_params = self.calc_params(MULT, num, denom)
self.set_pll(pll='A', params=pll_params)
div = PLL_FREQ // freq_hz
num = PLL_FREQ % freq_hz
denom = freq_hz
num, denom = self.approximate_fraction(num, denom)
ms_params = self.calc_params(div, num, denom)
self.set_ms(clk, pll='A', params=ms_params)
self.write_register(3, 0xFE & ~(1 << clk)) # Enable CLKx
ms_div = div + num / denom
actual_freq = PLL_FREQ / ms_div
return actual_freq
def calc_params(self, mult, num, denom):
P1 = 128 * mult + int(128 * num / denom) - 512
P2 = 128 * num - denom * int(128 * num / denom)
P3 = denom
return (P1, P2, P3)
def set_pll(self, pll='A', params=(0, 0, 1)):
base = 26 if pll == 'A' else 34
P1, P2, P3 = params
data = [
(P3 >> 8) & 0xFF, P3 & 0xFF,
(P1 >> 16) & 0x03,
(P1 >> 8) & 0xFF, P1 & 0xFF,
((P3 >> 12) & 0xF0) | ((P2 >> 16) & 0x0F),
(P2 >> 8) & 0xFF, P2 & 0xFF
]
self.write_bulk(base, data)
def set_ms(self, clk, pll='A', params=(0, 0, 1)):
base = 42 + clk * 8
P1, P2, P3 = params
data = [
(P3 >> 8) & 0xFF, P3 & 0xFF,
(P1 >> 16) & 0x03 | (0b00 << 6), # clk invert, int mode = 0
(P1 >> 8) & 0xFF, P1 & 0xFF,
((P3 >> 12) & 0xF0) | ((P2 >> 16) & 0x0F),
(P2 >> 8) & 0xFF, P2 & 0xFF
]
self.write_bulk(base, data)
self.write_register(16 + clk, 0x0F | (0 << 6)) # CLKx Control
# --------------------------
# GPIO設定
# --------------------------
i2c = I2C(0, scl=Pin(17), sda=Pin(16), freq=100_000)
enc_a = Pin(14, Pin.IN, Pin.PULL_UP)
enc_b = Pin(15, Pin.IN, Pin.PULL_UP)
button_step = Pin(13, Pin.IN, Pin.PULL_UP)
shift_input = Pin(12, Pin.IN, Pin.PULL_DOWN)
# --------------------------
# 状態初期化
# --------------------------
step_sizes = [100, 500, 1000, 10000]
step_index = 2
base_freq = 5_500_000
# --------------------------
# Si5351 初期化
# --------------------------
si5351 = SI5351(i2c)
si5351.init()
si5351.set_freq(base_freq)
# --------------------------
# ステップ切替ボタン
# --------------------------
last_button_time = 0
def handle_button(pin):
global step_index, last_button_time
now = ticks_ms()
if ticks_diff(now, last_button_time) > 300:
step_index = (step_index + 1) % len(step_sizes)
last_button_time = now
button_step.irq(trigger=Pin.IRQ_FALLING, handler=handle_button)
# --------------------------
# ロータリーエンコーダ
# --------------------------
enc_table = {
(0b00, 0b01): 1,
(0b01, 0b11): 1,
(0b11, 0b10): 1,
(0b10, 0b00): 1,
(0b00, 0b10): -1,
(0b10, 0b11): -1,
(0b11, 0b01): -1,
(0b01, 0b00): -1,
}
last_enc = (enc_a.value() << 1) | enc_b.value()
rotate_dir = 0
update_flag = False
new_freq = 0
def check_encoder(timer):
global last_enc, rotate_dir, update_flag, new_freq, base_freq
current = (enc_a.value() << 1) | enc_b.value()
if current != last_enc:
dir = enc_table.get((last_enc, current), 0)
if dir != 0:
step = step_sizes[step_index]
temp_freq = base_freq + dir * step
new_freq = temp_freq
rotate_dir = dir
update_flag = True
last_enc = current
timer = Timer()
timer.init(freq=2000, mode=Timer.PERIODIC, callback=check_encoder)
last_shift_state = shift_input.value()
# --------------------------
# メインループ
# --------------------------
while True:
if update_flag:
update_flag = False
base_freq = new_freq
freq = base_freq + (700 if shift_input.value() else 0)
si5351.set_freq(freq)
current_shift_state = shift_input.value()
if current_shift_state != last_shift_state:
sleep(0.01)
if current_shift_state != shift_input.value():
last_shift_state = current_shift_state
continue
last_shift_state = current_shift_state
freq = base_freq + (700 if current_shift_state else 0)
si5351.set_freq(freq)
sleep(0.05)
こんなんでましたけど。
結果。
早速試してみましたが、問題なく使えました。
120本体VOX ON、外付メモリーキーヤーを使い、7MHz CWで国内QSOしてみましたが、問題なくシフトに追従してくれます。
呼んだら応答あるし、CQ出したら呼んできてくれるので、大丈夫そうです。
120本体VOX ON、外付メモリーキーヤーを使い、7MHz CWで国内QSOしてみましたが、問題なくシフトに追従してくれます。
呼んだら応答あるし、CQ出したら呼んできてくれるので、大丈夫そうです。
もしCW運用の利便性をより追及するのなら、「+700Hzシフトを考慮した受信周波数にして、500Hzステップ」などというのをやってみてもいいかもしれませんね。
コード触って遊んでみてください。
コード触って遊んでみてください。