モールス信号を復号したい

スポンサーリンク
スポンサーリンク

モールス信号

モールス信号を復号したい。誰かから送られてきたやつじゃなくて、自分が入力したやつを復号したい。

スポンサーリンク

スイッチを押下・離上間の時間を取得

unsigned long starttime = 0;
unsigned long endtime = 0;
unsigned long diff = 0;

void setup() {
  pinMode(9, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {

  if (digitalRead(9) == LOW) {
    starttime = millis();
    
    while (digitalRead(9) == LOW) {}
    
    endtime = millis();
    diff = endtime - starttime;
    
    Serial.print(diff);
    Serial.println();
    delay(10);
  }
}

とりあえず時間が取れた。

スポンサーリンク

閾値を設定して短点と長点を判断

#define threshold 200

unsigned long starttime = 0;
unsigned long endtime = 0;
unsigned long diff = 0;

void setup() {
  pinMode(9, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {

  if (digitalRead(9) == LOW) {
    starttime = millis();
    while (digitalRead(9) == LOW) {}
    endtime = millis();
    diff = endtime - starttime;

    if (diff < threshold) {
      Serial.print("・");
      Serial.println();
    } else {
      Serial.print("-");
      Serial.println();
    }

    delay(10);
  }
}

判断もできた。こっからだなぁ。

スポンサーリンク

閾値を設定して文字の区切りを取得

#define thresholdsl 200
#define thresholdchr 400

unsigned long starttime = 0;
unsigned long endtime = 0;
unsigned long diff = 0;
boolean duringinput = false;
boolean decrypted = true;

void setup() {
  pinMode(9, INPUT_PULLUP);
  Serial.begin(9600);
}

String decisl(unsigned long t) {
  if (t < thresholdsl) {
    return "・";
  }
  return "-";
}

void loop() {

  if (digitalRead(9) == LOW) {
    starttime = millis();
    
    if (!duringinput) {
      duringinput = true;
      decrypted = false;
    }

    while (digitalRead(9) == LOW) {}
    endtime = millis();
    diff = endtime - starttime;

    Serial.print(decisl(diff));
    Serial.println();
    delay(10);
  }

  if ( (millis() - endtime) > thresholdchr && !decrypted) {
    Serial.print("result");
    Serial.println();
    duringinput = false;
    decrypted = true;
  }
  
}

行き当たりばったりで書いていったらこうなった。もう一回作れと言われると作れなさそう。できるだけ残そ。

短点2つの場合、

millis()1002003004005007501000
starttime0200200400400400400
endtime00300300500500500
diff00100100100100100
decisl()“・”“・”
millis() – endtime250500
print(“result”)“result”
duringinputFALSETRUETRUETRUETRUETRUEFALSE
decryptedFALSEFALSEFALSEFALSEFALSEFALSETRUE

うーん、上手く書けない。こんな感じで遷移してるはず。あとはresultを、入力から対応する文字に復号した結果を表示させるようにすればいいはず。

スポンサーリンク

入力値から復号

Arduinoには、key-value形式で扱えるような、DictionaryとかHashMapみたいなものがない、らしい。探したけど見つかんなかった。「・-」→「A」みたいなデータの引っ張り方はできないってことなのでなにか考えないといかん。最悪switchで愚直に全部書く方法があるけど、それはやだなって思ったので、とりあえず「・」→「0」、「ー」→「1」として、それをkeyにしてデータ引っ張れないかを試してみることにする。

文字符号「・」→「0」
「-」→「1」
BIN2DEC桁数16bit添字
A・-011201000000000000104
B-・・・100084100000000000010023
C-・-・1010104101000000000010025
D-・・10043100000000000001111
E00100000000000000011
F・・-・001024001000000000010017
G--・11063110000000000001113
H・・・・000004000000000000010015
I・・000200000000000000103
J・---011174011100000000010022
K-・-10153101000000000001112
L・-・・010044010000000000010019
M--113211000000000000106
N-・102210000000000000105
O---11173111000000000001114
P・--・011064011000000000010021
Q--・-1101134110100000000010028
R・-・0102301000000000000119
S・・・0000300000000000000117
T11110000000000000012
U・・-0011300100000000000118
V・・・-000114000100000000010016
W・--01133011000000000001110
X-・・-100194100100000000010024
Y-・--1011114101100000000010026
Z--・・1100124110000000000010027
0-----11111315111110000000010162
1・----01111155011110000000010146
2・・---0011175001110000000010138
3・・・--0001135000110000000010134
4・・・・-0000115000010000000010132
5・・・・・0000005000000000000010131
6-・・・・10000165100000000000010147
7--・・・11000245110000000000010155
8---・・11100285111000000000010159
9----・11110305111100000000010161
・----・011110306011110000000011093
-・・・・-100001336100001000000011096
・-・・-・010010186010010000000011081
(-・--・10110225101100000000010153
)-・--・-1011014561011010000000110108
*-・・-100194100100000000010024
,--・・--1100115161100110000000110114
.・-・-・-010101216010101000000011084
/-・・-・10010185100100000000010149
:---・・・1110005661110000000000110119
?・・--・・001100126001100000000011075
@・--・-・011010266011010000000011089
^・・・・・・00000006000000000000011063
+・-・-・01010105010100000000010141

最初考えたのはバイナリ化した符号を10進にして、それを配列の添字にしてあげればデータを引っ張れるんじゃないかと思った。でも、10進数にすると重複が発生してしまい、よろしくなかった。なんかないかなーとネットの海を彷徨っていたら、16bitのデータ長で上位12bit(実際に使われるのは6bit)を短長点、下位4bit(実際に使われるのは3bit)を符号長として表すやり方をみつけた。これでいけそうな気がする。で、2分木として扱えばよさげだなーと思ったので、添字を計算した。でも、なんか記号のプログラムのソースコード上での扱い方がわかんなかったので、上表の9までにしか対応ないことにした。

morsetable.h

const String mtable[] = {
  "", "E", "T", "I", "A", "N", "M", "S", "U", "R", "W", "D", "K", "G", "O", "H", "V", "F", "", "L", "", "P", "J", "B", "X", "C", "Y", "Z", "Q", "", "", "5", "4", "", "3", "", "", "", "2", "", "", "", "", "", "", "", "1", "6", "", "", "", "", "", "", "", "7", "", "", "", "8", "", "9", "0"
};

morse

#include "morsetable.h"

#define pin 9
#define tlsl 200
#define tlchr 400

unsigned long starttime = 0;
unsigned long endtime = 0;
unsigned long diff = 0;
boolean duringinput = false;
boolean decrypted = true;
byte mrsbin [] = {0b0, 0b0};

void setup() {
  pinMode(pin, INPUT_PULLUP);
  Serial.begin(9600);
}

void decisl(unsigned long t) {
  mrsbin[0] = mrsbin[0] << 1;

  if (t > tlsl) {
    mrsbin[0] = mrsbin[0] + 1;
  } else {
    mrsbin[0] = mrsbin[0] + 0;
  }

  mrsbin[1] = mrsbin[1] + 1;
}

int mrstblidx (byte b[]) {
  byte msb = 0b0;
  int idx = 0;

  for (int i = 1; i <= (int)b[1]; i++) {
    msb = ((b[0] << (8 - (int)b[1]) + i - 1) & 0b10000000) >> (8 - i);

    if (msb == 0) {
      idx = 2 * idx + 1;
    } else {
      idx = 2 * idx + 2;
    }
  }
  return idx;
}

void loop() {

  if (digitalRead(pin) == LOW) {
    starttime = millis();

    if (!duringinput) {
      duringinput = true;
      decrypted = false;
    }

    while (digitalRead(pin) == LOW) {}
    endtime = millis();
    diff = endtime - starttime;
    decisl(diff);

    //    Serial.print(mrsbin[0]);
    //    Serial.print(mrsbin[1]);
    //    Serial.println();
    delay(10);
  }

  if ( (millis() - endtime) > tlchr && !decrypted) {
    Serial.print(mtable[mrstblidx(mrsbin)]);
    Serial.println();
    duringinput = false;
    decrypted = true;
    mrsbin [0] = 0;
    mrsbin [1] = 0;
  }

}

こんな感じになった。MSB取り出すところがちょっと気持ち悪いなー。

いー感じだ!ただまぁ、短長点の手癖には対応できてないので機械に人間が合わせる感じになるかな。

スポンサーリンク

参考

モールス符号 - Wikipedia

http://www.kyohritsu.jp/eclib/DIGIT/KIT/morsejamp.pdf

はじめてのPIC18F14K50 モールス解析器
PICの基本動作から応用プログラムまでを学びます。
二分木 - Wikipedia
2進数リテラル - cpprefjp C++日本語リファレンス
整数リテラルのプレフィックスとして`0b`もしくは`0B`を付けることで、2進数を表す値を記述できる。
Arduino 日本語リファレンス
Arduino 日本語リファレンス

コメント

タイトルとURLをコピーしました