I2C通信の準備ができたら、次にLCD表示に進みます。
今回使うI2C用LCDAQM0802Aは、8文字2行の小さなLCDです。コントラスト調節は、コマンドで行います。
まず、LCDを初期化します。
手順は、I2Cで次のようなコマンドを順番に送ります。各コマンドとコマンドの間には26.3μs以上の待ち時間をとります。
ただし、最初に40ms以上、Follower Controlコマンドの後には、200ms以上、Clear Displayの後には1.08ms以上の待ち時間が必要です。
アセンブラで書くと
;--- LCDの初期化 ----
LCD_Ini
MOVLW d'40'
CALL waitms ;40ms待つ
MOVLW 0x38 ;8bit,2line
CALL LCD_cmd ;Function set
MOVLW 0x39 ;IS=1:extention modeにする。
CALL LCD_cmd ;Function set
MOVLW 0x14
CALL LCD_cmd ;Internal OSC Frequency
MOVLW 0x70
CALL LCD_cmd ;Contrast set
MOVLW 0x56
CALL LCD_cmd ;Power/ICON/Contrast Control
MOVLW 0x6C
CALL LCD_cmd ;Follower Control
MOVLW d'200'
CALL waitms ;200ms待つ
MOVLW 0x38 ;IS=0:extention mode解除
CALL LCD_cmd ;Function set
MOVLW 0x0C
CALL LCD_cmd ;Display ON
MOVLW 0X01
CALL LCD_cmd ;Clear Display
MOVLW 2
CALL waitms ;2ms待つ
RETURN
LCD_Ini
MOVLW d'40'
CALL waitms ;40ms待つ
MOVLW 0x38 ;8bit,2line
CALL LCD_cmd ;Function set
MOVLW 0x39 ;IS=1:extention modeにする。
CALL LCD_cmd ;Function set
MOVLW 0x14
CALL LCD_cmd ;Internal OSC Frequency
MOVLW 0x70
CALL LCD_cmd ;Contrast set
MOVLW 0x56
CALL LCD_cmd ;Power/ICON/Contrast Control
MOVLW 0x6C
CALL LCD_cmd ;Follower Control
MOVLW d'200'
CALL waitms ;200ms待つ
MOVLW 0x38 ;IS=0:extention mode解除
CALL LCD_cmd ;Function set
MOVLW 0x0C
CALL LCD_cmd ;Display ON
MOVLW 0X01
CALL LCD_cmd ;Clear Display
MOVLW 2
CALL waitms ;2ms待つ
RETURN
さて、各コマンドをLCDに送る方法です。
LCDに送るのは、コマンドとデータの2種類です。これを区別するためにスレーブアドレスに続いてコントロールコマンドを送り、次にコマンドまたはデータ(文字)を送ります。
コントロールバイトのCoは、連続しない1バイト送信の場合は、Co=0、複数のデータを送る場合は、Co=1です。
RSについては、RS=0で次のバイトがコマンドであることを、RS=1で次のバイトがデータであることを示します。
従って、コマンドを送るルーチンは
;--- LCDにコマンドを送る ---
;Wレジスタにコマンドをセット
;Wレジスタにコマンドをセット
LCD_cmd
MOVWF TEMP ;Wレジスタの内容をTEMPに保存
CALL I2C_Start ;スタートコンディション発行
CALL I2C_Add ;スレーブアドレス送信
CALL I2C_Ack ;Ackチェック
MOVLW 0x00 ;コントロールバイト(Co=0,RS=0)
CALL I2C_Data ;コントロールバイト送信
; CALL I2C_Ack ;Ackチェック
MOVFW TEMP ;TEMPの内容をWレジスタにセット
CALL I2C_Data ;コマンド送信
; CALL I2C_Ack ;Ackチェック
CALL I2C_Stop ;ストップコンディション発行
CALL wait26us ;26.5us待つ
RETURN
;--- LCDに1文字送る ---
;Wレジスタに文字(ASCIIコード)をセット
LCD_char
MOVWF TEMP ;Wレジスタの内容をTEMPに保存
CALL I2C_Start ;スタートコンディション発行
CALL I2C_Add ;スレーブアドレス送信
CALL I2C_Ack ;Ackチェック
MOVLW 0x40 ;コントロールバイト(Co=0,RS=1)
CALL I2C_Data ;コントロールバイト送信
; CALL I2C_Ack ;Ackチェック
MOVFW TEMP ;TEMPの内容をWレジスタにセット
CALL I2C_Data ;1文字送信
; CALL I2C_Ack ;Ackチェック
CALL I2C_Stop ;ストップ・コンディション発行
CALL wait26us ;26.5us待つ
RETURN
MOVWF TEMP ;Wレジスタの内容をTEMPに保存
CALL I2C_Start ;スタートコンディション発行
CALL I2C_Add ;スレーブアドレス送信
CALL I2C_Ack ;Ackチェック
MOVLW 0x00 ;コントロールバイト(Co=0,RS=0)
CALL I2C_Data ;コントロールバイト送信
; CALL I2C_Ack ;Ackチェック
MOVFW TEMP ;TEMPの内容をWレジスタにセット
CALL I2C_Data ;コマンド送信
; CALL I2C_Ack ;Ackチェック
CALL I2C_Stop ;ストップコンディション発行
CALL wait26us ;26.5us待つ
RETURN
;--- LCDに1文字送る ---
;Wレジスタに文字(ASCIIコード)をセット
LCD_char
MOVWF TEMP ;Wレジスタの内容をTEMPに保存
CALL I2C_Start ;スタートコンディション発行
CALL I2C_Add ;スレーブアドレス送信
CALL I2C_Ack ;Ackチェック
MOVLW 0x40 ;コントロールバイト(Co=0,RS=1)
CALL I2C_Data ;コントロールバイト送信
; CALL I2C_Ack ;Ackチェック
MOVFW TEMP ;TEMPの内容をWレジスタにセット
CALL I2C_Data ;1文字送信
; CALL I2C_Ack ;Ackチェック
CALL I2C_Stop ;ストップ・コンディション発行
CALL wait26us ;26.5us待つ
RETURN
のように組んでみました。
ここで、問題点があります。Ackチェックルーチンをスレーブアドレス送信後、コントロールバイト送信後、コマンドまたはデータの送信後においたのですが、うまくうごきませんでした。
Ackチェックルーチンを入れないと動きます。原因をまだ解明できていませんが、スレーブアドレス送信後に入れた場合は、OKだったので、後の2回のAckチェックには、;を入れて実行しないようにしています。
実際にコントロールコマンドを送った時のSCLとSDA信号をPicoScopeで見てみました。
LCDクリアコマンド0x01をLCDに送信するI2C信号です。青がSCL、赤がSDAです。
スタートコンディション、ストップコンディションの様子がよくわかります。
とりあえず、I2C LCDに表示ができるようになりましたが、完璧に理解したわけではありません。
この記事を読んで説明してただける方、コメントをお願いします。