このサイトはMacを使って Arduino Uno の動作や活用法を学びます。

33 Arduino モールス通信練習機 5 [完成]

第5回の記事では、モールス練習器からコンピュータに送信するMark時間とSpace時間とを別の行に表示するフォーマットを追加して完成スケッチとします。

使用する部品は、今までと同様に圧電スピーカーと縦振れ電鍵で、以下のピンに接続しています。

 

スケッチの内容

modeSep 変数の値で、コンピュータに送信するフォーマットを切り替えています。modeSep = 0 で、Mark時間とSpace時間が同じ行に表示され、modeSep = 1 では、Mark時間とSpace時間が別の行に表示されます。

modeSep 変数は、起動時に modeSep = 0 に設定されています。シリアル通信で'4'を受信することで、modeSep = 1 に変更されます。

 

// KeyOsc_5
//  MkSp  7-12

#include <EEPROM.h>

#define bounceCk    5    // チャタリング防止する時間
#define gapLenMs    2000  // Gapと判断する時間

int frequency;
int modeSep = 0;    // 出力モード

int keyPin = 2;     // 電顕は pin 2
int spkPin = 8;     // 圧電スピーカーは pin 8
int ledPin = 13;    // 内蔵LEDは pin 13

String sFreq1 = "1 -> Frequency 1000 Hz";
String sFreq2 = "2 -> Frequency  800 Hz";
String sFreq3 = "3 -> Frequency  600 Hz";
String sFreq4 = "4 -> Separated format";
String sFreq5 = "5 -> Combined format";
String sSel = " Selected";
String sTtl = "No  Mark  Space (mS)";

void setup() {
  Serial.begin(115200);           // シリアル通信の設定
  pinMode(keyPin, INPUT_PULLUP);  // 出力に設定
  pinMode(ledPin, OUTPUT);        // 出力に設定
  // コマンド説明
  Serial.println("++++++++++++++++++++++");
  Serial.println("Select Tone Frequency.");
  Serial.println(sFreq1);
  Serial.println(sFreq2);
  Serial.println(sFreq3);
  Serial.println(sFreq4);
  Serial.println(sFreq5);
  Serial.println();
  // EEPROM 読み込み
  ckEEPROMdata();    // EEPROMデータ取得
}

void loop() {
  static uint32_t msTime = 0;     // 経過時間
  if(!digitalRead(keyPin)){       // keyが押されたら
    digitalWrite(ledPin, HIGH);   //   LEDをオン
    tone(spkPin,frequency);       //   サイドトーン ON
  }else{                          // keyが離れていれば
    digitalWrite(ledPin, LOW);    //   LEDをオフ
    noTone(spkPin);               //   サイドトーン OFF
  }
  if(msTime == millis()){
    // シリアル通信でデータ受信した時の処理 ++++++++++++++++
    if(Serial.available()){       // 受信してるなら
      int val = Serial.read();    // 一文字入力し
      setPara(val);               // setPara関数へ
      if((val>='1')&(val<='3')){  // 有効データなら
        EEPROM.write(1, val);     // EEPROMに上書き
        delay(5);                 // 書き込み時間の確保
      }
    }
  }else{                // 1 msに一度実行
    msTime = millis();  // 経過時間を最新に更新
    keyingTime();       // On/Off時間測定
  }
}

// On/Off時間測定 [ステート制御]
void keyingTime(){
  #define start       0     // ステート名
  #define waitKeyDown 1
  #define waitSpace   2
  #define waitMark    3
  static uint32_t mkTime;         // Mark時間計測
  static uint32_t spTime;         // Space時間計測
  static uint32_t gpTime;         // Gap時間計測
  static int state = start;       // 開始ステート
  static int antiCnt = bounceCk;  // チャタリング防止回数
  static int num;                 // 符号番号
  char chStrg[32];                // sprintf作業用

  switch(state){
    case start:       // 制御開始 ---------
      num = 0;                // 符号番号リセット
      Serial.println();       // 改行
      state = waitKeyDown;    // keyが押されるのを待つ
      break;
    case waitKeyDown:   // 電鍵が押されるのを待つ -------
      if(!digitalRead(keyPin)){ // keyが押され続けたら
        if(!antiCnt--){         // 規定回数確認に達したら
          mkTime = millis();    // 時間を取得
          antiCnt = bounceCk;   // 防止回数新たにセット
          if(!modeSep){          // 分離モードでないなら
            Serial.println(sTtl); // タイトル表示
          }
          state = waitSpace;    // keyが離れるのを待つへ
        }
      }else{                    // keyが離れたら
        antiCnt = bounceCk;     // 防止回数を元に戻す
      }
      break;
    case waitSpace:     // 電鍵が離れるのを待つ -------
      if(digitalRead(keyPin)){      // keyが離れ続けたら
        if(!antiCnt--){             // 既に規定回数確認済みなら
          spTime = millis();        // 時間を取得
          mkTime = spTime - mkTime; // Mk時間を計算
          if(modeSep){
            sprintf(chStrg, "M %5d\r\n",mkTime);
          }else{
            sprintf(chStrg, "%2d %5d ", num++, mkTime);
          }
          Serial.print(chStrg);
          antiCnt = bounceCk;       // 防止回数新たにセット
          state = waitMark;         // keyが離れるのを待つへ
        }
      }else{                    // keyが離れたら
        antiCnt = bounceCk;     // 防止回数を元に戻す
      }
      break;
    case waitMark:      // 電鍵が押されるのを待つ -------
      if(!digitalRead(keyPin)){       // keyが押され続けたら
        if(!antiCnt--){               // 規定回数確認に達したら
          mkTime = millis();          // 時間を取得
          spTime = mkTime - spTime;   // Sp時間を計算
          if(modeSep){
            sprintf(chStrg, "S %5d\r\n",spTime);
          }else{
            sprintf(chStrg, "%5d\r\n", spTime);
          }
          Serial.print(chStrg);
          antiCnt = bounceCk;   // 防止回数新たにセット
          state = waitSpace;    // keyが離れるのを待つへ
        }
      }else{                    // keyが離れたら
        antiCnt = bounceCk;     // 防止回数を元に戻す
        gpTime = spTime + gapLenMs;   // Gap時間を計算
        if(millis() > gpTime){        // Gap時間に達したら
          if(modeSep){
            Serial.println("G   ---");
          }else{
            Serial.println("  ---");    // Gapを送信
          }
          state = start;              // keyが離れるのを待つへ
        }
      }
      break;
  } // -end- switch(state)
} // -end- stateControl

// 周波数データの有効性確認と周波数への変換
// 1番地;周波数コード(1, 2, 3)
// 無効データは '3'に読み替える

void ckEEPROMdata(){
  int val = EEPROM.read(1);
  if((val>'3')|(val<'1'))val='3';
  setPara(val);
}

// データを解釈し処理する
void setPara(int val){
  switch(val){
    case '1':   // 1000Hz 周波数変更 -----------
      frequency = 1000;
      Serial.println(sFreq1 + sSel);
      break;
    case '2':   // 800Hz 周波数変更 -----------
      frequency = 800;
      Serial.println(sFreq2 + sSel);
      break;
    case '3':   // 600Hz 周波数変更 -----------
      frequency = 600;
      Serial.println(sFreq3 + sSel);
      break;
    case '4':                   // 分離出力フォーマット
      modeSep = 1;
      Serial.println(sFreq4 + sSel);
      break;
    case '5':                   // 統合出力フォーマット
      modeSep = 0;    //
      Serial.println(sFreq5 + sSel);
      break;
  }
}

 

動作の確認

スケッチを Arduino に書き込みプログラムがスタートしたら、Arduino IDE のシリアルモニターを起動してください。シリアルモニター画面が開いたら以下の手順で操作します。

  1. 通信速度を 115200 に設定する。
  2. ArduinoボードのリセットSWを押す。
  3. 使用できるコマンドがシリアルモニターに表示される。
  4. シリアルモニター上部送信欄に「4」を入力する。
  5. 送信ボタンを押す。
  6. 電鍵でモールス 符号を打つ。
  7. シリアルモニター上に符号のMark時間、Space時間が別行表示される。

 

モールス信号解析アプリ

Arduinoボードからの出力信号は、Arduino IDE シリアルモニターやCoolTermなどの通信ソフトでも表示できます。より直感的に全体像を把握し、細部の検討も可能なアプリケーションをVisual C# 2019 を使い以前に作成しました。今回作成したスケッチもこのアプリに対応しています。詳細は以下の記事をご覧ください。なお、残念ながら Windows 専用アプリです。

モールス信号解析アプリ 1 (Windows) 

 

 

 

モールス信号解析アプリ Processing

Visual C# 2019 のアプリと同等の機能を持つアプリプログラムを Precessingで作成しました。Precessingを使用すれば、WindousでもMacでも使用できるアプリケーションになります。詳細は以下の記事をご覧ください。

 

[p19]】モールス信号解析アプリ (Processing)