秋月電子I2C接続小型LCDモジュールに表示を行う

〔PICの動かせ方入門に戻る〕


以前、キャラクタLCDのSD1602をPIC16F819で表示を行う記事は書きました。
このLCDは、最低でも6本の線を配線しないと表示できませんでした。
ですが、秋月電子のI2C接続小型LCDモジュール(AQM0802A)はI2Cで配線しますので2本で済みます、
なのでPIC12F1822でも利用可能と言う事になります。
但し、このI2C接続LCDの接続端子間ピッチが 1.5mm なので、
こちらのI2C接続小型LCDモジュールピッチ変換キットを利用しました、
キットなので半田付け必要です。(いやぁ〜、1.5mmピッチの半田付け一苦労しましたぁ)

8x2/16x2のI2C接続LCDについての記事を追記したのと同時にライブラリを大幅に追加&変更しました。
I2C接続LCDは秋月電子[AQM0802A][AQM1602A]やストロベリー・リナックス[SB1602B][SB1602BW]
などの ST7032i 搭載コントローラであればここの記事で利用可能と思います。
但し、2行表示可能LCDを想定した記事です、1行の場合は設定を含め見直さないとダメです。 *2)

《Display Data RAM (DDRAM)》 *2)

通常LCDのDDRAMアドレスを指定してそこに文字データを書き込めば画面に表示されます。
(以下は8文字x2行と16文字x2行のLCDにて説明しますが、1行LCDは少し異なります、
 ここでは"2-line display"ですよ)

DDRAM構成図
DDRAM構成図
緑枠が8文字x2行のLCDで、青枠が16文字x2行のLCDです。

この様に実際は表示している場所以外もDDRAMエリアが有り、その場所に対しても文字データを
書き込めますが表示はされません。(表示させる方法は有ります)
でぇ、その隠れているエリアを表示させる為に、ページ画面と言う概念を用いて私独自の方法で
表示できる機能を提供します、ってこんな機能必要なの?みたいなぁ。

ページ画面機能

下記の様にDDRAMをページ単位に分けて、そのページを指定する事により表示させます。
16文字x2行LCDは[20H]/[60H]以上は使いません。(もったいない人はご自分で行いましょう)

8文字x2行LCDのページ画面DDRAM構成図
8文字x2行LCDのページ画面DDRAM構成図

16文字x2行LCDのページ画面DDRAM構成図
16文字x2行LCDのページ画面DDRAM構成図

《配線図》

LCDピン構成図  左がI2C接続LCDのピン構成図です。
 RESET端子はLOWでリセットがかかるので通常はVDDに接続です
 この変換基板はコンデンサー類が取付けてあるので、
 外付け部品は必要ありません、また、基板裏の"PU"に半田を
 盛ればI2Cプルアップ抵抗(10KΩ)も可能なようです。

 また、バックライトは無く、コントラストはコマンドで設定します。

12F1822配線図  左図がPIC12F1822での配線図です。

 I2C接続LCDは3.3VなのでPICも3.3Vで駆動させます。
 PICの6番がSCL端子で5番がSDA端子です。

 I2C信号用プルアップ抵抗はPIC内蔵のプルアップを。
 使用しています。

 PIC16F1823での接続は
 10番がSCL端子で9番がSDA端子です。
 PIC16F1827での接続は
 10番がSCL1端子で7番がSDA1端子です。

 ※ 電源は3.3Vとなっていますが、昇圧回路OFFで5Vも可能です、5Vでの動作実験は行っています。

昇圧回路について *2)

 ST7032iの電源は3.3V-5VまでOKで、液晶は7Vまでの様で有り、ST7032iの昇圧回路は2倍に
 液晶電源を上げるみたいです。
 ですのでVDD=3.3Vなら昇圧回路ONは良いのですが、VDD=5Vでの昇圧回路ONはダメです。
 VDD=5Vにするなら昇圧回路はOFFで使います

その他LCDのピン構成 *2)

AQM0802ALCDピン構成図  I2C低電圧キャラクタ液晶モジュール(SB1602B)です。
 アイコン表示付、バックライト無です。

 この"RST"端子もリセットです、LOWでリセットが掛かるので
 通常はVDDに接続します。
 電源は3.3Vとなっていますが、昇圧回路OFFで5Vも可能です、
 5Vでの動作実験は行っています。

 バックライト付きは端子番号9番(A)と10番(K)に接続ですが制限抵抗が必要です。

AQM1602ALCDピン構成図  I2C接続小型キャラクタLCDモジュール(AQM1602A)です。
 この様に接続端子側を上に配置で使います。
 あまり意味がなかったのか端子からリセットが無くなっていますね。
 変換基板内では接続はされている様です。

 尚、”電源電圧は3.1〜5.5Vで、Arduinoとの接続が可能です”
 って謳っています、で、付いてくるデータシートに5Vでのスケッチが
 記載されていますがぁ昇圧回路ONのままです、大丈夫ぅ?
 この液晶は耐電圧が上がっているのでしょうか?
 (ここでは5Vで昇圧回路OFFの実験は行っています)

 基板の裏には半田を盛ればプルアップ可能な半田ジャンパーパッドが有ります。
 液晶ガラス(2mm厚)のみなので取り扱いは要注意でしょう。

《ダウンロードプログラムについて》

↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
LCD.lzh(Ver1.00)
LCD.lzh(2015/03/04) *2)
LCD.lzh(2015/04/24) *3)
LCD.lzh "skI2Clib"に、スレーブデバイスのレジスタから読書きを行う関数を追加。 *4)
LCD.zip ライブラリの更新 *5)
LCD.zip "InitI2C_Master"関数の速度指定は、"_XTAL_FREQ"を見て切替える様に変更。*6)

プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。 *2)

ダウンロードしたら解凍して下さい、以下のファイル構成です。
 LCD8x2.c・・・・・・・・PIC12F1822用 8文字x2行LCDソースプログラム *2)
 LCD16x2I.c・・・・・・PIC12F1822用 16文字x2行アイコン付LCDソースプログラム *2)
 LCD1.c・・・・・・・・・・PIC12F1822用 本体のソースプログラム
 LCD2.c・・・・・・・・・・PIC16F1827用 本体のソースプログラム
 skI2CLCDlib.c・・・・I2C接続LCDライブラリ関数ソースファイル *5)
 skI2CLCDlib.h・・・・I2C接続LCDライブラリ用インクルードファイル *5)
 skI2Clib.c・・・・・・・・I2C通信を行う関数ソースファイル *3) *4) *6)
 skI2Clib.h・・・・・・・・I2C通信を行う関数のインクルードファイル *3) *4) *5)

メインプログラムソースに12F1822用と16F1827用を付けときましたので、好きな方でコンパイルを
行って下さい。

LCD1.c/LCD2.c

LCD画面  プログラムを実行させると左図の様に表示します。

 CPUのクロックは8MHzを想定しています。
 クロックを変更する場合は、"skI2CLCDlib.h"と"skI2Clib.c"を
 変更する必要が有ります。

 LCDの写真を撮って、保護フイルムが貼って有るのに気付いたよぉ


LCD16x2I.c *2)

このプログラムは16文字x2行のアイコン付LCDでの動作例です。
"LCD8x2.c"は8文字x2行のLCDでのプログラムですが内容は同じ様な動作ですので説明は省きます。

LCD実行画面1  LCD実行画面2  LCD実行画面3
まず実行すれば左側の画面(0ページ画面)が表示されます。
次に真ん中の画面(1ページ画面)に、5秒後に切り替わります、
更に5秒後に右画面が表示されますが、この画面は1ページ目の画面を書き換えています。
それから5秒後に左側0ページ画面に戻ります。

skI2CLCDlib.h

I2C接続LCDにアクセスする為のライブラリ用のインクルードファイルです。
"skI2CLCDlib.c"を利用する場合に
#include "skI2CLCDlib.h" をプログラムの先頭で記述して下さい。

今回は8MHzで利用しているので、
#ifndef _XTAL_FREQ
 // Unless already defined assume 8MHz system frequency
 // This definition is required to calibrate __delay_us() and __delay_ms()
 #define _XTAL_FREQ 8000000    // 使用するPIC等により動作周波数値を設定する
#endif
と記述しています、8MHz以外で利用する人は"8000000"を書き換えて下さい。

I2Cスレーブアドレスについて  *1)

アドレス設定  アドレスは7ビットで表します、左図の1〜7ビットです。
 0ビット目はR/Wでこれはスレーブに対する読書き指示ビットです。
 R/W=0 : 書き込み要求です(スレーブは受信モード)
 R/W=1 : 読み込み要求です(スレーブは送信モード)

今回のI2C接続小型LCDモジュールアドレスは、"0111110"(0x3e)です。("0111110"+R/W)
資料によっては、R/W=0として"0111110"+"0"で0x7cの8ビットで記載されています注意しましょう。
よってここでは
#define ST7032_ADRES 0x3E   // 秋月電子のI2C接続小型LCDモジュールのアドレス
となっています。
尚、ST7032i搭載コントローラであれば、どのLCDもアドレスはすべて同じ様です。

skI2CLCDlib.c

このライブラリはI2C接続LCDにアクセス(表示)を行う為の関数集です。
尚、このライブラリは、I2C接続小型LCDモジュール(AQM0802A)を想定しています、
なので他のI2C接続LCDで動作するのかは不明です。
この関数集自体は他のPICでも使用出来ます。

この"skI2CLCDlib.c"を使う場合はメインソースファイルの初期化処理部分で
"InitI2C_Master( )"関数を呼び出します。(LCD1.c等を参照下さい) *2)

I2C接続LCDにアクセスを行う関数の使い方を説明します。

 LCD_Init(icon,contrast,bon,colsu) *2)
  LCDの初期化を行う処理です。
  アイコンが無いLCDは使用しないと設定します。
  電源を5V回路にする場合は、必ず、昇圧回路の利用はしない"0"と設定します
   icon      :アイコンを使用するのかを指定します(1=使う 0=使わない)
   contrast:LCDのコントラストを指定します(0−63)
   bon      :昇圧回路の利用有無を指定 1=有り(VDDは3.3V) 0=無し(VDDは5.0V)
   colsu    :画面カラム数を指定します(8/16文字)

 LCD_Contrast(contrast) *2)
  LCDのコントラスト調整を行う処理です。
  数値が小さすぎると表示がされませんので注意が必要かもね。
   contrast:LCDのコントラストを指定します(0−63)

   コントラストの指示を説明します。
     command(0x70) ;     // Contrast set           : コントラスト調整データ(下位4ビット)
     command(0x50) ;     // Contrast set           : コントラスト調整データ(上位2ビット)
   コントラストは6ビットデータで0〜63を設定、今回は32(0b100000)を設定しています。
   0x70=0111xxxx → 下位4ビット(0b0000)をxxxxに設定
   0x50=0101??xx → 上位2ビット(0b10)をxxに設定(??は他の機能用Bit)

 LCD_Clear( )
  LCDモジュールの画面を消し初期状態に戻す処理です。
  画面全体(DDRAM全て)が0x20のスペースで消され、カーソルは1行目の1桁目に移動します。
  ページ画面も初期状態(0ページ)に戻ります。

 LCD_SetCursor(col, row)
  LCDモジュール画面内のカーソル位置を設定する処理です。
  この関数のカーソル位置指定はDDRAM全てに有効ですが、
  表示領域以外だと、文字データは書き込まれますが表示はされません。
   col :横(列)方向のカーソル位置(0-39)を指定
   row:縦(行)方向のカーソル位置(0-1)を指定

 LCD_Putc(c)
  LCDにデータを1バイト出力する処理です。
   c :出力する文字データを指定

 LCD_Puts(*s)
  LCDに文字列データを出力する処理です。
  文字列は、NULL(0x00)まで繰返し出力します。
   *s :出力する文字列のデータを格納した場所のアドレスを指定

  例)
  char mes[5]= {0xca,0xdb,0xb0,0x21,0x00} ; // "ハロー!"

       LCD_SetCursor(0,0) ;      // カーソルは1行目の1桁目に移動
       LCD_Puts(mes) ;           // 文字列を表示する

 LCD_CreateChar(p,*dt)
  オリジナルのキャラクタ(5x7ドット)を登録する処理です。
  キャラクタコードの0x00〜0x05に登録可能です。
   p :登録する場所の指定(0〜5の6ヶ所のみ)
   *dt:登録したいキャラクタのデータを格納したバッファを指定

 注意) この関数をコールした後はLCDのアドレスカウンターがCGRAMになっているので
     この後に表示を行う場合は、DDRAMにアドレスを設定する必要が有ります
     表示する前に"LCD_SetCursor( )"関数を呼び出せば良いでしょう。
  例)
  char heart[7] = {
    0b01010,
    0b11011,
    0b11111,
    0b11111,
    0b01110,
    0b00100,
    0b00000,
  } ;

       LCD_CreateChar(2,heart) ; // 2番に登録する
       LCD_SetCursor(0,1) ;      // この行がないと表示しない
       LCD_Putc(0x02) ;          // 2番に登録したキャラを表示する
 ※ I2C接続小型キャラクタLCDモジュール(AQM1602A)のLCDは0x00〜0x07の8個登録可能です
 ※ ストロベリー・リナックス[SB1602B][SB1602BW]のLCDは0x00〜0x0Fの16個登録可能です。 *2)

 ※ 良く使いそうなキャラクタはEEPROMとかに登録して利用する様な事を行えば良いかもね。

 LCD_IconOnOff(flag, dt) *2)
  指定アイコンの表示ON/OFFを行う処理です。
  アイコン表示が有るLCDのみですよ。
   flag:指定したアイコンの表示をするしない(1=表示する 0=消す)
   dt :アイコンのアドレスとビットを指定します、"skI2CLCDlib.hのdefine宣言で指定します。
  例
   LCD_IconOnOff(1,LCD_ICON_PHONE) ;   // 電話を表示します。

  ※ 消すのはアドレス単位なので、△▽又は、電話関連アイコンは全て消えます。
  ※ アイコンの絵柄等の説明内容は、ストロベリー・リナックスのこちらを参照下さい。

 LCD_IconClear( ) *2)
  全部のアイコン表示を消す処理です。
  表示したままでLCD電源を切っても、電源を入れたら再表示してしまいます。
  なので、立ち上げ処理(setup関数辺り)で一度この処理を実行させないとダメですよ。

 注意) LCD.IconOnOff( )/LCD.IconClear( )の関数をコールした後はLCDのアドレスカウンターが
     ICON RAMになっているので、この後に表示を行う場合は、DDRAMにアドレスを設定する
     必要が有ります、表示する前に"LCD_SetCursor( )"関数を呼び出せば良いでしょう。

 ans = LCD_PageSet(no) *2)
  ページ画面の切り替えを行う処理です。
  単純にページを切り替えるだけなので、切り替える前のページデータは残ったままです。
  又、切り替えには画面のシフトコマンドを使っているのでぇ、パッとは切り替わりません。
   no :表示するページ画面の番号を指定(8x2なら0-4/16x2なら0-1)
   ans:0=正常 −1=指定したページ番号がおかしい

 LCD_PageClear( ) *2)
  現在表示中のページ画面単位での消去を行う処理です。
  カーソル位置も現在表示中のページ画面内、1行目の1桁目に移動します。

 LCD_PageSetCursor(col, row) *2)
  現在のページ画面内でのカーソル設定を行う処理です。
  現在表示中の画面内でのカーソル位置指定ですが、領域外の数値入力はチェックしていないので
  注意しましょう、又は、ご自分でロジックを追加しましょう。
   col :横(列)方向のカーソル位置(8x2なら0-7/16x2なら0-15)を指定
   row:縦(行)方向のカーソル位置(0-1)を指定

 ans = LCD_PageNowNo( ) *2)
  現在表示中のページ画面番号を返す処理です。

skI2Clib.h

I2C通信の関数ライブラリ用インクルードファイルです。
"skI2Clib.c"を利用する場合に
#include "skI2Clib.h" をプログラムの先頭で記述しないとだめです。

デフォルトではMSSP1を使う様になりますが、PICによってはMSSP2が有ります。
MSSP2側を使う場合は、"#define I2C_MSSP2_USE"を記述して下さい。 *3)

skI2Clib.c

このライブラリはI2Cデバイス(RTC/EEPROM等)と接続を行う為の関数集です。
この関数集は12F1822/16F1827/16F18xx系で利用出来ます。
但し、16F1827はSSP2利用不可です、利用する場合はレジスタ名を変更しないとダメです。
この関数集は12F1822/16F182x/16F193x/18F25K22系で利用可能です、
又、SSP1/SSP2何方でもOKです、今回の変更で統合しました。 *3)

I2C通信の関数ライブラリの使い方を説明します。

 InitI2C_Master(speed) *2)
  I2C通信のマスターモードで初期化を行う処理です。
  I2C通信用の速度クロック周波数は100KHz/400KHzでの設定です、
  この速度はFOSC(PICのCPU周波数)8MHzの場合で初期化されています。
   speed  :I2Cの通信速度を指定します。(0=100KHz 1=400KHz)

  尚、このLCDはI2C通信用の速度クロック周波数400KHzにも対応しています。
  又、通信速度を400KHzにしても、実際は250KHz程しか速度は出ません。 *3)

  ※ I2C通信用の速度設定は、"#define _XTAL_FREQ"の内容を見てプログラムを切替える様に変更
    しましたので書換える必要は有りません。
    但し、8/16/32/40/48/64MHzの場合だけです、それ以外のクロック(Fosc)を利用する場合は、
    こちらかデータシートを参考にSSPADDレジスタを変えて下さい。 *6)

 ans = I2C_Start(adrs,rw)
  スレーブにスタートコンディションを発行する処理です。
   adrs  :スレーブのアドレスを指定します
   rw     :スレーブに対する動作の指定をします
        0 = スレーブに書込みなさい要求  1 = スレーブに送信しなさい要求
   ans   :0 = 正常 1 = 異常(相手からACKが返ってこない)

 ans = I2C_rStart(adrs,rw)
  スレーブにリピート・スタートコンディションを発行する処理です。
   adrs  :スレーブのアドレスを指定します
   rw     :スレーブに対する動作の指定をします
        0 = スレーブに書込みなさい要求  1 = スレーブに送信しなさい要求
   ans   :0 = 正常 1 = 異常(相手からACKが返ってこない)

 I2C_Stop()
  スレーブにストップコンディションを発行する処理です。

 ans = I2C_Send(dt)
  スレーブにデータを1バイト送信する処理です。
   dt     :送信するデータを指定します
   ans   :0 = 正常 1 = 異常(相手からACKが返ってこない又はNOACKを返した)
  例)slave_adrsへの2バイト送信
     ans = I2C_Start(slave_adrs,RW_0);  // スタートコンディションを発行する
     if (ans == 0) {
          I2C_Send(dt) ;                // 1バイト目を送信する
          I2C_Send(dt) ;                // 2バイト目を送信する
     } else 異常 ;
     I2C_Stop() ;                       // ストップコンディションを発行する
 c = I2C_Receive(ack)
  スレーブからデータを1バイト受信する処理です。
   ack    :スレーブからデータを受信した後に返答するデータを指定します
        0 = ACKをスレーブに返す 1 = NOACKをスレーブに返す(受信データが最後なら1)
   c       :受信した1バイトのデータを返す
  例)slave_adrsから2バイト受信する
     ans = I2C_Start(slave_adrs,RW_1) ;  // スタートコンディションを発行する
     if (ans == 0) {
          dt1 = I2C_Receive(ACK) ;       // 1バイト目を受信する
          dt2 = I2C_Receive(NOACK) ;     // 2バイト目を受信する
     } else 異常 ;
     I2C_Stop() ;                        // ストップコンディションを発行する
ans = I2C_SlaveRead(slv_adrs,reg_adrs,*data,kosu) *4)
 スレーブのデバイスから指定個数のデータを読み込む処理です。
 センサー等のデバイスのレジスターから値を読み取ります
 マルチマスターに対応しています。
  slv_adrs  :スレーブのデバイスアドレスを指定します(7bitで指定)
  reg_adrs :読出すデータのレジスターアドレスを指定します
        連続的に読出す場合は、読出すレジスターの先頭アドレスを指定
  *data     :読出したデータの格納先を指定します
  kosu      :読出すデータのバイト数を指定します
   ans       :0=正常 1=異常(相手からACKが返ってこない)
        -1=他のマスターとのバス衝突が発生してリトライオーバー

ans = I2C_SlaveWrite(slv_adrs,reg_adrs,*data,kosu) *4)
 スレーブのデバイスに指定個数のデータを書き込む処理です。
 センサー等のデバイスのレジスターに値を書き込みます
 マルチマスターに対応しています。
  slv_adrs  :スレーブのデバイスアドレスを指定します(7bitで指定)
  reg_adrs :書出すデータのレジスターアドレスを指定します
        連続的に書出す場合は、書出すレジスターの先頭アドレスを指定
  *data     :書出すデータの格納先を指定します
  kosu      :書出すデータのバイト数を指定します
   ans       :0=正常 1=異常(相手からACKが返ってこない)
        -1=他のマスターとのバス衝突が発生してリトライオーバー

 InterI2C()
  I2C関連の割り込み処理です。
  メインプログラム(例"LCD.c")の割込み処理で必ず呼びます。
  例)
     void interrupt InterFunction( void )
     {
          // I2C関連の割り込み処理
          InterI2C() ;
     }

《その他》

実はぁ、このI2C接続LCDは前から気になってはいたのですがぁ、なんせ接続端子間が1.5mmピッチ
なので使いずらいと躊躇していたのでした、けど変換基板が出たので使いやすくなり購入してみた次第です

しかしこのLCDは、”English/Japan/European”文字やその他記号などでえらくいっぱいキャラクタが
登録してありますねぇ〜。
キャラクタ一覧はデータシートを見て下さい。データシートはこちら

バックライト付きが欲しい人はこちらのストロベリー・リナックスで販売されています。
秋月の変換基板に穴を開ければ使えるかなぁ?、
てかぁ、秋月さんバックライト付きが挿せる様にパターン作ってほしぃ。
また、アイコン付のLCDが欲しい人はこちらです、バックライト付きならこちら
こちら(SB1602E)はデカ文字LCDらしい。

ストロベリー・リナックスのアプリケーションノートにこんな ST7032iのI2C不具合が有るそうです。



"skI2Clib"ライブラリ変更(*6) 2018/03/19
ライブラリ更新(*5) 2017/01/02
"skI2Clib"に、スレーブデバイスのレジスタから読書きを行う関数を追加(*4) 2016/09/30
ライブラリ変更(*3) 2015/04/24
追記&変更(*2) 2015/03/01
追記(*1) 2013/08/25


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2018 Shigehiro Kimura All Rights Reserved.