今まで勉強してきたRaspberry Pi Picoの機能活用とMicroPythonのプログラミングの練習としてモールス符号練習機(Morse Trainer)を作ってみました。
電池2本でスタンドアローンで動作します。モードはランダムモードとABC順モードの2つです。速度は10kΩボリュームで6wpm~24wpmの間で調整できます。文字はOLEDに表示します。モールス音は、GPIO0に接続したスピーカーから出ます。周波数は700Hz固定としました。スタートボタンを押すと符号の送出が始まり、途中でこのボタンを押すと止まります。
プログラミングの前に、モールス符号について説明します。モールス符号は、短点(dot)と長点(dash)の組み合わせで文字を表現します。文字内のdotまたはdashの間は1dotの時間、文字間は3dotの時間、語間は、7dotの時間と定められています。
モールス通信の速度は、語/分(wpm(word per minute) )で表します。1語として「PARIS」という語を使い、下の図のように語間スペースも含めると50dot分になります。
従って、1dotの時間(ms)は、1200/wpmで計算できます。逆に速度wpmは、1200/1dot(ms)で計算できます。良く使われる字/分は、wpm×5字/分となります。
今回速度の可変範囲は、6wpm(30字/分)~24wpm(120字/分)としました。コンテストなどでも20wpmを聞き取れれば大丈夫です。
スクリプトです。音を出すときは、pwm.duty_u16(0x8000)とし、700Hzデューティ比50%のPWM信号をGPIO0に出力します。spaceなど音を出さないときは、pwm.duty_u16(0)としてPWM信号を出しません。
Picoの出力ポートは力持ちで、直接スピーカーをつないで音を出すことができます。ただし、音量は変えられません。
なお、スクリプトは、main.pyとしてPicoに保存します。ssd1306というライブラリーを利用しますので、前のOLEDテストの記事に記載したようにダウンロードしてPicoにインストールしておきます。
-----------------------------------------------------------------------------------
"""
Morse Trainer Ver1
2021.11.27
JH7UBC Keiji Hata
"""
from machine import I2C,Pin,PWM,ADC
import random
import utime
import ssd1306
M_code = [".-","-...","-.-.","-..",".","..-.","--.","....","..",
".---","-.-",".-..","--","-.","---",".--.","--.-",".-.",
"...","-","..-","...-",".--","-..-","-.--","--.."]
moji = ["A","B","C","D","E","F","G","H","I","J","K","L","M",
"N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
mode_txt=["RAND","ABCD"]
def text_clr():
oled.fill_rect(0,8,127,63,0)
def random_txt():
global x0
global y0
column = 0
row=0
count=0
while True:
speed_read()
x = x0 + 8 * column
y = y0 + 8 * row
i=int(random.random() * 26)
oled.text(moji[i],x,y)
oled.show()
morse_out(i)
column =column + 1
count = count +1
if count > 3:
column = column +1
count =0
if column >14:
column = 0
row = row + 1
if row > 5:
break
if start_sw.value()==0:
break
def abcd_txt():
global x0
global y0
column = 0
row=0
count=0
for i in range(26):
speed_read()
x = x0 + 8 * column
y = y0 + 8 * row
oled.text(moji[i],x,y)
oled.show()
morse_out(i)
column =column + 1
count = count +1
if count > 3:
column = column +1
count =0
if column >14:
column = 0
row = row + 1
if start_sw.value()==0:
break
def dot():
pwm.duty_u16(0x8000)
utime.sleep_ms(dot_time)
def space():
pwm.duty_u16(0)
utime.sleep_ms(dot_time)
def dash():
pwm.duty_u16(0x8000)
utime.sleep_ms(dot_time)
utime.sleep_ms(dot_time)
utime.sleep_ms(dot_time)
def char_space():
pwm.duty_u16(0)
utime.sleep_ms(dot_time)
utime.sleep_ms(dot_time)
def morse_out(n):
m=M_code[n]
l=len(m)
for j in range(l):
s=m[j]
if s==".":
dot()
elif s=="-":
dash()
space()
char_space()
def mode_disp(m):
oled.fill_rect(16,0,32,8,0)
oled.show()
oled.text(mode_txt[m],16,0)
oled.show()
def mode_change():
utime.sleep_ms(10)
global mode
mode = mode +1
if mode>1:
mode=0
mode_disp(mode)
def start_morse():
global mode
utime.sleep_ms(10)
text_clr()
if mode==0:
mode_disp(mode)
random_txt()
elif mode==1:
abcd_txt()
def speed_read():
global wpm
global dot_time
global dash_time
dot_time=speed.read_u16() >> 8
if dot_time < 50:
dot_time=50
if dot_time >200:
dot_time=200
wpm=int(1200/dot_time)
wpm_disp()
def wpm_disp():
global wpm
global old_wpm
if wpm != old_wpm:
oled.fill_rect(96,0,32,8,0)
oled.show()
oled.text(str(wpm),96,0)
oled.show()
old_wpm=wpm
#setup
i2c=I2C(0,sda=Pin(16),scl=Pin(17),freq=400000)
oled=ssd1306.SSD1306_I2C(128,64,i2c)
#ピン割り当てと設定
start_sw=Pin(15,Pin.IN,Pin.PULL_UP)
mode_set=Pin(14,Pin.IN,Pin.PULL_UP)
speed=ADC(0)
#PWM設定
pwm=PWM(Pin(0))#morse音をPin0に出力
pwm.freq(700) #tone=700Hz
pwm.duty_u16(0)#最初、音を出さない
x0 = 8
y0 = 16
mode = 0
mvalue=0
old_mvalue= 0
svalue=0
old_svalue=0
wpm = 10
old_wpm =0
#初期画面表示
oled.text("M: WPM:",0,0)
oled.show()
mode_disp(mode)
wpm_disp()
#main loop
while True:
speed_read()
mvalue=mode_set.value()
if mvalue==0 and old_mvalue==1:
mode_change()
old_mvalue=mvalue
svalue=start_sw.value()
if svalue==0 and old_svalue==1:
start_morse()
old_svalue=svalue
utime.sleep_ms(10)
-----------------------------------------------------------------------------------
ブレッドボードです。
ABC順モードです。
白いボタンがSTART/STOP、青いボタンがモードボタンです。速度は右上に表示されます。
電池は、39番ピンVSYSに接続します。
※コメント投稿者のブログIDはブログ作成者のみに通知されます