正直言って、キャラクタディスプレイなめてました。
Arduinoでは主目的があった上でチェック用のデータ表示用としてLCDを使用していました。また、先達の方々の知恵を拝借して苦もなく解法に行き着いていたのですが、LCDを使う事を主目的として調べていくと自分の無知を思い知るに至っている次第です。
"アスキー表示しかできねーじゃん!!"とか言って、すみません。。。
さて、今回は表示部分を色々触って行きたいと思います。
AE-AQM0802の初期化ですが、1ラインづつ実行していくのも面倒なので、
Ctrl+Eで、まとめてコピペして実行します。Ctrl+Dで実行&終了です。
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
>>>
paste mode; Ctrl-C to cancel, Ctrl-D to finish
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
===
from machine import I2C, Pin
i2c = I2C(scl=Pin(5), sda=Pin(4),freq=400000)
i2c.writeto_mem(0x3e, 0x00, b'\x38')
i2c.writeto_mem(0x3e, 0x00, b'\x39')
i2c.writeto_mem(0x3e, 0x00, b'\x14')
i2c.writeto_mem(0x3e, 0x00, b'\x73')
i2c.writeto_mem(0x3e, 0x00, b'\x56')
i2c.writeto_mem(0x3e, 0x00, b'\x6c')
i2c.writeto_mem(0x3e, 0x00, b'\x38')
i2c.writeto_mem(0x3e, 0x00, b'\x0C')
i2c.writeto_mem(0x3e, 0x00, b'\x01')
i2c = I2C(scl=Pin(5), sda=Pin(4),freq=400000)
i2c.writeto_mem(0x3e, 0x00, b'\x38')
i2c.writeto_mem(0x3e, 0x00, b'\x39')
i2c.writeto_mem(0x3e, 0x00, b'\x14')
i2c.writeto_mem(0x3e, 0x00, b'\x73')
i2c.writeto_mem(0x3e, 0x00, b'\x56')
i2c.writeto_mem(0x3e, 0x00, b'\x6c')
i2c.writeto_mem(0x3e, 0x00, b'\x38')
i2c.writeto_mem(0x3e, 0x00, b'\x0C')
i2c.writeto_mem(0x3e, 0x00, b'\x01')
>>>

>>>
...
...
for i in 'Hello World!':
i2c.writeto_mem(0x3e, 0x40, i.encode())
...i2c.writeto_mem(0x3e, 0x40, i.encode())
...
...
>>>

答えは、DDRAM(Display-Data-RAM)のメモリ配置にあります。
DDRAMに割り当てられているのは80byte(文字)までとなっていて、
2行表示(Function Set : N = 1)
2行表示では、下図の様に1行目、2行目には40byteのアドレスがわは連続しないアドレスが割り当てられています。
- 1行目アドレス範囲 : 0x00 ~ 0x27
- 2行目アドレス範囲 : 0x40 ~ 0x67
画面表示部分 ........ 38 39 40 25 26 27 65 66 67 1 2 3 4 5 6 7 00 01 02 03 04 05 06 40 41 42 43 44 45 46 ........ 38 39 40 25 26 27 65 66 67 1行表示(Function Set : N = 0)
1行表示は、連続した80byteのアドレスで、始点終点アドレスが繋がりループする構造となっています。
- アドレス範囲 : 0x00 ~ 0x4F
画面表示部分 ........ 78 79 80 4D 4E 4F 1 2 3 4 5 6 7 00 01 02 03 04 05 06 ........ 78 79 80 4D 4E 4F
ここで格納された文字データは、Clear Displayを実行しない限り残ったままとなります。
では、実際にデータが残っているのか文字をずらして確認してみましょう。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>
画面表示を左方向にシフトする命令です。左に一文字ずれて"r"の文字が出てきましたね。>>>

Cursor or Display Shift - 命令コード
ここまで来ると全文見たくなるので、キーボードのカーソルキーの"↑"を押すと履歴入力出来るので選択して実行します。D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | S/C | R/L | X | X | |
0 | 0 | 0 | 1 | 0 | 0 | X | X | 0x10 ~ 0x13 |
0 | 0 | 0 | 1 | 0 | 1 | X | X | 0x14 ~ 0x17 |
0 | 0 | 0 | 1 | 1 | 0 | X | X | 0x18 ~ 0x1B |
0 | 0 | 0 | 1 | 1 | 1 | X | X | 0x1C ~ 0x1F |
- S/C : 画面/カーソル選択ビット
0 : カーソルはR / Lビットで制御されます。
1 : 画面はR / Lビットで制御されます。 - R/L : 右/左
0 : 左方向にシフト設定
1 : 右方向にシフト設定
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>
履歴入力を3回ほど繰り返すと、下のようになります。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>

では、"Hello Wo"の状態で右にシフトするとどうなるでしょう?
その前に一度表示位置をを最初の位置に戻してみます。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x02')
>>>
カーソルをホームポジションに戻します。
>>>

Return Home - 命令コード
カーソルをホームポジションに戻す命令です。DDRAMのアドレスカウンタを0x00、カーソルを初期位置に設定します。これによるDDRAMへの影響はありません。
続いて、表示を右にシフトしてみます。D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 1 | X | |
0 | 0 | 0 | 0 | 0 | 0 | 1 | X | 0x02 ~ 0x03 |
>>>i2c.writeto_mem(0x3e, 0x00, b'\x1c')
>>>
Cursor or Display Shift命令で右シフトすると、>>>

それでは、本当に40文字目(DDRAMのアドレス0x27)が表示されているのか確認するために1行目の最終アドレスに文字を書き込んでみます。
>>>
>>>
>>>
i2c.writeto_mem(0x3e, 0x00, b'\xa7')
i2c.writeto_mem(0x3e, 0x40, 'A'.encode())
>>>
i2c.writeto_mem(0x3e, 0x40, 'A'.encode())

上のコードで気になるのは、DDRAMの0x027に書き込むと言いながら、0xA7が指定されている点でしょうか。その疑問を解くには下の解説を読むと理解出来ます。
Set DDRAM Address - 命令コード
D7は1の固定値で、D6~D0のビットにAC6~AC0を使ってDDRAMアドレス設定するので0x80+DDRAMアドレスが命令コードとなります。
1行表示モードでは、DDRAMアドレスは0x80〜0xCF(AC : 0x00〜0x4F)、
2行表示モードでは、1行目のDDRAMアドレスは0x80~0xA7(0x00〜0x27)、
2行目のDDRAMアドレスは 0xC0~0xE7(0x40〜0x67)となります。
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
---|---|---|---|---|---|---|---|---|
1 | AC6 | AC5 | AC4 | AC3 | AC2 | AC1 | AC0 | 0x80 ~ 0xE7 |
1行表示モードでは、DDRAMアドレスは0x80〜0xCF(AC : 0x00〜0x4F)、
2行表示モードでは、1行目のDDRAMアドレスは0x80~0xA7(0x00〜0x27)、
2行目のDDRAMアドレスは 0xC0~0xE7(0x40〜0x67)となります。
ここまでAE-AQM0802で使える概ねの命令を触って来ました。
データシートには、READ系、ICON系の命令もありますが本機では対応していないので、
残る命令は、CGRAM(Character-Generator-RAM)だけとなりました。
このCGRAMも、使えるサイズをOPR1、2ピンを用いて16byte、8byte、6byte、未使用の4つから選択出来るのですが、AE-AQM0802では6byteに設定されています。
とりあえずは、CGRAMアドレスへの書込みも試してみたいと思います。
最初に行うのは、CGRAMへの書込み結果を確認するため先ほど"A"を書き込んだアドレスにCGRAMに割り当てられたアドレス(ここでは0x00)を設定します。データシートには、READ系、ICON系の命令もありますが本機では対応していないので、
残る命令は、CGRAM(Character-Generator-RAM)だけとなりました。
このCGRAMも、使えるサイズをOPR1、2ピンを用いて16byte、8byte、6byte、未使用の4つから選択出来るのですが、AE-AQM0802では6byteに設定されています。
とりあえずは、CGRAMアドレスへの書込みも試してみたいと思います。
>>>
>>>
>>>
i2c.writeto_mem(0x3e, 0x00, b'\xa7')
i2c.writeto_mem(0x3e, 0x40, b'\x00')
>>>
i2c.writeto_mem(0x3e, 0x40, b'\x00')

なければ書けば良いだけなので試してみましょう。
まずは、CGRAM書込み用のアドレスの指定から。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x40')
>>>
>>>
Set DDRAM Address - 命令コード
D7、D6は0、1の固定固定値で、D5~D0のビットにAC5~AC0を使ってCGRAMアドレス設定するので0x40+CGRAMアドレスが命令コードです。
CGRAMアドレスとキャラクタパターンの関係は下の表で確認出来ます。
では、上の表にあるデータをCGRAMへ書き込んでみます。
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
---|---|---|---|---|---|---|---|---|
0 | 1 | AC5 | AC4 | AC3 | AC2 | AC1 | AC0 | 0x40 ~ 0x6F |
CGRAMアドレスとキャラクタパターンの関係は下の表で確認出来ます。
CGRAM Address | Character Patterns (CGRAM Data) |
||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | ||
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | - | - | - | 0 | 0 | 0 | 0 | 0 | 0x40 | 0x00 |
0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0x41 | 0x0A | ||||||||
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0x42 | 0x0A | ||||||||
0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0x43 | 0x00 | ||||||||
1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0x44 | 0x11 | ||||||||
1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0x45 | 0x0E | ||||||||
1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0x46 | 0x00 | ||||||||
1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0x47 | 0x00 | ||||||||
0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | - | - | - | 0 | 0 | 0 | 0 | 0 | 0x48 | 0x00 |
0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0x49 | 0x0A | ||||||||
0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0x4A | 0x0A | ||||||||
0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0x4B | 0x00 | ||||||||
1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0x4C | 0x0E | ||||||||
1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0x4D | 0x11 | ||||||||
1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0x4E | 0x00 | ||||||||
1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0x4F | 0x00 |
>>>i2c.writeto_mem(0x3e, 0x40, b'\x00\x0A\x0A\x00\x11\x0E\x00\x00')
>>>
>>>

上のコードでは、CGRAMのデータを8byteのデータで書き込んでいます。
1byte単位でも書き込めますし、これに限らず他にも解説していない設定もあるので、色々試してみてください。
>>>
>>>
...
...
>>>
>>>
...
...
>>>
>>>
...
...
>>>
>>>
...
...
>>>
i2c.writeto_mem(0x3e, 0x00, b'\x01')
for i in 'Hello':
i2c.writeto_mem(0x3e, 0x40, i.encode())
i2c.writeto_mem(0x3e, 0x00, b'\xc1')
for i in 'World':
i2c.writeto_mem(0x3e, 0x40, i.encode())
i2c.writeto_mem(0x3e, 0x40, b'\x00')
>>>
for i in 'Hello':
i2c.writeto_mem(0x3e, 0x40, i.encode())
i2c.writeto_mem(0x3e, 0x00, b'\xc1')
for i in 'World':
i2c.writeto_mem(0x3e, 0x40, i.encode())
i2c.writeto_mem(0x3e, 0x40, b'\x00')

特に"Read Busy flag and address"の読み込みが出来ないので、Acknowledge信号を拾わない限り、命令、データの送信が完了しているのかも判別出来ませんから、処理終了までの待機時間を想定しないと誤動作の原因となるので注意しましょう。
ほとんどの命令は30μ秒未満で、一部1m秒前後なので何かあれば待機時間を設定して動作検証するレベルで問題ないとは思いますが意識しておいて損はないです。
0 件のコメント:
コメントを投稿