モールス信号
モールス信号を復号したい。誰かから送られてきたやつじゃなくて、自分が入力したやつを復号したい。
スイッチを押下・離上間の時間を取得
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取り出すところがちょっと気持ち悪いなー。
いー感じだ!ただまぁ、短長点の手癖には対応できてないので機械に人間が合わせる感じになるかな。
参考
![](https://upload.wikimedia.org/wikipedia/commons/9/9c/J38TelegraphKey.jpg)
http://www.kyohritsu.jp/eclib/DIGIT/KIT/morsejamp.pdf
![](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Binary_tree.svg/640px-Binary_tree.svg.png)
コメント