前回までにLCDに時刻表示ができましたが、2行目の欄が空いているので温湿度表示を追加したいと思います。

温湿度のセンサーは、以前Arduinoに接続したAM2321を使用したいと思います。

AM2321はi2cによって接続されますので、LCD i/f及びRTCに並列接続となります。

前回のarduinoのデータの読み込み手順に沿ってソフトを作成していきたいと思います。

AM2321のスレーブアドレスは、前回確認している Ox5Cです。

まずは、眠っているAM2321を起こしに行きます。
ダミーの0x00を書き込みに行きますが、眠っているので、応答としてNACKが帰ってきます。
これまでのi2cのプログラムであれば、端末にerr表示をして先に進んでくれません。

ということで、NACKが帰ってきたら強制的にSTOPモードにして、待機状態に戻してあげます。
変更した部分のi2c_writeのプログラムは次の通りとなります。

ld      a,0xc4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
i2c_w_loop2:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_w_loop2

in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x20                    ;;Write data N-ACK
jr      z,data_w_stop           ;;go to Stop mode
cp      0x18
jr      nz,err

次に 1ms待った後に、データ読み込み命令を書き込みします。
この命令は、 スレーブアドレス+W+DATA+DATA+DATAと複数のデータを書き込みする必要がありますので、従来のi2c_writeに対して、複数のデータを書き込み可能な、i2c_buff_writeを新たに作成しました。
HLレジスタに書き込むデータのbuffアドレスを設定します。
Bレジスタには書き込むデータのバイト数
Eレジスタにはスレーブアドレスを設定します。
実際のプログラムは次のようになります。

i2c_buff_write:                         ;;write buff data >> HL reg
;;write buff size >> B reg
;;slave address >> E reg

ld      a,0xe4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 STA=1
i2c_bw_loop1:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_bw_loop1
in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x08
jp      nz,err
in      a,(I2CDAT)
ld      a,e                     ;;Slave address set
sla     a
out0    (I2CDAT),a
ld      a,0xc4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
i2c_bw_loop2:  in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_bw_loop2

in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x20                    ;;Write data N-ACK
jr      z,data_bw_stop          ;;go to Stop mode
cp      0x18
jr      nz,err
;; HL reg = buffer adress
i2c_bw_next:                                        ;; end buffer is "00
ld      a,(hl)                  ;; write data Areg is I2CDAT
out0    (I2CDAT),a
ld      a,0xc4                  ;;Slave recciver mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
i2c_bw_loop3:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_bw_loop3

in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x28
jr      nz,err

inc     hl
djnz    i2c_bw_next

data_bw_stop:
ld      a,0xD4                  ;;Generate STOP mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 SI=0
D_bW_ST0:
in0     a,(I2CCON)              ;; STO=0 ?
bit     4,a
jr      nz,D_bW_ST0
in         a,(I2CSTA)
cp         0xf8
jr         nz,err
ret

このi2c_buff_writeを使って書き込むデータは次のようになります。
       0x03:レジスターを読み込む指令
       0x00:レジスターのスタートアドレスは 0x00から
       0x04:レジスターの読み込み個数は 4レジスター

続いて、2mS後に

AM2321の温湿度データを読みに行きます。
ここでも、複数のデータを読み込みに行かなくていけませんので、従来のi2c_readに対して、複数データ読み込み可能なi2c_buff_readを新たに作成しました。
HLレジスタに読み込んだデータを格納するbuffアドレスを設定します。
Bレジスタには読み込むデータのバイト数
Eレジスタにはスレーブアドレスを設定します。
実際のプログラムは次のようになります。

i2c_buff_read:                          ;;buff >> HL reg
;;buff size >> B reg
;;Slave Address C reg

ld      a,0xe4                  ;;Master Receiver Mode
out0    (I2CCON),a              ;; AA=1 ENSIO=1 STA=1
i2c_br_si01:
in0     a,(I2CCON)              ;; SI=1 ?
bit     3,a
jr      z,i2c_br_si01
in0     a,(I2CSTA)              ;;Poll from transmission finished
cp      0x08
jp      nz,i2c_br_err
in0     a,(I2CDAT)

ld      a,e                     ;read  slave address d reg
scf                             ;set read mode bit0=1
RLA
out0    (I2CDAT),a              ;set slave address
ld      a,0xc4                  ;send data
out0    (I2CCON),a
i2c_br_si06:
in0     a,(I2CCON)
bit     3,a                     ;SI=1 ?
jr      z,i2c_br_si06

in0     a,(I2CSTA)              ;Address+R has been transmitted
cp      0x40                    ;ACK has been received
jr      nz,i2c_br_err

dec     b
jr      z,i2c_br_next_end

i2c_br_next:
ld      a,0xc4                  ;Reset SI And AA bit
out0    (I2CCON),a              ;AA=0 ENSIO=1 STA=0 STO=0
i2c_br_si07:
in0     a,(I2CCON)
bit     3,a                     ;SI=1 ?
jr      z,i2c_br_si07

in0     a,(I2CSTA)              ;Data has been received
cp      0x50                    ;data-ACK has been returned
jr      nz,i2c_br_err

in0     a,(I2CDAT)              ;Received Data read a reg
ld      (HL),a
inc     hl
djnz    i2c_br_next

i2c_br_next_end:

ld      a,0x44                  ;Reset SI And AA bit
out0    (I2CCON),a              ;AA=0 ENSIO=1 STA=0 STO=0
i2c_br_si08:
in0     a,(I2CCON)
bit     3,a                     ;SI=1 ?
jr      z,i2c_br_si08

in0     a,(I2CSTA)              ;Data has been received
cp      0x58                   ;data-ACK has been returned
jr      nz,i2c_br_err

in0     a,(I2CDAT)              ;Received Data read a reg
ld      (HL),a

ld      a,0xd4                  ;Generate STOP command
out     (I2CCON),a              ;AA=1 ENSIO=1 STA=0 STO=1

i2c_br_stop_loop:
in0     a,(I2CCON)
bit     4,a                     ;STO=0 ?
jr      nz,i2c_br_stop_loop
in0     a,(I2CSTA)
cp      0xf8                    ;reset or STOP command
jr      nz,i2c_br_err
xor     a
ret

このi2c_buff_readにより 8バイトのデータを読み込みます。
      0x03:レジスターを読み込みます
      0x04:4つのレジスター内容を4バイトで返します。
      0x??:湿度の高位バイトを返します
      0x??:湿度の低位バイトを返します
      0x??:温度の高位バイトを返します
      0x??:温度の低位バイトを返します
      0xCRC1: CRCを2バイトに分けて返します
      0xCRC2:

読み込んだデータをLCDに表示していきますが、紙面が長くなるので次回に分けたいと思います。

AM2321, Z8S180, I2Cの関連記事
  • Z80(TMPZ84C015)に萌えたい。I2Cソフト:LCD+RTC+温度表示
  • Z80(Z8S180)に萌えたい LCDに温湿度表示(AM2321)その2
  • Z80(Z8S180)に萌えたい LCDに温湿度表示(AM2321)その1
おすすめの記事
Z8S180
内蔵タイマーの確認を行ってみました。 内蔵タイマーは2チャンネルありますが、ここでは1チャンネルだけでLED 点滅(といっても 20mSの速...
Z8S180
I2C通信が行えるようにZ8S180にパラレル-I2C変換用IC PCA9564Dを接続したいと思います。 なお、PCA9564Dは以前、Z...
Z8S180
ハード的にマイコンとの通信がUSB経由でできるようになりましたので、Z80側に通信用確認プログラムを作成して、ちゃんと通信できるか確認したい...