micro:bit でモールス信号送信したくて、その前に Delphi でロジック考えた際の記録
基本ルール
- 扱うのはアルファベット (A - Z) の 26 文字のみ
- micro:bit を想定しているので、2 つのボタンでトン・ツーを表現する
- 文字と文字の間は 1 ~ 2 秒あける
- 単語の終了は 3 秒以上あける
- 単語終了したらメモに表示する
- Clear ボタンを押したらトン・ツーをリセット
モールス符号は、wikipedia に掲載されている欧文モールス符号のアルファベットを使います
micro:bit を想定しているので、長押しの検知ではなく 2 つのボタンを使用して表現するルールを考えたらこんなルールになりました
実際 micro:bit 側では、AB ふたつのボタンと、AB のボタン同時押し、シェイクを使って、文字と単語の構成等々を行いましたが、先にロジック的なものができていたので、実装は楽でした
変換テーブルを作ったほうがいいよなぁ..
micro:bit は配列を定義できるので、アルファベットと、トン(A)ツー(B)を表した配列テーブルを作成するのが良さそうだ
モールス符号 | アルファベット |
---|---|
AB | A |
BAAA | B |
BABA | C |
BAA | D |
A | E |
AABA | F |
BBA | G |
AAAA | H |
AA | I |
ABBB | J |
BAB | K |
ABAA | L |
BB | M |
BA | N |
BBB | O |
ABBA | P |
BBAB | Q |
ABA | R |
AAA | S |
B | T |
AAB | U |
AAAB | V |
ABB | W |
BAAB | X |
BABB | Y |
BBAA | Z |
文字間や単語の終了の判断はタイマー使おーっと
最初は、自分でカウントしようかと思っていましたが、タイマー使ったほうが楽じゃんってことに気が付いた
設計画面はこんなの
Timer の Interval プロパティはそれぞれ 1000と 3000をセット、また Timer の Enabled プロパティはそれぞれ False にします
サンプルコード
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ScrollBox,
FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls;
type
TMorse = Record // 変換テーブル
xWord: string;
xAlpha: string;
end;
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Memo1: TMemo;
Timer1: TTimer;
Timer2: TTimer;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
private
// mWord はトンツー(AB)文字列を格納
// mLine は変換した文字列を格納
// mMorse は変換テーブル
mWord, mLine: string;
const mMorse: Array[0..25] of TMorse = (
(xWord: 'AB' ; xAlpha: 'A'),
(xWord: 'BAAA'; xAlpha: 'B'),
(xWord: 'BABA'; xAlpha: 'C'),
(xWord: 'BAA' ; xAlpha: 'D'),
(xWord: 'A' ; xAlpha: 'E'),
(xWord: 'AABA'; xAlpha: 'F'),
(xWord: 'BBA' ; xAlpha: 'G'),
(xWord: 'AAAA'; xAlpha: 'H'),
(xWord: 'AA' ; xAlpha: 'I'),
(xWord: 'ABBB'; xAlpha: 'J'),
(xWord: 'BAB' ; xAlpha: 'K'),
(xWord: 'ABAA'; xAlpha: 'L'),
(xWord: 'BB' ; xAlpha: 'M'),
(xWord: 'BA' ; xAlpha: 'N'),
(xWord: 'BBB' ; xAlpha: 'O'),
(xWord: 'ABBA'; xAlpha: 'P'),
(xWord: 'BBAB'; xAlpha: 'Q'),
(xWord: 'ABA' ; xAlpha: 'R'),
(xWord: 'AAA' ; xAlpha: 'S'),
(xWord: 'B' ; xAlpha: 'T'),
(xWord: 'AAB' ; xAlpha: 'U'),
(xWord: 'AAAB'; xAlpha: 'V'),
(xWord: 'ABB' ; xAlpha: 'W'),
(xWord: 'BAAB'; xAlpha: 'X'),
(xWord: 'BABB'; xAlpha: 'Y'),
(xWord: 'BBAA'; xAlpha: 'Z')
);
{ private 宣言 }
public
{ public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
begin
// タイマー停止
Timer1.Enabled := False;
Timer2.Enabled := False;
// トン = A を設定
mWord := mWord + 'A';
// タイマー始動
Timer1.Enabled := True;
Timer2.Enabled := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// タイマー停止
Timer1.Enabled := False;
Timer2.Enabled := False;
// ツー = B を設定
mWord := mWord + 'B';
// タイマー始動
Timer1.Enabled := True;
Timer2.Enabled := True;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
// タイマー停止
Timer1.Enabled := False;
Timer2.Enabled := False;
// トンツー文字クリア
mWord := '';
// タイマー始動
Timer1.Enabled := True;
Timer2.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i: integer;
begin
// 1 秒以上空いたら変換を行なう
// タイマー停止
Timer1.Enabled := False;
// 変換テーブルと付き合わせて変換
for i := 0 to 25 do begin
if mWord = mMorse[i].xWord then begin
mLine := mLine + mMorse[i].xAlpha;
mWord := '';
end;
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
// 3 秒以上空いたら単語終了
// タイマー停止
Timer1.Enabled := False;
Timer2.Enabled := False;
// 単語をメモに表示
Memo1.Lines.Add(mLine);
mLine := '';
end;
end.
mWord と mLine の最初の初期化をさらっと忘れていますw
動かしてみた
SOSを送信しています
さて、これを踏まえて micro:bit 側が作れるか?