Arduinoで半角カタカナのローマ字入力を行うプログラムを作成しました。
用途的にはArduino STM32用で稼働するTiny BASIC用ですが、Arduino UNOでも
利用出来ます。

パソコンの半角入力ではなく、Arduino側でローマ字を半角カタカナに変換して
出力した内容を表示しています。
半角カタカナを正しく表示するには、感じコードをSJIS設定する実用があります。
スケッチ
変換テーブルが大きです。
Arduino UNOではフラッシュメモリに配置等の工夫が必要ですね。
//
// ローマ字半角カタカナ入力
// 作成 2017/05/02 by たま吉さん
// 修正 2017/05/17,ltu(ッ)抜けの対応
//
#include <string.h>
#define RK_ENTRY_NUM (sizeof(RomaKama)/sizeof(RomaKama[0]))
//子音状態遷移コード
enum {
_romaji_top = 0,
_romaji_b, _romaji_c, _romaji_d, _romaji_f, _romaji_g, _romaji_h, _romaji_j, _romaji_k, _romaji_l, _romaji_m,
_romaji_n, _romaji_p, _romaji_q, _romaji_r, _romaji_s, _romaji_t, _romaji_v, _romaji_w, _romaji_x, _romaji_y,
_romaji_z, _romaji_by,_romaji_ch,_romaji_cy,_romaji_dh, _romaji_dw,_romaji_dy,_romaji_fw,_romaji_fy,_romaji_gw,
_romaji_gy,_romaji_hy,_romaji_jy,_romaji_kw,_romaji_ky, _romaji_lt,_romaji_ly,_romaji_my,_romaji_ny,_romaji_py,
_romaji_qw,_romaji_qy,_romaji_ry,_romaji_sh,_romaji_sw,_romaji_sy, _romaji_th,_romaji_ts,_romaji_tw,_romaji_ty,
_romaji_vy,_romaji_wh,_romaji_xt,_romaji_xy,_romaji_zy,
};
// カタカタ文字列変換テーブル
const char RomaKama[][5][4] = {
// a e i o u
{ "\xb1", "\xb4", "\xb2", "\xb5", "\xb3", }, //[] : ア エ イ オ ウ
{ "\xca\xde", "\xcd\xde", "\xcb\xde", "\xce\xde", "\xcc\xde", }, //[b] : バ ベ ビ ボ ブ
{ "\xb6", "\xbe", "\xbc", "\xba", "\xb8", }, //[c] : カ セ シ コ ク
{ "\xc0\xde", "\xc3\xde", "\xc1\xde", "\xc4\xde", "\xc2\xde", }, //[d] : ダ デ ヂ ド ヅ
{ "\xcc\xa7", "\xcc\xaa", "\xcc\xa8", "\xcc\xab", "\xcc", }, //[f] : ファ フェ フィ フォ フ
{ "\xb6\xde", "\xb9\xde", "\xb7\xde", "\xba\xde", "\xb8\xde", }, //[g] : ガ ゲ ギ ゴ グ
{ "\xca", "\xcd", "\xcb", "\xce", "\xcc", }, //[h] : ハ ヘ ヒ ホ フ
{ "\xbc\xde\xac", "\xbc\xde\xaa", "\xbc\xde", "\xbc\xde\xae", "\xbc\xde\xad", }, //[j] : ジャ ジェ ジ ジョ ジュ
{ "\xb6", "\xb9", "\xb7", "\xba", "\xb8", }, //[k] : カ ケ キ コ ク
{ "\xa7", "\xaa", "\xa8", "\xab", "\xa9", }, //[l] : ァ ェ ィ ォ ゥ
{ "\xcf", "\xd2", "\xd0", "\xd3", "\xd1", }, //[m] : マ メ ミ モ ム
{ "\xc5", "\xc8", "\xc6", "\xc9", "\xc7", }, //[n] : ナ ネ ニ ノ ヌ
{ "\xca\xdf", "\xcd\xdf", "\xcb\xdf", "\xce\xdf", "\xcc\xdf", }, //[p] : パ ペ ピ ポ プ
{ "\xb8\xa7", "\xb8\xaa", "\xb8\xa8", "\xb8\xab", "\xb8", }, //[q] : クァ クェ クィ クォ ク
{ "\xd7", "\xda", "\xd8", "\xdb", "\xd9", }, //[r] : ラ レ リ ロ ル
{ "\xbb", "\xbe", "\xbc", "\xbf", "\xbd", }, //[s] : サ セ シ ソ ス
{ "\xc0", "\xc3", "\xc1", "\xc4", "\xc2", }, //[t] : タ テ チ ト ツ
{ "\xb3\xde\xa7", "\xb3\xde\xaa", "\xb3\xde\xa8", "\xb3\xde\xab", "\xb3\xde", }, //[v] : ヴァ ヴェ ヴィ ヴォ ヴ
{ "\xdc", "\xb3\xaa", "\xb3\xa8", "\xa6", "\xb3", }, //[w] : ワ ウェ ウィ ヲ ウ
{ "\xa7", "\xaa", "\xa8", "\xab", "\xa9", }, //[x] : ァ ェ ィ ォ ゥ
{ "\xd4", "\xa8", "\xb2", "\xd6", "\xd5", }, //[y] : ヤ ィェ イ ヨ ユ
{ "\xbb\xde", "\xbe\xde", "\xbc\xde", "\xbf\xde", "\xbd\xde", }, //[z] : ザ ゼ ジ ゾ ズ
{ "\xcb\xde\xac", "\xcb\xde\xaa", "\xcb\xde\xa8", "\xcb\xde\xae", "\xcb\xde\xad",}, //[by] : ビャ ビェ ビィ ビョ ビュ
{ "\xc1\xac", "\xc1\xaa", "\xc1", "\xc1\xae", "\xc1\xad", }, //[ch] : チャ チェ チ チョ チュ
{ "\xc1\xac", "\xc1\xaa", "\xc1\xa8", "\xc1\xae", "\xc1\xad", }, //[cy] : チャ チェ チィ チョ チュ
{ "\xc3\xde\xac", "\xc3\xde\xaa", "\xc3\xde\xa8", "\xc3\xde\xae", "\xc3\xde\xad", }, //[dh] : デャ デェ ディ デョ デュ
{ "\xc4\xde\xa7", "\xc4\xde\xaa", "\xc4\xde\xa8", "\xc4\xde\xab", "\xc4\xde\xa9", }, //[dw] : ドァ ドェ ドィ ドォ ドゥ
{ "\xc1\xde\xac", "\xc1\xde\xaa", "\xc1\xde\xa8", "\xc1\xde\xae", "\xc1\xde\xad", }, //[dy] : ヂャ ヂェ ヂィ ヂョ ヂュ
{ "\xcc\xa7", "\xcc\xaa", "\xcc\xa8", "\xcc\xab", "\xcc\xa9", }, //[fw] : ファ フェ フィ フォ フゥ
{ "\xcc\xac", "\xcc\xaa", "\xcc\xa8", "\xcc\xae", "\xcc\xad", }, //[fy] : フャ フェ フィ フョ フュ
{ "\xb8\xde\xa7", "\xb8\xde\xaa", "\xb8\xde\xa8", "\xb8\xde\xab", "\xb8\xde\xa9", }, //[gw] : グァ グェ グィ グォ グゥ
{ "\xb7\xde\xac", "\xb7\xde\xaa", "\xb7\xde\xa8", "\xb7\xde\xae", "\xb7\xde\xad", }, //[gy] : ギャ ギェ ギィ ギョ ギュ
{ "\xcb\xac", "\xcb\xaa", "\xcb\xa8", "\xcb\xae", "\xcb\xad", }, //[hy] : ヒャ ヒェ ヒィ ヒョ ヒュ
{ "\xbc\xde\xac", "\xbc\xde\xaa", "\xbc\xde\xa8", "\xbc\xde\xae", "\xbc\xde\xad", }, //[jy] : ジャ ジェ ジィ ジョ ジュ
{ "\xb8\xa7", "\x00", "\x00", "\x00", "\x00", }, //[kw] : クァ NG NG NG NG
{ "\xb7\xac", "\xb7\xaa", "\xb7\xa8", "\xb7\xae", "\xb7\xad", }, //[ky] : キャ キェ キィ キョ キュ
{ "\x00", "\x00", "\x00", "\x00", "\xaf", }, //[lt] : NG NG NG NG ッ
{ "\xac", "\xaa", "\xa8", "\xae", "\xad", }, //[ly] : ャ ェ ィ ョ ュ
{ "\xd0\xac", "\xd0\xaa", "\xd0\xa8", "\xd0\xae", "\xd0\xad", }, //[my] : ミャ ミェ ミィ ミョ ミュ
{ "\xc6\xac", "\xc6\xaa", "\xc6\xa8", "\xc6\xae", "\xc6\xad", }, //[ny] : ニャ ニェ ニィ ニョ ニュ
{ "\xcb\xdf\xac", "\xcb\xdf\xaa", "\xcb\xdf\xa8", "\xcb\xdf\xae", "\xcb\xdf\xad", }, //[py] : ピャ ピェ ピィ ピョ ピュ
{ "\xb8\xa7", "\xb8\xaa", "\xb8\xa8", "\xb8\xab", "\xb8\xa9", }, //[qw] : クァ クェ クィ クォ クゥ
{ "\xb8\xac", "\xb8\xaa", "\xb8\xa8", "\xb8\xae", "\xb8\xad", }, //[qy] : クャ クェ クィ クョ クュ
{ "\xd8\xac", "\xd8\xaa", "\xd8\xa8", "\xd8\xae", "\xd8\xad", }, //[ry] : リャ リェ リィ リョ リュ
{ "\xbc\xac", "\xbc\xaa", "\xbc", "\xbc\xae", "\xbc\xad", }, //[sh] : シャ シェ シ ショ シュ
{ "\xbd\xa7", "\xbd\xaa", "\xbd\xa8", "\xbd\xab", "\xbd\xa9", }, //[sw] : スァ スェ スィ スォ スゥ
{ "\xbc\xac", "\xbc\xaa", "\xbc\xa8", "\xbc\xae", "\xbc\xad", }, //[sy] : シャ シェ シィ ショ シュ
{ "\xc3\xac", "\xc3\xaa", "\xc3\xa8", "\xc3\xae", "\xc3\xad", }, //[th] : テャ テェ ティ テョ テュ
{ "\xc2\xa7", "\xc2\xaa", "\xc2\xa8", "\xc2\xab", "\xc2", }, //[ts] : ツァ ツェ ツィ ツォ ツ
{ "\xc4\xa7", "\xc4\xaa", "\xc4\xa8", "\xc4\xab", "\xc4\xa9", }, //[tw] : トァ トェ トィ トォ トゥ
{ "\xc1\xac", "\xc1\xaa", "\xc1\xa8", "\xc1\xae", "\xc1\xad", }, //[ty] : チャ チェ チィ チョ チュ
{ "\xb3\xde\xac", "\xb3\xde\xaa", "\xb3\xde\xa8", "\xb3\xde\xae", "\xb3\xde\xad", }, //[vy] : ヴャ ヴェ ヴィ ヴョ ヴュ
{ "\xb3\xa7", "\xb3\xaa", "\xb3\xa8", "\xb3\xab", "\xb3", }, //[wh] : ウァ ウェ ウィ ウォ ウ
{ "\x00", "\x00", "\x00", "\x00", "\xaf", }, //[xt] : NG NG NG NG ッ
{ "\xac", "\xaa", "\xaa", "\xae", "\xad", }, //[xy] : ャ ェ ェ ョ ュ
{ "\xbc\xde\xac", "\xbc\xde\xaa", "\xbc\xde\xa8", "\xbc\xde\xae", "\xbc\xde\xad", }, //[zy] : ジャ ジェ ジィ ジョ ジュ
};
// 例外([nn])
const char RomaKama_nn[4] ="\xdd"; // 'ン'
// 母音テーブル
const char BoonTable[] = {
'a','e','i','o','u',
};
// 子音テーブル
const char ShionTable[] = {
'b' ,'c' ,'d' ,'f' ,'g' ,'h' ,'j' ,'k' ,'l' ,'m' ,'n' ,'p' ,'q' ,'r' ,'s' ,'t' ,'v' ,'w' ,'x' ,'y' ,'z',
};
// 2文字子音テーブル Xh系列
const char Shion_Xh_Table[][2] = {
{ _romaji_c, _romaji_ch },{ _romaji_d, _romaji_dh },{ _romaji_s, _romaji_sh }, { _romaji_t, _romaji_th },
{ _romaji_w, _romaji_wh },
};
// 2文字子音テーブル Xw系列
const char Shion_Xw_Table[][2] = {
{ _romaji_d, _romaji_dw },{ _romaji_f, _romaji_fw },{ _romaji_g, _romaji_gw },{ _romaji_k, _romaji_kw },
{ _romaji_q, _romaji_qw },{ _romaji_s, _romaji_sw },{ _romaji_t, _romaji_tw },
};
// 2文字子音テーブル Xt系列
const char Shion_Xt_Table[][2] = {
{ _romaji_x, _romaji_xt } , { _romaji_l, _romaji_lt } ,
};
// 2文字子音テーブル Xy系列
const char Shion_Xy_Table[][2] = {
{ _romaji_b, _romaji_by },{ _romaji_c, _romaji_xy },{ _romaji_d, _romaji_dy },{ _romaji_f, _romaji_fy },
{ _romaji_g, _romaji_gy },{ _romaji_h, _romaji_hy },{ _romaji_j, _romaji_jy },{ _romaji_k, _romaji_ky },
{ _romaji_l, _romaji_ly },{ _romaji_m, _romaji_my },{ _romaji_n, _romaji_ny },{ _romaji_p, _romaji_py },
{ _romaji_q, _romaji_qy },{ _romaji_r, _romaji_ry },{ _romaji_s, _romaji_sy },{ _romaji_t, _romaji_ty },
{ _romaji_v, _romaji_vy },{ _romaji_x, _romaji_xy },{ _romaji_z, _romaji_zy },
};
int16_t romaji_sts = _romaji_top; // 状態遷移コード
uint8_t flgTsu = false; // 小さいツ付加フラグ
char kataStr[6]; // 確定カタカナ文字列
// 文字コードから母音コード(0~4)に変換する
inline int16_t charToBoonCode(uint8_t c) {
for (uint8_t i=0; i < sizeof(BoonTable); i++)
if (c == BoonTable[i])
return i;
return -1;
}
// 文字コードから子音コードに変換する
inline int16_t charToShionCode(uint8_t c) {
for (uint8_t i=0; i < sizeof(ShionTable); i++)
if (c == ShionTable[i])
return i+1;
return -1;
}
// ローマ字カタカタ変換
// 直前の状態遷移から次の状態に遷移する
char* pRomaji2Kana(uint8_t c) {
int16_t code;
char* ptr;
// 小文字変換
if (c >= 'A' && c <= 'Z')
c = c - 'A' + 'a';
// 文字範囲チェック
// (後で長音・濁音・半濁音・句点・読点の許可する対応の追加)
if (c < 'a' || c > 'z')
goto STS_ERROR;
code = charToBoonCode(c); // 母音チェック
if (code >= 0) {
// 母音の場合,文字列を確定する
if (romaji_sts >= _romaji_top && romaji_sts <= _romaji_zy) {
ptr = (char*)RomaKama[romaji_sts][code];
goto STS_DONE; // 変換完了
} else
goto STS_ERROR; // 変換エラー
} else {
// 母音でない場合、子音コードを取得
code = charToShionCode(c);
if (code < 0)
goto STS_ERROR; // 子音でない(エラー)
if (romaji_sts == _romaji_top) {
// 初期状態で子音コードなら次の状態に遷移
romaji_sts = code;
goto STS_NEXT;
} else if (romaji_sts >= _romaji_b && romaji_sts <= _romaji_z) {
// 1文字子音受理済みからの子音入力の対応
if ( romaji_sts == code) {
// 同じ子音が連続
if (!flgTsu) {
if (code == _romaji_n) {
// nn('ン')の場合
ptr = (char*)RomaKama_nn;
goto STS_DONE; // 変換完了
} else {
flgTsu = true; // 小さい'ツ'の先頭付加フラグの設定
goto STS_NEXT;
}
} else
// 既に小さい'ツ'の先頭付加フラグがセットされている場合はエラー
goto STS_ERROR;
} else {
// 2文字子音への遷移チェック
switch(code) {
case _romaji_h:
for (uint16_t i=0; i < (sizeof(Shion_Xh_Table)/sizeof(Shion_Xh_Table[0])); i++)
if ( Shion_Xh_Table[i][0] == romaji_sts) {
romaji_sts = Shion_Xh_Table[i][1];
goto STS_NEXT;
}
goto STS_ERROR;
case _romaji_w:
for (uint16_t i=0; i < (sizeof(Shion_Xw_Table)/sizeof(Shion_Xw_Table[0])); i++)
if ( Shion_Xw_Table[i][0] == romaji_sts) {
romaji_sts = Shion_Xw_Table[i][1];
goto STS_NEXT;
}
goto STS_ERROR;
case _romaji_t:
for (uint16_t i=0; i < (sizeof(Shion_Xt_Table)/sizeof(Shion_Xt_Table[0])); i++)
if ( Shion_Xt_Table[i][0] == romaji_sts) {
romaji_sts = Shion_Xt_Table[i][1];
goto STS_NEXT;
}
goto STS_ERROR;
case _romaji_y:
for (uint16_t i=0; i < (sizeof(Shion_Xy_Table)/sizeof(Shion_Xy_Table[0])); i++)
if ( Shion_Xy_Table[i][0] == romaji_sts) {
romaji_sts = Shion_Xy_Table[i][1];
goto STS_NEXT;
}
goto STS_ERROR;
default:
goto STS_ERROR;
}
}
}
}
STS_NEXT: // 次の状態へ
return NULL;
STS_ERROR: // [状態遷移エラー]
romaji_sts = _romaji_top; // 状態の初期化
flgTsu = false; // 小さい'ツ'の先頭付加フラグクリア
return NULL;
STS_DONE: // [ローマ字カタカナ変換 遷移完了]
if (flgTsu) {
kataStr[0] = 0xaf; // 'ッ' の設定
strcpy(kataStr+1, ptr);
ptr = kataStr;
}
romaji_sts = _romaji_top; // 状態の初期化
flgTsu = false; // 小さい'ツ'の先頭付加フラグクリア
return ptr;
}
void setup() {
Serial.begin(115200);
}
void loop() {
char c;
char* ptr;
if (Serial.available()) {
c = Serial.read();
if (c == '\n') {
Serial.println();
} else {
ptr = pRomaji2Kana(c);
if (ptr) {
Serial.print(ptr);
}
}
}
}
スケッチの作成は次のような状態遷移表(クリックで拡大表示)をEXCELで作成し、
EXCELの関数やらを駆使してC言語用のテーブルを自動生成してます。
EXCELはプログラムを作成のツールとして重宝します。

一見、単純なローマ字 => 半角カタカナ 対応のテーブルを使った方が簡単と思ったのですが
意外と難しいく、1文字入力する都度、状況(状態)に応じて変換した方が楽でした。
例えば、"ガッチャマン"と入力する場合、
ローマ字入力では、gattyamann を入力しますが、
単純なローマ字、カタカナテーブルを使って行おうとすると
ga => ガ
ttya => ッチャ
ma => マ
nn => ン
のように、可変長文字列を切り出しにて検索する等、ちょと面倒になってきます。
その切り出し処理に、結局は状態の管理が必要になります。
入力された1文字づつ処理した方が単純になります。
最近のコメント