2019年2月23日土曜日

MicroPythonでAE-AQM0802を使ってみた。

"MicroPythonでAE-AQM0802を使ってみる"の続きです。

正直言って、キャラクタディスプレイなめてました。
Arduinoでは主目的があった上でチェック用のデータ表示用としてLCDを使用していました。また、先達の方々の知恵を拝借して苦もなく解法に行き着いていたのですが、LCDを使う事を主目的として調べていくと自分の無知を思い知るに至っている次第です。
"アスキー表示しかできねーじゃん!!"とか言って、すみません。。。

さて、今回は表示部分を色々触って行きたいと思います。

AE-AQM0802の初期化ですが、1ラインづつ実行していくのも面倒なので、
Ctrl+Eで、まとめてコピペして実行します。Ctrl+Dで実行&終了です。
>>>
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')

>>>
次に前回と同じように、AE-AQM0802に文字を表示してみます。
>>>
...
for i in 'Hello World!':
i2c.writeto_mem(0x3e, 0x40, i.encode())
...
...
...
>>>
"hello Wolrd!"と表示したのですが、横に8文字しか表示出来ないので文字が切れちゃってますね。"rld!"の4文字は、どこに行ってしまったんでしょうか?

答えは、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 : 右方向にシフト設定
この命令は、カーソルまたは表示位置を左右にシフトするためのものです。2行モードでは、画面のシフトを行うと表示画面全体がシフトされ、カーソル選択では1行目の40桁を越えると2行目にカーソルが移動します。表示データのシフトを繰り返すと、各行のシフトが別々に移動します。なお、これらの処理を行ってもアドレスカウンタの内容には影響しません。
ここまで来ると全文見たくなるので、キーボードのカーソルキーの"↑"を押すと履歴入力出来るので選択して実行します。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>i2c.writeto_mem(0x3e, 0x00, b'\x18')
>>>
履歴入力を3回ほど繰り返すと、下のようになります。
ちゃんとアドレスに残っていましたね。
では、"Hello Wo"の状態で右にシフトするとどうなるでしょう?
その前に一度表示位置をを最初の位置に戻してみます。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x02')
>>>
カーソルをホームポジションに戻します。
Return Home - 命令コード
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
カーソルをホームポジションに戻す命令です。DDRAMのアドレスカウンタを0x00、カーソルを初期位置に設定します。これによるDDRAMへの影響はありません。
続いて、表示を右にシフトしてみます。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x1c')
>>>
Cursor or Display Shift命令で右シフトすると、
スペースが出てきます。これは"Clear Display"命令でDDRAMのアドレスを"20H"(スペースコード)で埋めていた結果です。
それでは、本当に40文字目(DDRAMのアドレス0x27)が表示されているのか確認するために1行目の最終アドレスに文字を書き込んでみます。
>>>
>>>
i2c.writeto_mem(0x3e, 0x00, b'\xa7')
i2c.writeto_mem(0x3e, 0x40, 'A'.encode())
>>>
最初にDDRAM1行目の最終アドレスを指定し、その後"A"を書き込んでいます。
"A"が表示されたでしょうか?
上のコードで気になるのは、DDRAMの0x027に書き込むと言いながら、0xA7が指定されている点でしょうか。その疑問を解くには下の解説を読むと理解出来ます。
Set DDRAM Address - 命令コード
D7 D6 D5 D4 D3 D2 D1 D0
1 AC6 AC5 AC4 AC3 AC2 AC1 AC0 0x80 ~ 0xE7
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)となります。
ここまでAE-AQM0802で使える概ねの命令を触って来ました。
データシートには、READ系、ICON系の命令もありますが本機では対応していないので、
残る命令は、CGRAM(Character-Generator-RAM)だけとなりました。
このCGRAMも、使えるサイズをOPR1、2ピンを用いて16byte、8byte、6byte、未使用の4つから選択出来るのですが、AE-AQM0802では6byteに設定されています。
とりあえずは、CGRAMアドレスへの書込みも試してみたいと思います。
最初に行うのは、CGRAMへの書込み結果を確認するため先ほど"A"を書き込んだアドレスにCGRAMに割り当てられたアドレス(ここでは0x00)を設定します。
>>>
>>>
i2c.writeto_mem(0x3e, 0x00, b'\xa7')
i2c.writeto_mem(0x3e, 0x40, b'\x00')
>>>
なんだか先ほど見たような画面になりましたが、CGRAMにデータが何も登録されていないので空白が表示されたわけです。
なければ書けば良いだけなので試してみましょう。
まずは、CGRAM書込み用のアドレスの指定から。
>>>i2c.writeto_mem(0x3e, 0x00, b'\x40')
>>>
Set DDRAM Address - 命令コード
D7 D6 D5 D4 D3 D2 D1 D0
0 1 AC5 AC4 AC3 AC2 AC1 AC0 0x40 ~ 0x6F
D7、D6は0、1の固定固定値で、D5~D0のビットにAC5~AC0を使ってCGRAMアドレス設定するので0x40+CGRAMアドレスが命令コードです。
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
では、上の表にあるデータをCGRAMへ書き込んでみます。
>>>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')
>>>
2行表示とCGRAMデータのサンプルです。
ここまで、表示周りの使用方法を解説して来ましたが、一番重要なのは各命令の処理時間です。マスター側の処理速度、マスタースレーブ間の通信速度にもよりますが、AE-AQM0802に送られて来た命令を実行する極わずかな処理時間が発生します。
特に"Read Busy flag and address"の読み込みが出来ないので、Acknowledge信号を拾わない限り、命令、データの送信が完了しているのかも判別出来ませんから、処理終了までの待機時間を想定しないと誤動作の原因となるので注意しましょう。
ほとんどの命令は30μ秒未満で、一部1m秒前後なので何かあれば待機時間を設定して動作検証するレベルで問題ないとは思いますが意識しておいて損はないです。

0 件のコメント:

コメントを投稿