見出し画像

DelphiでLCDに描画する

0.はじめに


現役時代、リアルタイムでIC内部の動作状況を見たい、という要望を持っていました。例えば、ラジオの電界強度を100msec間隔で読み込むなどですが、ICメーカーから供給される評価ソフトでは満足できず、かといってICを制御するマイコンのソフト屋さんに頼むと結構な費用がかかってしまうので、断念せざるえませんでした。
退職後、時間に余裕が出てきましたので、ボケ防止も含めて、ICの動作状況をリアルタイムで見るためにI2Cの制御に取り組むことにしました。
なお、I2C制御の例はネット上にたくさんありますが、PICやArduinoを使った例がほとんどで、PC上で結果を見たい私としては目的に合っていませんでしたので、昔から慣れ親しんでいるDelphiでやることにしました。

1.システム構成


将来的にはI2Cを介してターゲットとなるICを動作させて、リアルタイムで読み込むことが目的ですが、まずはPCからI2Cを動作させることを目的にネットで簡単に入手できるLCDモジュールに描画させることとします。

システム構成

*1 エレファイン様のUSB-I2C/SPI/UART/IOの変換モジュール
  (以下、エレファイン様の購入ページに記載のあるISSと呼びます)
*2 I2Cをパラレルに変換するPCF8574が搭載されたモジュール
*3 HD44720互換チップが搭載された2行16文字のLCDモジュール

USB-I2C変換には2種類あるようで、ドライバーが必要となるが特定のコマンドで動作する今回使用したタイプ(実際はWindowsが自動で認識してくれました)と、ドライバーは必要なくてHID(Human Interface Device)として動作させるタイプがあるようです。
プログラムは素人レベルですし、参考情報の少ないDelphiなので敷居の高いHIDタイプは避けて、特定のコマンドで動作させるタイプを選択しています。

USB-I2C変換モジュール(エレファイン様)

PCF8574モジュールはネット上で「どうしてこんな価格で販売できるのか」というような価格で販売されていますので入手も簡単です。

PCF8574モジュール

LCDとPCF8574が一体になったものも販売されていますので、一体になったものを購入した方がはんだ付けが不要になり便利かもしれません。
でも、GNDワイヤーを接続するためにはんだ付けは必要ですが。

LCDモジュール

これも信じられないような価格で販売されていますが、いくらアフターサポートが不要で、不良率が%台でOKだとしても、恐るべし中国価格と言ったところでしょうか。日系が価格で勝てないのもわかります。

2.USB-I2Cモジュール(ISS)の制御


PCとISSモジュールはUSBのフルスピード12Mで通信されますが、PCからは仮想COMポートとして通信することになります。ただし、bps設定などは無効で、不要となります。
エレファイン様の購入ページにTera Termを使っての通信確認方法の記載がありますので、マクロを記載してやってみました。例えば、

  send $5A$01

と送信すれば、ISSモジュールのVersionが返ってくることが確認できます。
実際のプログラムですが、DelphiにはデフォルトでUARTのコンポーネントはありませんので、追加のコンポーネントが必要となります。今回はGetItパッケージからAsyncPro for VCLをインストールしてプログラムしました。
(井澤計装様の「Delphi 10でApdComPortを使う」を参考にさせていただきました)

3.PCF8574の制御


I2C BUSのStart/Stopなどの細かい制御はISSモジュールに委ねることになりますが、まずはSlave Addressを決めなければなりません。モジュールの基板を見るとA1/A2/A3はオープンとなっているので、0x4Eになります。
参考としたネット上の記事では0x27などと1bitずらした表現となっていますが、現役時代は素直にAddress部分を読んでいましたので、少し戸惑ってしまいました。

アドレスマップ

ISSモジュールからI2Cデバイス存在確認を行うと、アドレス0x4Eで存在していることを示す0x01が返ってきましたので、PCF8574の制御も完了です。
蛇足ですが、ISSモジュールはI2C BUSのスピードを20k/50k/100k/400k/1000kHzと設定可能で、常温ですが400kHzのスピードでも通信可能でした。さすがに1000kHzはダメでしたけど。(PCF8574の仕様書上はMax.100kHzとなっています)

4.LCDモジュールの制御


ここまではスムーズに進んだのですが、実際にLCDに表示させるのに3つの問題がありました。

(1)BUS幅
LCDモジュール基板にはD0-D7のシルク印刷があるので、8bitで制御していると思い込んでいました。
でも、HD44720の仕様書に記載があるイニシャライズのコマンドを送信しても、初期化されたようには見えません。
ブリンキングさせるコマンドを送っても反応はありません。
何故だろう、と考えていく中で、「どのタイミングでデータを書き込んでいるんだ」と基本的なことを思い、HD44720の仕様書をちゃんと見るとHD44720の“E”がH->Lに切り替わるタイミングで読み込むと記載があるじゃないですか。
“E”を制御してあげる必要があることになりますが、PCF8574には8bitの出力しかないのでどうやって?、もう一個PCF8574が必要?とちょっと悩んでしまいました。
ネットを検索してみるとPCF8574モジュールの回路図が掲載してあり、それを見てビックリで、4bit制御となっているじゃないですか。

PCF8574モジュール回路図
ポート説明

こうなると1Byteの命令を送るのに、4Byteを送る必要があることになります。例えば、イニシャライズの最初に送るように書いてある0x38の場合、下表のデータを順に送ることになります。

送信例(0x38)

(2)送信データ
これで一件落着、コマンドを送ればイニシャライズされるはずなのですが、イニシャライズされません。当然キャラクターのコマンドを送っても表示してくれません。
テスター(オシロが欲しい!)を使ってPCF8574の各ポートを見てみると、期待値が出力されていません!
ノイズが原因か、と思い、I2Cのワイヤーを短くしたり、USBケーブルを2.0対応のケーブルに交換したりしましたが、解決しません。こうなるとISSモジュールからのI2C出力がおかしいのではないか、と疑い始めました。
ロジアナがあれば簡単にI2C BUSを見れるのですが、計測器と言えるものはテスターしかもっていないのでそれはかないません。

なのでTera Termを使って送っているコマンドを確認してみます。マクロを使って0xFFをWriteし、その後PCF8574からReadしてみるとおかしな値が返ってきます。

  マクロ:send $53$4E$FF
       $53=ISSモジュールのコマンド、$4E=PCF8574のアドレス     
  マクロ:send $53$4F
       $4F=PCF8574の読み込みアドレス
  画面:53 4E EF BF BD 53 4F E7
       結果は0xE7が返ってきているが、0xFFがEF BF BDとおかしい

結果としての0xE7も気になりますが、それ以上に0xFFを送っているのに“EF BF BD”となっていることが気になります。
まさかあのTera Termに問題があるなどとは考えず、ISSモジュールに問題があると考え、エレファイン様に問い合わせをさせていただきました。翌日サポート担当の方から返信があり、違うターミナルソフトで確認してくれ、という事でフリーソフトのRS232C.exeを紹介していただいて確認すると正しく0xFFが出力されていました。実際にはCOMポートの設定などでWindowsのデバイスマネージャーで強制的にCOMポートを設定したりなど、手間がかかっています。
あと、今思えばですが、Tera Termは表示はおかしいですが、0xFFを出力していました。

もうこれで大丈夫か、という事で自分のソフトでRS232C.exeに0x53 0x4E 0xFFを送ってみると、0xFFの部分が0x79と表示されます。いろいろと悩んだのですが、さすがDelphi、ちゃんと警告が出ていました。

Delphi メッセージ

正しく型宣言を行うように修正することで、RS232C.exeでも正しく0xFFが表示されるようになりました。    
  Char($FF) -> AnsiChar($FF)

(3)受信データ
しかし本来の問題である0xFFなのに0xE7になる、という問題は残ったままです。
P4とP3がおかしいことになりますが、埒が明かないのでエレファイン様の好意でロジアナを借用することにしました。ロジアナと言ってもPCで結果を見るタイプのもので、エレファイン様で販売されているものです。
これによりISSモジュールが正しいデータを出力していることがわかりました。(疑ってすいません)

I2Cで0x4E 0xFFを送信

じゃあなぜ期待値が返ってこないのか、0x11~0x77までは正しく返ってきますが、0xCCだと0xC4、0xFFだと0xE7となります。
これはハードが関係しているな、と思い、再度考え直しました。
P3はバックライトのON/OFFですが、0x00でOFF、0x08でONと、バックライトを制御できています。このことから、トランジスタのドライブ回路の影響を受けていると予想できます。テスターで見てみると、ONを出力してもP3はベース電圧と同じとなっており、ポートのHを判断できるレベルにはなっていませんでした。そのため、制御はできているが、読み込みは常に0となるようです。

P3想定回路

P4はD4の制御ですが、どうやらHD44720チップの影響があるようです。回路図がないのではっきりとしたことは言えませんが、PCF8574モジュール単品で使用すると、設定どおりに正しく0/1が読み込めます。

これで一件落着なのですが、結局、自分のBUS幅の勘違いと自作ソフトの問題でした。 

5.LCD表示の実行


改めてLCDのイニシャライズを行います。

理由は深く考えていませんが、データシートによると最初にFunction Setを何度も送るように記載されています。
(わかりやすい三共社様のアプリケーションノートから抜粋させていただいています)

送信フローチャート
送信ステップ

この後、表示オンのコマンドを送ります。わかりやすいようにカーソルを表示して、ブリンキングする設定の0x0Fを送るとイニシャライズされたことを目で認識できます。
実際に送信するデータは下記となります(インストラクション4)。

表示オン
イニシャライズ後のLCD

なお、PCの速度にもよるのかもしれませんが、何らかのウエイトが無いとエラーが出ます。
例えば、表示オンの0x0Fを送りたい場合、0x0C->0x08->0xFC->0xF8と送りますが、1Byteの送信後に送ったデータをTMemoに表示する処理だったり、TimeGetTimeを利用したWait処理が必要です。Wait時間はT=0でも大丈夫でした。 

procedure TForm1.WaitTimer(T: Cardinal);
var
  finish:Cardinal;
begin
  finish:=TimeGetTime + T;
  repeat
    Application.ProcessMessages
  until TimeGetTime > Finish;
end;

ここまでくると実際にキャラクターを表示させるのは簡単で、文字コードとP0(RS)を切り替えるコマンドを送るだけです。
例えば、“1”を表示させる場合の表示データは0x31なので、実際に送信するデータは下記となります(インストラクション10)。

0x31を表示

表示位置を変えたい場合は、最初にそのアドレスとD7(Set DDRAM address)を送ればOKです(インストラクション8)。

DDRAMアドレス

例えば、2行目の1文字目に表示させる場合は下記となります。

アドレス0x40に移動
インストラクション一覧

6.まとめ


今回使用したLCDは1602と呼ばれる2行16文字のタイプです。
I2C BUSを使用していますし、4bit制御なので4回のコマンドを送る必要があり、お世辞にも表示速度は速いとは言えません。TimeGetTime関数で測定したところ、32文字を描くのに420msecくらいでした。描いている、というのが目で見てわかりますので、商品とするには8bit制御とするか、あえて表示をスクロールで行うようにする必要がありそうです。

ここまで書いて、プログラムのことはほとんど書いていないことに気が付きました。プログラムが難しかった、というより、制御方法でつまづいたことが多かったので、この記事はこれで良いのかなと思います。
素人のスパゲッティソフトを見せても恥ずかしいだけですし。

作成したソフトの画面


この記事が気に入ったらサポートをしてみませんか?