Arduinoでモールス符号をLチカ(スケッチしてみる)

久々に使う Arduino Uno R3 の使い方を思い出してみる(中編)

という事で前回、久しぶりに頭の引き出しから出してみたモールスの知識。だいたいの設計は完了したので、実際に書くための準備に入ります。

コードへの落とし込み

Arduinoに落とし込む場合、CPMだ!WPMだ!と言ったところで スケッチ上意味をなさない(Ariduinoが理解できない)単位を持ち出しても意味がありません。Arduinoで理解できる単位で落とし込んでいく必要があります。

最初に定義されたモールス符号の条件

  • 基準となるのは「短点」これを任意の時間で定める。
  • 「長点」は「短点」の3倍の長さと定める。
  • 各点の間は「短点」の長さと同じと定める。
  • 各文字の間は「短点」の3倍の長さと定める。
  • 各単語の間は「短点」の7倍の長さと定める。

これを眺めると、すべてが「短点」の長さに紐づく話になっています。
なので、単純に1短点がどの程度の長さなのかを考えればいいことになります。
Lチカのコードをそのまま流用することを考えると、delayを使用するわけですが、これは “ms” 記述。なら、それぞれのWPMの時の短点の”ms”を計算すればいい。という簡単な結論になります。

WPMと”ms”の変換の検討

1WPM は 1分間に 1Word を打つ計算。1Word は 50Dots ですから、単純に50DPS。 60Sec で 50Dots 打つとなると1Dot あたり 1.2Secで打つ計算になります。ただ 50Dots は Dot が 50キーイングする計算ではなく、Dot幅で50回分の意味。なので、実際にキーイングされる数は十分に小さい数になります。(PARISと打った場合、10 Dots・4 Dashsで、実際にキーイングされている時間は 24Dots 分で、26Dots 分は間の部分になっています。)

これを計算式にすると

    Dot = 60 / (50 * WPM) ※ (Sec)

という感じ。この数式をスケッチにいれときゃOKってことになるでしょうか。

参考までに、手計算した結果。

ライセンス Words Per Minute Dots Per Minute Seconds Per Dot
1アマ 12WPM 600DPM 100ms
2アマ 9WPM 450DPM 133ms
電信アマ 5WPM 250DPM 240ms

割と資格によって速度差があったみたいですね。

単純にこのアイデアを書くとこれだけ。

//
int WPM2SPD(int WPM){
    int Dot;
    Dot = (60 / (50 * (double)WPM))*1000;
    return Dot;
}

うん、単純。

WPMの前に(double)をつけてるの。これは単純に割り算が理由。 この数式。最後の*1000するまでは「小数点以下」の値が出てくる。 だけど、WPMがintだと計算結果が小数点以下切り捨てられてゼロになっちゃう。 なので、キャストしておく。 *1000の部分は単純にSecからmSecへの変換。

モールス符号を仕込む

次は実際にモールスで送信(キーイング)するための情報を準備。 実際に”A”という文字を”・-”に置き換える為の諸情報を与えて上げる必要があります。

ベタにやるなら…

    a[] = {1,2,0,0};
    b[] = {2,1,1,1};
    c[] = {2,1,2,1};
    d[] = {2,1,1,0};
...
    x[] = {2,1,1,2};
    y[] = {2,1,2,2};
    z[] = {2,2,1,1};

こんなアホなやり方もあるだろうけど、これはこれでスタイリッシュさに欠けます。

別方法を考えてみます。文字に対する符号を配列でぶち込んでやればきれいに収まります。 Arduinoの配列は C と同じ感じでこんな感じで記述します。

int morseCode[26][4] = { // DOT=1 , DASH=2 , BLANK=0
    {1,2,0,0}, {2,1,1,1}, {2,1,2,1}, {2,1,1,0}, {1,0,0,0}, // A,B,C,D,E
    {1,1,2,1}, {2,2,1,0}, {1,1,1,1}, {1,1,0,0}, {1,2,2,2}, // F,G,H,I,J
    {2,1,2,0}, {1,2,1,1}, {2,2,0,0}, {2,1,0,0}, {2,2,2,0}, // K,L,N,M,O
    {1,2,2,1}, {2,2,1,2}, {1,2,1,0}, {1,1,1,0}, {2,0,0,0}, // P,Q,R,S,T
    {1,1,2,0}, {1,1,1,2}, {1,2,2,0}, {2,1,1,2}, {2,1,2,2}, // U,V,W,X,Y
    {2,2,1,1} }; // Z

あとは、ABC…の文字に対応して変数の中身が取り出せればいいわけですね。 そうなると、文字を文字コードに変換して数字として取り出してみればいい。 Arduino的には、文字を文字コードにするのはどうすんのよ?となるのですが。これ、考えるまでもなく。

    int CharCode = (int)keyingChar;

で終わりです。”A”が文字コードで 66 ですから、(int)keyingChar-66とすれば対応できることになります。

実際に指定した文字を打ってみる

ここまでおぜん立てしたら、とりあえず、任意の文字を打ってみましょう。 モールスの定義のところで、アルファベット以外の部分を端折ったので、その部分は無いものとして簡単に考えます。

void keying (String Text) {
  int i, j;
  for ( i=0; i<Text.length(); i++) {
    for ( j=0; j<4; j++) {
      switch (morseCode[(int)Text.charAt(i)-65][j]){
        case 1: // DOT
          digitalWrite(LED_BUILTIN, HIGH);
          delay(KeyingSpeed);
          digitalWrite(LED_BUILTIN, LOW);
          delay(KeyingSpeed);
          break;
        case 2: // DASH
          digitalWrite(LED_BUILTIN, HIGH);
          delay(KeyingSpeed*3);
          digitalWrite(LED_BUILTIN, LOW);
          delay(KeyingSpeed);
          break;
        default: // BLANK
          break;
      }
      delay(KeyingSpeed*2);
    }
  delay(KeyingSpeed*4); 
  }
}

delayを使っているので、美しい書き方ではないけれど、Blinkを基準に作るならこんな感じでしょうかね。

と、ここまで考えて時間切れ。 大人の自由研究は本当に時間との戦いだなぁ。 昔ならまとまった時間で一気に遊べたのに…。

という事で次回に続く。

コメント