無断転載および再配布を禁じる。
Copyright (c) 2020 All rights reserved.
注意1: | この文書の記載内容については、いっさいの責任を負いません。 各製品添付の資料で確認のうえ、自己責任でご利用ください。 |
注意2: | この文書の内容に関して、各製品の販売元およびメーカーはまったく無関係であり、いっさいの責任がありません。 この文書に関して、販売元やメーカーへの問い合わせなどは固く禁じます。 |
これは、PicBasic Pro(PBP)で作ったプログラムでPICを動作させ、I2C入力アダプター「PCF8574」を使ってLCD(液晶)「CFAH1602X」を表示させます。
「CFAH1602X」は、SUNPLUS社製のLCDドライバー「SPLC780D」を使っていますが、これは日立製「HD44780」とソフトウェア互換です。
(参照:「SPLC780D or S6A0069 LCD'S compatible with HD44780?」の記事)
「HD44780」系のLCDドライバーは4bitパラレルまたは8bitパラレル入力なので、マイコンの端子を少なくとも4本+アルファ、つまり5本以上占有します。
これに対して、I2C接続が占有するマイコンの端子はたった2本です。
このため、I2C入力のLCDアダプター「PCF8574」を採用することによって、より小型のマイコンで液晶表示させることができます。
今回、使用するマイコンのダウンサイジングを目的として、I2C入力のアダプター「PCF8574」を使った液晶表示プログラムをPBP(Picbasic Pro)で作りました。
5-1.I2C書き込みコード
5-2.「PCF8574」と「SPLC780D」の書き込みタイミング
7-1.動作の準備
7-2.LCD表示の設定
7-3.文字の表示
7-4.数値の表示
7-5.I2C書き込みコード成型サブルーチン
7-6.数値>ASCIIキャラクタコード変換サブルーチン
おもな開発環境は次のとおりです。
PIC | 16F1823(14pin) |
コンパイラ | PBP2(PicBasic Pro 2) |
プログラミング | Pickit2 |
電源 | 単3x3本 |
これはパラレル入力タイプのLCD「CFAH1602X」をアダプター「PCF8574」を使ってI2C駆動するのですが、「PCF8574」基板の回路図を最初に見たときに抱いた「これはI2Cを使ってPBP(PICBasic Pro)の"LCDOUT"と同じ動作をPCF8574のポートにさせるのではないか?」という思いは当たりでした。
(参照:「ちょっとTea Time!? キャラクターLCDをI2Cで動かしてみる。」内の基板回路図)
実際に動かしてみたところ、もともとI2C入力タイプに作られたLCD「AQM1602」と比べ、次表のように特に優位な点は見当たりません。
しかし、「AQM1602」にはバックライトがないので、暗い場所の用途があれば、この「PCF8574+CFAH1602X」も良いかもしれません。
比較項目 | PCF8574+CFAH1602X | AQM1602 |
---|---|---|
重量 | 35.5g | 8.0g |
実装 | 基板の四隅に取り付け用ネジ穴 | 取り付けに使える部分は特に無い |
バックライト | あり | なし |
コントラスト | バックライトが不可欠だが、黒浮きが激しい | バックライト不要。 エッジからの光浸入があるが、これを塞げば良好。 |
コントラスト調整 | 可変抵抗 | 操作コードの書き込み |
I2C初期化 | 自動実行 | プログラムで遂行 |
PBPプログラム | ASIIコードを2分割してI2Cコードに成型しなければ文字を表示できない | 「” ”」で囲んだ文字列はそのまま表示できる |
ただし、特筆すべきは「I2C初期化」が自動化されていることです。
I2C通信の周辺機能デバイスは必ずしもROM搭載ではないので、一般的にはコントローラがプログラムによって「初期化」を書き込みます。
しかし、「PCF8574」は「I2C communication with this device is initiated by a master sending a start condition(データシートより)」なので、ほとんど手間要らずです。
「Block Diagram」には明記されていないので推測になりますが、ROM搭載なのかもしれません。
そのため、ユーザープログラムはいきなり「CFAH1602X」に対して「4ビットバスで行きます」と伝えるところから始めることができます。
普通、この「初期化」手順は少々くどいだけでなく、デバイスごとに微妙に違って、さらにユーザーが望んでするものでもないので、しないで済むのはけっこうありがたいです。
これは、データシートの「Features」に明記しても良いくらいなのですが、「PCF8574」はもともと汎用ポートエクスパンダーなので「お手軽」が当然なのかもしれません。
ややこしいポートエクスパンダーを使うなら、最初からポートの多いコントローラを使えばよいのですから・・・
次の写真がLCD(液晶)表示器基板、その次の図が配線図です。
I2C通信は配線長が長いと通信不良が起き易いので、極力短距離に配線しました。
基板の組み立てで特に注意すべきはLCD表示の上下です。
下の基板写真のように、「PCF8574」基板の接続端子が向かって左側に来るように配置すると表示が正立します。
ちなみに、PICにはI2Cモジュールが内蔵されているのですが、PBP2のマニュアルには、「I2C命令はソフトウェア的に遂行している」と書いてあったので、「それならば端子はどこでも良いのだろうか?」と考えました。
そこで、実験してみたところ、I2Cデバイスの接続は概ねポートのどの端子でも構わないようです。
今回、動作クロックの発振はC:PBPフォルダのINCファイルに「_FOSC_INTOSCIO」と記入し、内蔵発振回路を使っているため、基板回路には発振に関する部品は一切ありません。
そのため、通常のポートとして使える端子が2本多く確保できます。
「PCF8574」基板には、個人的に気になる点がふたつほどありました。
そこで、次のように対処しました。
これらの実施後、PIC16F1823を含めた全体の消費電流は3.6mAでした。
ここで使っているI2C入力アダプター「PCF8574」は18ピンのパッケージで、8端子の入出力ポートをひとつだけ持っています。
この8端子で、LCD(液晶)「CFAH1602X」つまりLCDドライバー「SPLC780D」と接続しています。
その接続にはパラレルバスのほかに数本の制御端子も必要なので、パラレルバスは4ビットです。
(参照:「ちょっとTea Time!?・・・」内の基板回路図)
このため、I2C通信プログラムでは1byte中の上位4ビットをデータ(キャラクタコードまたは操作コード)に用います。
PBP(PicBasic Pro)書式:I2CWRITE SDA,SCL,ADDRESS,[DATA BYTE]
ヘッダー | ジャンパー | WRITE | 16進コード | |||||
---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1(A2) | 1(A1) | 1(A0) | 0 | $4E |
注:上表の「WRITE」ビットは「PCF8574に対する書き込み」であって、「SPLC780Dに対する書き込み」は、「DATA BYTE」に記述されます。
DATA BYTE | 遂行順序 | データコード | EN | E | WR | RS | 16進コード | |||
---|---|---|---|---|---|---|---|---|---|---|
操作コード | OP1 | D7 | D6 | D5 | D4 | 1 | 1 | 0 | 0 | $?C |
OP2 | D7 | D6 | D5 | D4 | 1 | 0 | 0 | 0 | $?8 | |
OP3 | D3 | D2 | D1 | D0 | 1 | 1 | 0 | 0 | $?C | |
OP4 | D3 | D2 | D1 | D0 | 1 | 0 | 0 | 0 | $?8 | |
キャラクタコード | CH1 | D7 | D6 | D5 | D4 | 1 | 1 | 0 | 1 | $?D |
CH2 | D7 | D6 | D5 | D4 | 1 | 0 | 0 | 1 | $?9 | |
CH3 | D3 | D2 | D1 | D0 | 1 | 1 | 0 | 1 | $?D | |
CH4 | D3 | D2 | D1 | D0 | 1 | 0 | 0 | 1 | $?9 | |
V | V | V | L> | 0:操作コード、1:キャラクタコード | ||||||
V | V | L>>> | 0:書き込み、1:読み出し | |||||||
V | L>>>> | 立ち下り(1>0)で「SPLC780Dに書き込み」 | ||||||||
L>>>>> | !!!超重要!!! 参考にした「ちょっとTea Time!?・・・」内の基板回路図上は無結線ですが、実際はバックライトのアノードでした。 0:バックライトOFF、1:ON 「Display OFF」や「Clear Display」の際に、この「EN」を「0」にして書き込むと、バックライトを消灯して節電できます。 |
注:上表の操作コードには4bitのものがあり、その場合は操作コードは4つでなくOP1とOP2のふたつだけです。
PICから「PCF8574」へのI2C書き込みは下図のようにSCLの立ち上がりタイミングで行われます。
これにより、一回8ビットの書き込みが終わった後「PCF8574」のポートに並列出力されます。
「PCF8574」のポート出力のうち、ビット2(E)出力だけを最初「1」、次に「0」にし、その間 他の出力は同一にしておくと、下図のようにビット2(E)出力の「1→0」の立下りで「DATA BYTE」の上位4ビットが「SPLC780D」に書き込まれます。
Picbasic Pro(PBP)の「LCDOUT」命令は「文字列」とか「数値」とかを自由に扱えますが、このタイミング発生が最後の一押しかもしれません。
ここで紹介するプログラムは、I2C入力アダプター「PCF8574」によって、LCD(液晶)「CFAH1602X」に次のような表示をします。
上の写真のLCDで、右下の「K=1」の「1」は、変数であり、0から99までカウントアップする「数値」を表示します。
ソースプログラムは、添付のPDFのとおりです。
以下、順に説明をします。
5-6行目:コンフィグレーションのコピー
「C:PBP」フォルダ内の「16f1823.INC」ファイル上の「コンフィグレーション」設定です。
8-9行目:不使用
8行目がシリアル通信で使うモジュール、9行目がプログラムをシリアル通信で書き込むときに使うモジュールです。
どちらもここでは使わないので、削除可です。
11-16行目:ポート、クロックの設定
ここでは、すべてのポートをデジタル出力としてしか使わないので、そのように設定しています。
13-15行目は、I2Cを使う場合には不可欠です。これが無いとI2Cがうまく動かない場合があります。
16行目は、内蔵のクロック発振器を使って4MHzで動作することを設定します。
この設定はconfigの「FOSC」の設定に優先します。
18-30行目:使用する変数の宣言
ここでは、プログラム内で使う変数名を宣言します。
19-21行目の4行は上から順に、表示する文字キャラクターのASCIIコード(8ビット)/その上半分4ビット/その下半分4ビットです。
22-25行目の4行は上から順に、I2C通信コード上の上半分4ビットデータの「PCF8574」出力/同「CFAH1602X」への書き込み/下半分4ビットデータの「PCF8574」出力/同「CFAH1602X」への書き込みです。
26-30行目の5行は上から順に、ループを回すためのカウント数N、LCD表示するための「数値K」、桁毎の10進数値DGTS、桁毎のキャラクタコードCODE、1桁づつ表示するときのキャラクタコードCODSです。
32-36行目:I2Cの端子とアドレス
33,34行目の2行は、PICのI2C端子を指定しています。
35-36行目は「PCF8574」のI2C「書き込み」アドレスで、I2Cのこれに続くデータが「PCF8574」へ「書き込み」されます。
36行目のアドレスは基板のジャンパーによって変えることができます。
この値はジャンパー(3個)がすべてオープンでハイレベルになっているときのものです。
ヘッダー | ジャンパー | WRITE | 16進コード | |||||
---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1(A2) | 1(A1) | 1(A0) | 0 | $4E |
LCDの動作設定を行うSPLC780Dの「操作コード」の説明は、フロリダ大学のサイトが詳しいです。
39-46行目:「CFAH1602X」に動作条件を書き込み
ここでは、「CFAH1602X」の基本動作を「SPLC780D」に書き込んでいます。
39行目は、「PCF8574」の出力バス幅を「CFAH1602X」に設定します。
「PCF8574」の出力ポートはひとつ(8ビット)なので、制御用の端子を割り付けるとバス幅は4ビットしか取れません。
この行で、それを「CFAH1602X」に書き込むことにより、正しいデータの授受が行われます。
RS | WR | 操作コード | DATA BYTE:$2C,$28 | |||
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 0 | 設定内容:4ビットバス |
L> | 0:4ビットバス、1:8ビットバス |
DATA BYTE | 動作手順 | 操作コード | EN | E | WR | RS | 16進コード | ||||
---|---|---|---|---|---|---|---|---|---|---|---|
4ビットバス設定 | OP1 | 「PCF8574」ポート出力 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | $2C |
OP2 | 「SPLC780D」書き込み | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | $28 |
この操作コードだけが4ビットで、ほかはすべて4ビットx2の8ビットです。
ところで、先に述べたように、「PCF8574」は「I2C communication with this device is initiated by a master sending a start condition(データシートより)」なのですが、まさにこの39行目が「a master sending a start condition」であり、この行によって「PCF8574」が初期化を自動で遂行するのだと考えられます。
そのため、次の40行目のPAUSEはちょっと長めの10msにしました。
41行目は、「2行表示」の設定ですが、単独ではなく、すでに39行目で設定済みの「出力バス幅」とともに設定されます。
RS | WR | 操作(上) | 操作(下) | DATA BYTE:$2C,$28,$8C,$88 | ||||||
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 設定内容:4ビットバス、2行、5x8dots/文字 |
V | V | V | ||||||||
V | V | L>>> | 0:5x8、1:5x10dots/文字 | |||||||
V | L>>>> | 0:1行、1:2行 | ||||||||
L>>>>> | 0:4ビットバス、1:8ビットバス |
DATA BYTE | 動作手順 | 操作コード | EN | E | WR | RS | 16進コード | ||||
---|---|---|---|---|---|---|---|---|---|---|---|
Function set | OP1 | 「PCF8574」ポート出力 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | $2C |
OP2 | 「SPLC780D」書き込み | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | $28 | |
OP3 | 「PCF8574」ポート出力 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | $8C | |
OP4 | 「SPLC780D」書き込み | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | $88 |
43行目は、「LCDに表示する」の設定ですが、ここではカーソルに関する設定もできます。
「操作コード」から「I2CWRITE」の「DATA BYTE」への組み換え成型は41行目と同じなので、以下省略します。
RS | WR | 操作(上) | 操作(下) | DATA BYTE:$0C,$08,$CC,$C8 | ||||||
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 設定内容:画面表示、カーソル非表示、カーソル非点滅 |
V | V | L> | 0:カーソル非点滅、1:カーソル点滅 | |||||||
V | L>> | 0:カーソル非表示、1:カーソル表示 | ||||||||
L>>> | 0:画面非表示、1:画面表示 |
45行目は、「表示の書き進みをする/しない」および「その方向」の設定です。
しかし、ここは実際にプログラムを動かしてみると、下表のようにネット上の資料どおりになりません。
単なる筆者の勘違いなのか、もともと日立製「HD44780」の資料と実物が違うのか、それともいわゆる「相当品」の中には「HD44780」とのソフトウェア互換が不完全なものがあるのか、あるいは他の設定の影響なのか判断しかねます。
RS | WR | 操作(上) | 操作(下) | DATA BYTE:$0C,$08,$6C,$68 | ||||||
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 設定内容:右に書き進み、書き進みする |
V | L> | ネット上の資料はどれも「0:表示は動かない、1:表示は流れる」と読めるのだが、実際にプログラムを動かしてみると「0:左端を固定して右方に書き足す、1:文字列が右端から左方に流れる」動作をした。 | ||||||||
L>> | ネット上の資料はどれも「0:左に書き進み、1:右に書き進み」と読めるのだが、実際にプログラムを動かしてみると、ここの値は動作に影響しない「無効」に見える。 |
49-94行目が文字を繰り返し表示するメインルーチンです。
この中でも、51-84行目は固定した文字の表示、49行目および87-92行目はフレームごとにカウントアップする「数値」の表示です。
数値の表示には、「AQM1602」のプログラムから「数値>桁毎のキャラクタコード」変換のサブルーチン「CONVTVC」を組み入れ、できたキャラクタコードをI2Cコードに変換するのは、他の文字表示と同じく今回開発したサブルーチン「DISPCHAR」を使いました。
最初に49行目で「数値K」をゼロクリアし、次の50-94行目が繰り返しKを表示します。
51行目は「画面クリア」で表示されている文字を消去します。
これは全ビットが固定で、この状態しかありません。
RS | WR | 操作(上) | 操作(下) | DATA BYTE:$0C,$08,$1C,$18 | ||||||
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 設定内容:表示消去 |
52行目だけPAUSEが「500」で長いですが、特に意味は無く、「clear display」を目に見える長さにしているだけです。
53-67行目:LCDの1行目に表示する文字
これらは、各「” ”」内の文字のASCIIコードを変数ASCに取り込み、表示サブルーチン「DISPCHAR」でLCD「CFAH1602X」に表示します。
70-84行目:LCDの2行目に表示する文字
65行目でLCDの文字を表示する個所が2行目に移ります。
下側7ビットで表示RAMアドレスを指定するので、画面のどこにでも指定できます。
RS | WR | 操作(上) | 操作(下) | DATA BYTE:$CC,$C8,$0C,$08 | ||||||
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 設定内容:書き込み位置は2行目の左端 |
LCDの2行目も1行目と同様、プログラム71-84行目の「” ”」内の文字のASCコードを変数ASCに取り込み、表示サブルーチン「DISPCHAR」でLCD「CFAH1602X」に表示します。
87-92行目:数値Kのカウントアップと表示
92行目でカウントアップを続ける変数Kが100になると87行目で0に戻ります。
88行目でその都度の「数値K」に対してサブルーチン「CONVTVC」を使って、10進の桁毎にキャラクタコードを取得します。
その桁毎のキャラクタコードを90行目でI2Cの文字表示サブルーチン「DISPCHAR」でLCDに表示させます。
それを89行目および91行目のループで数値Kの桁数だけ繰り返して、複数桁(ここでは2桁)の数値をLCD表示します。
97-107行目:LCDに文字を表示するサブルーチン
PICは文字のキャラクタコードをASCIIコードで取り扱っています。
たとえば「"A"」はPIC内でASCIIコード「$41」として扱われます。
この値を53-84行目で変数ASCに取り込み、このサブルーチンに来ると98行目で下4ビットが強制的に”0”にクリアされ、変数ASHになります。
これに、99行目で下4ビット「$D」が付け加えられて変数CH1になり、これを105行目でI2Cによって書き込むとASCIIコードの「上4ビット」が「PCF8574」のポートから出力されます。
さらに、100行目でCH1の下表の「E」を”0”にすると変数CH2になり、これを105行目でI2Cによって書き込むとASCIIコードの「上4ビット」が「SPLC780D」に書き込まれます。
次に101行目で変数ASCは「下4ビット」が「上4ビット」に移動し、変数ASLになります。
これに、102行目で下4ビット「$D」が付け加えられて変数CH3になり、これを105行目でI2Cによって書き込むとASCIIコードの「下4ビット」が「PCF8574」のポートから出力されます。
さらに103行目でCH3の下表の「E」を”0”にすると変数CH4になり、これを105行目でI2Cによって書き込むとASCIIコードの「下4ビット」が「SPLC780D」に書き込まれます。
ここでは、仮に文字「A」の場合についてI2CWRITEの「DATA BYTE」成型を以下に示します。
RS | WR | ASCII(上) | ASCII(下) | DATA BYTE:$4D,$49,$1D,$19 | ||||||
---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 表示させる文字:A |
DATA BYTE | 動作手順 | ASCII | EN | E | WR | RS | 16進コード | ||||
---|---|---|---|---|---|---|---|---|---|---|---|
文字"A"表示 | CH1 | 「PCF8574」ポート出力 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | $4D |
CH2 | 「SPLC780D」書き込み | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | $49 | |
CH3 | 「PCF8574」ポート出力 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 1 | $1D | |
CH4 | 「SPLC780D」書き込み | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | $19 |
これを105行目の書式でI2C通信により順に「PCF8574」に書き込むと、当初53-84行目で「” ”」に記述された文字をLCD「CFAH1602X」に表示します。
111行目から117行目は、2桁の10進数Kをキャラクタコードに変換します。
112-114行目
113行目は2桁の10進数Kの各桁を順番に抽出して、サブルーチン「DISP_CODE」に跳んで、相当するASCIIキャラクタコードCODSを持ち帰ります。
この動作を112行目と114行目のループで2回繰り返し、毎回のCODSを2つの変数CODE[0],CODE[1]として保存します。
115-117行目
一般的な10進数の表記として、上位桁の「0」は表示しません。
この3行はその対策ですが、ひとまずここでは最上位であるCODE[1]についてだけ対策しています。
120-134行目
113行目から120行目に跳んで、121行目から132行目で10進数の桁毎の値を、ASCIIキャラクタコードに変換し、134行目から113行目に戻って続きを実行します。
以上により、90行目で2桁の10進数をLCDに表示できます。