前回までに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に表示していきますが、紙面が長くなるので次回に分けたいと思います。