フォト
2017年7月
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
無料ブログはココログ

arduino

2017年7月19日 (水)

次はSTM32ボードを積極的に使ていきたい(19) - シリアルポートの調査(2)

STM32F103C8T6搭載ボードをArduino STM32環境下にて利用する場合の
シリアルポートの利用について以前調査し、下記にまとめたのですが、

 関連記事 : 「次はSTM32ボードを積極的に使ていきたい(2) - シリアルポートの調査」


起動直後のUSB-シリアル接続待ち処理において若干、推奨する作法が変わったようです。

従来
Serial.isConnected() で接続確認
void setup(void){
  Serial.begin(115200);
  while (!Serial.isConnected()) delay(100);
}

現時点
Serial で 接続確認

#define timeoutPeriod 2147483647    // Long time... about 25 days
void setup(void){
  Serial.begin(115200);
  Serial.setTimeout(timeoutPeriod);
  while (!Serial) delay(100);     
}

この変更はUSBをサポートしている Arduino Leonardo、Micro、DueとAPIを
同じにするためのようです。

関連情報: https://github.com/rogerclarkmelbourne/Arduino_STM32/pull/270

Serial.isConnected()も現時点でも利用出来ますが、
Arduino STM32(ベースのmapleを含む)固有ですので今後は使わない方がようでしょう。
Arduino STM32のサンプルスケッチも全てSerial.isConnected()を廃止して
Serialの値で判定するように修正されています。

ただし、シリアルをログ・デバッグ用に利用しているのであれば、
Serial.setTimeout()で設定する値は短くして良いでしょう。

Serial.setTimeout()で設定しない場合、デフォルトは1秒のようなのですが、
接続済みの状態でリセットすると再接続に失敗しました。
どうも、デフォルトは1秒でないようです。
明示的にSerial.setTimeout(1000)とすると接続出来ました。

なので、現在手掛けている、豊四季Tiny BASICでは次おようにしました。

void setup(void){
  Serial.begin(115200);
  Serial.setTimeout(1000);
  while (!Serial) delay(100);     
  ...

2017年7月15日 (土)

Windows 10でCH340を標準サポートになったっぽい?

先日購入した中古のWindows 10ノートパソコンにてArduino IDE 1.8.3インストールしました。

激安Arduino Uno互換機を接続するとUSB-シリアルCH340用のドライバーを
インストールすることなく、スケッチの書き込みができました。

以前は、ドライバーを入手して別途インストールが必要でした。

02

デバイスのプロパティを見ると、接続したタイミングでインストールされたようです。

01


それならばと思い、Silicon LabsのCP2102搭載のUSB-シリアルモジュールを繋げてみると、
やはりドライバーのインストール不要で利用出来ました。

02_2

デバイス マネージャーでの確認

03

いつから、標準対応になったのだろう..
それとも、夜中に小人さんさんがドライバーインストールしてくれたん?

2017/07/18 追記
念のため、他のWindows 10機で試してみました。
Arduino IDE等の開発環境をインストールしたことのないタブレットです。
Windows 10は最新版にアップデートしています。

04

CH340、CP2102搭載の搭載のUSBシリアル変換モジュールをUSBハブ経由で接続。
タブレットでもUSBに刺しただけで、ドライバーがインストールされました。
デバイスマネージャーで見てもちゃんとCOMポートとして認識しています。

05

やはり、わざわざドライバーを入手する必要はないみたいです。

 

2017年7月14日 (金)

SDライブラリのマルチメディアカード(MMC)対応

Arduino IDEのSDライブラリを修正してマルチメディアカード(MMC)が利用可能にしました。
ライブラリを下記のサイトにて公開します。
https://github.com/Tamakichi/SD

オリジナル版と名前がかぶりますが、libralbyの下に配置するとこちらを優先して
スケッチで利用されます。

修正については、Elias Zacariasさん、ChaNさんの記事を参考にしました。
ソースはほぼElias Zacariasさんの差分を利用しています。感謝!
・A BIT of Mystery - ARDUINO SD LIBRARY SUPPORT FOR MMC CARDS
   http://blog.damnsoft.org/arduino-sd-library-support-for-mmc-cards/
・MMC/SDCの使いかた
   http://elm-chan.org/docs/mmc/mmc.html

マルチメディアカード(MMC)にはいくつかのタイプがありますが、
とりあえず、下記の端子が7つあるタイプでの動作を確認しました。

06

SDカードと形状は同じですが、端子が2つ少ないです。

07

SDライブラリのサンプルスケッチで読み書き出来ました。

03

01

02


ところで、

なぜ、マルチメディアカード(MMC) 対応?

と思われますが、大人の事情です。

ArduinoでSDカードを利用する場合、
お手軽な方法としてはArduino IDEのSDライブラリ利用します。
ところがこのSDカードの利用、個人利用でも厳密にはライセンス(有料)が必要なようです。

参考情報

     ・ねむいさんのぶろぐ - いろいろ試す25(今回はSDカード関連中心です)

これを回避する手段としては、SDカードの下位互換でかつライセンス不要の
マルチメディアカード(MMC)に対応することで、
  「MMCまたは互換カード対応」
と主張するしかないようです。

悲しいことに、Arduino IDEのSDライブラリはMMC対応されていません。
そこでこの修正版を作成しました。
現在手掛けている豊四季Tiny BASIC for STM32のSDカード利用で問題となります。
ほかに過去に色々とSDカードを利用したスケッチ等を公開しています。

といあえず、これで
  「MMCまたは互換カード対応」
と主張出来ます。

2017年6月27日 (火)

豊四季タイニーBASIC for Arduino STM32、ボード実装

「豊四季タイニーBASIC for Arduino STM32」
開発環境をブレッドボードからユニバーサル基板に移行しました。

Dscn6689

ジャンパーワイヤーから解放されてすっきりしました。

Dscn6693

現在、スクリーンエディタ部のクラスを再設計して汎用化し、差分実装にて
色々なデバイス(シリアルコンソール、液晶モジュール等)への対応を行っています。

スクリーンエディタ部分はライブラリ化して、Tiny BASIC以外のユーザーインタフェース
に利用出来るよう、思案中です^^

2017年6月15日 (木)

「豊四季 Tiny BASIC for Arduino STM32」 、v0.83に更新

現在手掛けている、Blue Pillを使った「豊四季 Tiny BASIC for Arduino STM32」、
SDカード対応してv0.83としました。

SDカードにプログラムのセーブ、ロード出来るようになりました。
やはり、名前を付けてファイルとして保存出来るのはいいですね。

03

動いている様子
FILESコマンドで、ワイルドカードが使えます。

amazonで入手出来る安価なSDカードモジュール3点は問題なく利用出来ました。

Dscn6664

06


トップの写真の画面表示は次のプログラムで行っています。

10 CLS
20 LDBMP "TT.BMP",MEM,0,0,32,32,1
30 LDBMP "TT.BMP",MEM+128,32,0,32,32
40 LDBMP "TT.BMP",MEM+256,64,0,32,32
50 LDBMP "TT.BMP",MEM+384,0,32,96,32
60 BITMAP 10,30,MEM,0,32,32,2
70 BITMAP 74,40,MEM,1,32,32,2
80 BITMAP 138,50,MEM,2,32,32,2
90 BITMAP 10,120,MEM+384,0,96,32,2

動作検証用なので、ちょっと面倒なことをやっています。
(最初から1つの画像にしておけば1行で表示できるのですが..)

次の画像ファイル"TT.BMP"から任意の部分を切り出してロードし、
2倍にして表示しています。

Tt

面白そうな機能、と思い実装してみたのですが
あまり使い道がなさそう...




2017年6月 4日 (日)

豊四季Tiny BASIC、ビットマップファイルの利用を可能に..

安価なBlue Pillボードを使った豊四季Tiny BASIC、SDカードからビットマップファイルを
ロード出来るようになりました。



224x312のビットマップファイルから224x216サイズを
部分ロードして表示している様子です。
縦の切り出し位置を逐次変更することでスクロールしているように見えます。

ここで言っているビットマップファイルは
Windowsのモノクロビットマップ形式の画像ファイルです。

動画のプログラムソース

10 CLS
20 FOR Y=0 TO 312-216
30 LDBMP "CAT.BMP",GRAM,0,Y,GW,GH
40 NEXT Y
50 GOTO 20
画像はHelm42さんの猫絵を利用させて頂いています。
エラー処理等をもうちょっと、強化してからGitHubにて更新版を公開します。

2017年6月 3日 (土)

Arduino IDE添付のSDライブラリの修正

Arduio IDE 1.8.2に含まれているSDライブラリ、リソースの開放と再獲得が出来ない。
これでは、利用しているSDカードの抜き差しが自由に行えません。

そこでオリジナルのSDライブラリ
https://github.com/arduino-libraries/SD

をフォークして、自分で修正を施しました。
SD Library for Arduino
https://github.com/Tamakichi/SD

修正内容
1)SD.end()の追加
2)SD.begin()で直前に利用していたリソース開放を行うように修正
3)ファイル名に半角カタカタの利用が可能

大した修正ではないのですが、効果絶大SDカード使い勝手が良くなります。
これで抜き差ししても、SD.begin()を実行すればSDカードを再認識してくれます。

SDライブラリは豊四季Tiny BASICでも利用しています。
この修正で、ファイル名に半角カタカナが使えるようになりました。
抜き差ししても、SDカードを再認識出来ました。

01

2017年6月 1日 (木)

豊四季 Tiny BASIC for Arduino STM32の動作テスト(4) - 文字の拡大表示

現在取り組んでいる「豊四季 Tiny BASIC for Arduino STM32」の動作確認の続きです。

内蔵しているRTCから時刻を取得して、拡大文字で時間を表示するデモです。


プログラムソース

10 CLS
20 GETTIME H,M,S
30 @(0)=H/10:@(1)=H%10
40 @(2)=10
50 @(3)=M/10:@(4)=M%10
60 @(5)=10
70 @(6)=S/10:@(7)=S%10
80 FOR I=0 TO 7
90 BITMAP I*24+10,20,FNT,@(I)+ASC("0"),6,8,4
100 NEXT I
110 GOTO 20

GETTIMEコマンドで時刻を取得して、
BITMAPコマンドを使って、6x8ドットの文字を4倍に拡大して表示しています。
処理的には単純です。

内蔵しているRTCは外付けのボタン電池でバックアップをしており、
電源を切っても時刻を刻んでくれます。

Dscn6653

一ヶ月か1っヶ月半前に時刻をセットしたのですが、7分もずれています。
あまり精度は良く無いです。

ここで、1回ループ当たりの処理にかかる時間をTICK()関数で測定したのですが、
値は0でした。
TICK()関数、現時点の仕様は0.1秒刻みなのですが、これだと役に立たないっぽい。
長期の時間測定はRTCを使えば良いので、TICK()は1ミリ秒刻みにして
処理時間計測に利用出来るように修正します。

2017年5月28日 (日)

豊四季 Tiny BASIC for Arduino STM32の動作テスト(3) - LEDドットマトリックス

現在取り組んでいる「豊四季 Tiny BASIC for Arduino STM32」の動作確認の続きです。

LEDドライバ、MAX7219を使った8x8LEDドットマトリックスの制御をやってみました。

02

利用したモジュールはAliexpressで以前入手したものです。
1個150円程度で購入できます。amazonでも1個200円くらい入手出来るようです。

Free shipping! 1PCS MAX7219 dot matrix module

01

実際の動作


思っていたより、スムーズに表示出来ました。
以前IchigoJamでやった時は、1文字1秒かかりスクロール表示なんて無理な状況でした。
さすが、IchigoJamの100倍近い性能、難なく動かせました。

プログラムソース

1 'MAX7219(PB13: CLOCK, PB12: CS, PB14: DAT)
100 GOSUB "INIT"
110 M="ネコニコンバンワ!"
115 T=100
120 L=LEN(M)
130 FOR S=1 TO L
140 C=ASC(M,S)
150 GOSUB "SCROLLIN(C,T)"
160 NEXT S
170 END
200 "SCROLLIN(C,T)"
210 FOR J=0 TO 5
220 FOR K=0 TO 7
230 @(K)=(@(K)<<1)|(PEEK(C*8+FNT+K)>>(7-J))
250 NEXT K
255 GOSUB "DISP(@)"
260 WAIT T
270 NEXT J
280 RETURN
300 "DISP(@)"
310 FOR I=0 TO 7
320 R=I+1
330 V=@(I)&$FF
340 GOSUB "WRITE(R,V)"
350 NEXT I
360 RETURN
400 "INIT"
410 GPIO PB12,OUTPUT
420 GPIO PB13,OUTPUT
430 GPIO PB14,OUTPUT
440 @(0)=$0B,7,$0A,0,$0C,1,9,0,$0F,0
450 FOR I=0 TO 8 STEP 2
460 R=@(I):V=@(I+1)
470 GOSUB "WRITE(R,V)"
480 NEXT I
485 FOR I=0 TO 7:@(I)=0:NEXT I
490 RETURN
500 "WRITE(R,V)"
510 OUT PB12,LOW
520 SHIFTOUT PB14,PB13,MSB,R
530 SHIFTOUT PB14,PB13,MSB,V
540 OUT PB12,HIGH:OUT PB12,LOW
550 RETURN

プログラムの構造的には次のような感じになっています。
ボトムアップ的(下位から上位)に解説します。

・510~550行:ラベル "WRITE(R,V)"
MAX7219へのコマンド送信を行うサブルーチン
変数Rがレジスタ、変数Vがレジスタに設定する値です。
ボード上の端子PB12がCS、PB14がデータ、PB13がCLKへの出力です。
シフト操作によってR、Vの16ビットを送信しています。

ちなみに、ラベル名の"WRITE(R,V)"は単なるラベル名で、(R,V)は引数として
渡していることを分かり易くするためラベルに付けているだけです。

・400~490行:ラベル "INIT"
MAX7219の初期化処理
PB12,PB13,PB14を出力設定にしたのち、
"WRITE(R,V)"を呼び出して、440行のレジスタその設定値の内容を送信しています。
また、485行で8x8ドットの表示用バッファ(配列@(0)~@(7)を初期化しています。
レジスタ設定では輝度等の設定を行っています。

・300~360行:ラベル "DISP(@)"
8x8ドットパターンの表示処理
8x8ドットの表示用バッファ(配列@(0)~@(7))の内容をMAX7219に送信しています。
送信には"WRITE(R,V)"を呼び出しています。

・200~280行:ラベル "SCROLLIN(C,T)"
1文字単位のスクロール挿入処理
変数Cで指定した文字をスルロールしながら挿入します。
スクロールする際の1ドット毎のウェイトを変数Tで指定します。
8x8ドットの表示用バッファ(配列@(0)~@(7))に1ドットスクロールしたデータを書き込み
"DISP(@)"を呼び出して実際の表示を行っています。

文字のドットデータは、フォントデータを利用しています。
フォントデータの格納アドレスは定数FNTにて参照できます。

・100~170行:メイン処理
  下位のモジュールを使って文字列表示を行っています。
   変数Mに文字列、変数Tにスクロール速度を指定します。
   このレイアでは、MAX7219の使い方は意識しないで表示したい文字を指定して
   表示するだけです。
   
処理的に余裕がありそうなので、手持ちの四連結もMAX7219も制御出来そうです。
そのうちチャレンジ試してみよう..

2017年5月18日 (木)

Arduinoで半角カタカナのローマ字入力

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

01

パソコンの半角入力ではなく、Arduino側でローマ字を半角カタカナに変換して
出力した内容を表示しています。

半角カタカナを正しく表示するには、感じコードをSJIS設定する実用があります。

02

スケッチ
変換テーブルが大きです。
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はプログラムを作成のツールとして重宝します。

03

一見、単純なローマ字 => 半角カタカナ 対応のテーブルを使った方が簡単と思ったのですが
意外と難しいく、1文字入力する都度、状況(状態)に応じて変換した方が楽でした。

例えば、"ガッチャマン"と入力する場合、
ローマ字入力では、gattyamann を入力しますが、
単純なローマ字、カタカナテーブルを使って行おうとすると
  ga    => ガ
 ttya  => ッチャ
 ma   => マ
  nn    => ン

のように、可変長文字列を切り出しにて検索する等、ちょと面倒になってきます。
その切り出し処理に、結局は状態の管理が必要になります。
入力された1文字づつ処理した方が単純になります。

より以前の記事一覧