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

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

モールス信号

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

スポンサーリンク

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

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() 100 200 300 400 500 750 1000
starttime 0 200 200 400 400 400 400
endtime 0 0 300 300 500 500 500
diff 0 0 100 100 100 100 100
decisl() “・” “・”
millis() – endtime 250 500
print(“result”) “result”
duringinput FALSE TRUE TRUE TRUE TRUE TRUE FALSE
decrypted FALSE FALSE FALSE FALSE FALSE FALSE TRUE

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

スポンサーリンク

入力値から復号

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

文字 符号 「・」→「0」
「-」→「1」
BIN2DEC 桁数 16bit 添字
A ・- 01 1 2 0100000000000010 4
B -・・・ 1000 8 4 1000000000000100 23
C -・-・ 1010 10 4 1010000000000100 25
D -・・ 100 4 3 1000000000000011 11
E 0 0 1 0000000000000001 1
F ・・-・ 0010 2 4 0010000000000100 17
G --・ 110 6 3 1100000000000011 13
H ・・・・ 0000 0 4 0000000000000100 15
I ・・ 00 0 2 0000000000000010 3
J ・--- 0111 7 4 0111000000000100 22
K -・- 101 5 3 1010000000000011 12
L ・-・・ 0100 4 4 0100000000000100 19
M -- 11 3 2 1100000000000010 6
N -・ 10 2 2 1000000000000010 5
O --- 111 7 3 1110000000000011 14
P ・--・ 0110 6 4 0110000000000100 21
Q --・- 1101 13 4 1101000000000100 28
R ・-・ 010 2 3 0100000000000011 9
S ・・・ 000 0 3 0000000000000011 7
T 1 1 1 1000000000000001 2
U ・・- 001 1 3 0010000000000011 8
V ・・・- 0001 1 4 0001000000000100 16
W ・-- 011 3 3 0110000000000011 10
X -・・- 1001 9 4 1001000000000100 24
Y -・-- 1011 11 4 1011000000000100 26
Z --・・ 1100 12 4 1100000000000100 27
0 ----- 11111 31 5 1111100000000101 62
1 ・---- 01111 15 5 0111100000000101 46
2 ・・--- 00111 7 5 0011100000000101 38
3 ・・・-- 00011 3 5 0001100000000101 34
4 ・・・・- 00001 1 5 0000100000000101 32
5 ・・・・・ 00000 0 5 0000000000000101 31
6 -・・・・ 10000 16 5 1000000000000101 47
7 --・・・ 11000 24 5 1100000000000101 55
8 ---・・ 11100 28 5 1110000000000101 59
9 ----・ 11110 30 5 1111000000000101 61
・----・ 011110 30 6 0111100000000110 93
-・・・・- 100001 33 6 1000010000000110 96
・-・・-・ 010010 18 6 0100100000000110 81
( -・--・ 10110 22 5 1011000000000101 53
) -・--・- 101101 45 6 1011010000000110 108
* -・・- 1001 9 4 1001000000000100 24
, --・・-- 110011 51 6 1100110000000110 114
. ・-・-・- 010101 21 6 0101010000000110 84
/ -・・-・ 10010 18 5 1001000000000101 49
: ---・・・ 111000 56 6 1110000000000110 119
? ・・--・・ 001100 12 6 0011000000000110 75
@ ・--・-・ 011010 26 6 0110100000000110 89
^ ・・・・・・ 000000 0 6 0000000000000110 63
+ ・-・-・ 01010 10 5 0101000000000101 41

最初考えたのはバイナリ化した符号を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進数リテラル [N3472] - cpprefjp C++日本語リファレンス
整数リテラルのプレフィックスとして`0b`もしくは`0B`を付けることで、2進数を表す値を記述できる。
Arduino日本語リファレンス
Arduino日本語リファレンス

コメント

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