トップページ     電子回路のページのトップ

 I2C液晶表示器用ライブラリ

秋月電子の小型I2C液晶表示器

 少し前のことですが、秋月電子で小型のI2C液晶表示器が発売されたので購入してみました。
 8文字×2行で3.3V電源で使えます。
 しかしながら、使う機会が無いまま、ずっと埃をかぶっていました。
 小さい為、結線と固定が少し面倒でした。
 その後、ピッチ変換基板が発売されたので購入したのですが、今ならセットで購入した方が得です。
 使うには表示器用の関数を作らなければなりません。
 MikroCにもソフトウエアI2Cの基本的な組み込み関数が用意されているようですが、これらを使って表示用の ライブラリーを作るのは、かえって面倒な気がします。
 そこで、最初から作ることにしました。
 今回は秋月電子で売られている8文字2行の表示器用のライブラリーとします。
 他のI2C表示器が手元に無いので、そのまま流用出来るかどうかは分かりません。
 もし、流用出来ないとしても、僅かな修正で済むと思います。
 I2Cはソフトウエアで実現しています。
 PICにはI2Cのハードウエアを持っているものも多く存在します。
 ソフトウエアで実現した場合、効率が落ちますが、表示器はデータ量が少なく、スピードも遅いので十分、実用になると 思います。
 ディレー関数だけMikroCの組み込み関数を使っています。


結線図

結線図

 CPUはPIC12F1822を使用しました。
 当初、死蔵していた12F675を使う予定でしたが、内蔵クロックが4MHz固定ですので、他のCPUでクロックの周波数が 上がった時、動作するか保証がありません。
 12F1822はクロックの周波数が31KHz〜32MHzまで、多くのポイントが選択できます。
 とりあえず、最大の32MHzで試せば、低い周波数は問題ないと思います。
 12F1822はハードウエアのI2Cユニットを内蔵していますので、信号ピンはハードウエアに合わせてあります。
 ただし、I2Cユニットは使用していないので、入力専用のRA3ピン以外の任意のピンが使えます。
 勿論、ヘッダファイルで使用したピンを宣言しておく必要はあります。
 I2Cの信号ピンはオープンドレインでなければならないですが、12F1822のポートはオープンドレインでは ありません。
 従ってHレベルを出力するときはポートを入力に切り換え、プルアップ抵抗でHレベルを確保します。
 Lレベルはポートを出力にして0を出力します。
 ピッチ変換基板のプルアップ抵抗は使わず、外付けしています。
 内蔵の10KΩでは、やや値が大きくHの立ち上がりが遅れる気がします。
 4.7KΩを付けましたが、電圧も低いので、2.2KΩ〜3.3KΩでも良かったと思います。
 いずれにせよ、スピードと消費電力の兼ね合いです。
 尚、結線図の部品番号はCADが自動で割り付けたもので、変換基板のシルク印刷の部品番号と整合性がありません。


ヘッダーファイル

///////////////////////////////////////////////////////
//   global.h                                        //
//   IIC 液晶表示器 AQM0802A-RN-GBW 表示用ヘッダー   //
//   H26/01/19   MikroC Pro for PIC Ver 6.0.0        //
///////////////////////////////////////////////////////
#ifndef _GLOBAL_H
#define _GLOBAL_H

/////////   型の短縮名称
typedef unsigned char   uchar;
typedef unsigned int    uint;
typedef unsigned long   ulong;

/////////   ハードウエア依存部
//          SDA:RA2,SCL:RA1
#define SDA_IN      TRISA.B2 = 1                //SDAを入力に
#define SDA_OUT     TRISA.B2 = 0                //SDAを出力に
#define SCL_ON      TRISA.B1 = 1                //SCL = 1
#define SCL_OFF     {LATA.B1 = 0;TRISA.B1 = 0;} //SCL = 0
#define SDA_ON      TRISA.B2 = 1                //SDA = 1
#define SDA_OFF     {LATA.B2 = 0;TRISA.B2 = 0;} //SDA = 0
#define DATA_IN      (PORTA.B2 & 0x4)           //データ入力
#define S_ADDR      0x7c                        //スレーブアドレス

/////////   関数のプロトタイプ宣言
extern void Lcd_init(void);             //液晶表示器初期化
extern void Lcd_clear(void);            //画面消去
extern void Lcd_cmd(uchar);             //コマンド書き込み
extern void Lcd_cursol(uchar);          //カーソル位置のセット
extern void Lcd_putc(char);             //1文字表示
extern void Lcd_str(char *);            //文字列表示
extern void Lcd_setCG(uchar,char *);    //オリジナルキャラクタ登録

#endif

 今回、ヘッダーファイル、ライブラリールーチン、メインルーチンの3つのファイルをプロジェクトに追加しました。
 このヘッダファイルはライブラリールーチン、メインルーチンの両方から参照されます。
 まず、長い名前を短く書き直しています。
 次にポートでの処理をマクロ定義しています。
 ここを書き換えれば任意のPIC、任意のポートが使えるはずです。
 ただし、入力専用、出力専用のピンは使えません。
 関数のプロトタイプ宣言ですが、これらの関数はライブラリーとメインルーチンの両方で参照されます。


ライブラリールーチン

/////////////////////////////////////////////////////
//   i2lcdlib.C                                    //
//   IIC 液晶表示器 AQM0802A-RN-GBW ライブラリー   //
//   H26/01/19   MikroC Pro for PIC Ver 6.0.0      //
/////////////////////////////////////////////////////
#include "global.h"

/////////       ポート初期状態
void    i2c_init(void){
    SDA_ON;             //SDA = 1
    SCL_ON;             //SCL = 1
}

/////////       スタートコンディション
void    i2c_start(void){
    SDA_ON;             //SDA = 1
    SCL_ON;             //SCL = 1
    Delay_us(1);
    SDA_OFF;            //SDA = 0
    Delay_us(1);
    SCL_OFF;            //SCL = 0
}

/////////       ストップコンディション
void    i2c_stop(void){
    SCL_OFF;            //SCL = 0
    SDA_OFF;            //SDA = 0
    Delay_us(1);
    SCL_ON;             //SCL = 1
    Delay_us(1);
    SDA_ON;             //SDA = 1
}

/////////       書込基本関数
//              引数:書込データ
//              戻り値:0=成功、1=失敗
uchar i2c_write(uchar wdata){
    uchar i,ack;
    
    SDA_OUT;                    //SDAを出力方向に
    for(i=0;i<8;i++){
        if(wdata & 0x80)SDA_ON; //Hを出力
        else SDA_OFF;           //Lを出力
        asm NOP;
        SCL_ON;                 //SCL = 1
    Delay_us(1);
        SCL_OFF;                //SCL = 0
        if(i<7)wdata=wdata<<1;
    }
    SDA_IN;                     //SDAを入力方向に
    asm NOP;
    SCL_ON;                     //SCL = 1
    Delay_us(1);
    ack = DATA_IN;              //書込ステータスを入力
    SCL_OFF;                    //SCL = 0
    return ack;
}

/////////   コマンド書き込み
//          引数:書き込みコマンド
//          戻り:0=成功、1=失敗
uchar Lcd_cmd(uchar cmd){
    i2c_start();                        //IIC 終了
    if(i2c_write(S_ADDR)) goto err;     //スレーブアドレス書き込み
    if(i2c_write(0b10000000)) goto err; //コントロールバイト
    if(i2c_write(cmd)) goto err;        //コマンド書込
    i2c_stop();                         //IIC 終了
    Delay_us(26);
    return 0;
err:                                    //エラー
    i2c_stop();
    return 1;
}

/////////   表示位置
//          引数:表示位置(1行目0x0〜0x7、2行目0x40〜0x47)
void Lcd_cursol(uchar ddram_addr){
    uchar dummy;
    ddram_addr |= 0x80;
    dummy = Lcd_cmd(ddram_addr);
}

/////////   表示消去
void Lcd_clear(void){
    Lcd_cmd(0x01);
    Delay_ms(1);
    Delay_us(80);
}

/////////   液晶の初期化
void Lcd_init(){
     i2c_init() ;       //                  ポート初期化
     Delay_ms(40);      //                  40ms待つ
     Lcd_cmd(0x38);     // function set     8ビットモード2行
     Lcd_cmd(0x39);     // function set     拡張コマンドを有効にする
     Lcd_cmd(0x14);     // バイアスの       選択と内部発振周波数の調整
     Lcd_cmd(0x70);     // Contrast set     コントラスト調整データ(下位4ビット)
     Lcd_cmd(0x56);     // Contrast set     昇圧回路有効、コントラスト調整データ(上位2ビット)
     Lcd_cmd(0x6C);     // Follower control フォロア回路をONし増幅率の調整を行う
     Delay_ms(200);     //                  電力が安定するまで待つ
     Lcd_cmd(0x38);     // function set     拡張コマンドを無効にする
     Lcd_cmd(0x0c);     // display control  画面表示はON・カーソル表示はOFF
     Lcd_cmd(0x01);     // Clear Display    画面消去
     Delay_ms(1);
     Delay_us(80);
}

/////////   1文字表示
void Lcd_putc(char c){
    uchar dummy;
    i2c_start();                    //スタートコンディション
    if(i2c_write(S_ADDR))goto err;  //スレーブアドレス
    dummy = i2c_write(0b11000000);  //コントロールバイト
    dummy = i2c_write(c);           //文字書き込み
err:
    i2c_stop();                     //ストップコンディション
    Delay_us(26);
}

/////////    文字列の表示
void Lcd_str(char *s){
    uchar dummy;
    i2c_start();                    //スタートコンディション
    if(i2c_write(S_ADDR))goto err;  //スレーブアドレス
    dummy = i2c_write(0b01000000);  //コントロールバイト
    while(*s){
        dummy = i2c_write(*s);
        *s++;
    }
err:
    i2c_stop();
    Delay_us(26);
}

/////////   自作キャラクタの登録
//          引数:登録アドレス(0〜5)、登録データへのポインタ
void Lcd_setCG(uchar addr,char *dp){
    uchar dummy, i;
    
    i2c_start();                        //IIC 開始
    if(i2c_write(S_ADDR))goto err;      //スレーブアドレス書き込み
    dummy = i2c_write(0b10000000);      //コントロールバイト(コマンド書き込み)
    addr = addr << 3;                   //1キャラクタで8バイトの書き込み領域
    dummy = i2c_write(0x40 | addr);     //書き込み位置
    dummy = i2c_write(0b01000000);      //コントロールバイト(データ書き込み)
    for(i=0;i<7;i++){                   //キャラクタデータを送る
        i2c_write(*dp);
        dp++;
    }
err:
    i2c_stop();
    Delay_us(26);
}

 この液晶表示器は書き込みだけでステータス等の読み込みは出来ません。
 従ってライブラリーは書き込み関数だけです。
 ただし、液晶表示器が出力するACKは読み込める必要があります。
 スタートコンディション、ストップコンディション、基本書き込み関数は参考書(後述)に説明されていたタイムチャートを そのまま再現しました。
 タイムチャートに記載されているセットアップ時間や最小パルス幅はCPUのクロック周波数が変わっても確保されなければ なりません。
 今回は12F1822の最高周波数32MHzと8MHzで動作を確認しています。
 初期化ルーチンは液晶に添付されていた資料のサンプルをそのまま使っています。
 この資料には各種コマンドのフォーマットが記されています。
 コントラストはコマンドで設定するのでVRが不要です。
 VRで調整できる方が便利な気もしますが・・・・
 MikroCはポインタが使えますが、文字列変数も文字列定数も同じポインターで受け付けてしまうようです。
 PICはROMのアドレス空間とRAMのアドレス空間(スタックの空間も)が異なっているので本来は互換性が無いはず です。
 厳密なコンパイラでは文字列定数を一旦RAMにコピーするか、ROM用の関数とRAM用の関数を用意します。
 今までパラレル入力の液晶表示器では1文字表示する度に40uSの遅れ時間を付加していたのですが、今回はとりあえず8文字 送り、最後に26uSを1回送るだけで表示出来ました。
 注)26uSはデータシートに記載された値(正確には最大26.3uS)です。


メインルーチン

///////////////////////////////////////////////////
//   i2lcdt1.C                                   //
//   IIC 液晶表示器 AQM0802A-RN-GBW 表示テスト   //
//   H26/01/19   MikroC Pro for PIC Ver 6.0.0    //
///////////////////////////////////////////////////
#include "global.h"

// CLOCK 32MHz
// Oscillator INTOSC, Watchdog OFF, Power-up Timer ON,
// MCLR Pin ON, Code Protection OFF, Data Protection OFF,
// Brown-out Reset ON, Clock Out OFF, Int/Ext Switchover OFF,
// Fail-safe Clock Monitor OFF, F-Memory Self W-protection OFF, Pll ON
// Stack Of/Uf Reset ON, Brown-out Reset 1.9V, LVP OFF

const char CG_DATA1[]={0x15,0x0a,0x15,0x0a,0x15,0x0a,0x15}; //市松模様
char CG_DATA2[] = {0x1f,0,0x1f,0,0x1f,0,0x1f};              //横縞
const char *RomData = "ROM**";
char *RamData = "RAM!!";
const char C0 = '0';
char C1 = '1';

void main(){
    OSCCON = 0x70;          //内部 32MHz
    OPTION_REG = 0xc0;      //タイマー0関連ダミー
    ANSELA = 0;             //ALL DIGITAL
    TRISA = 0xe;            //ポート入出力設定
    WPUA = 0;               //PULL UP OFF
    Delay_ms(100);          //電源の安定を待つ
    Lcd_init();             //液晶表示器初期化
    Lcd_setCG(0,CG_DATA1);  //市松模様を登録
    Lcd_setCG(1,CG_DATA2);  //横縞を登録
    Lcd_cursol(0);          //表示位置1行目先頭
    Lcd_str(RomData);       //ROM領域の文字列を表示
    Lcd_cursol(0x06);       //1行目5文字目
    Lcd_putc('0');          //CGRAMアドレス表示
    Lcd_putc(0);            //市松模様を表示
    Lcd_cursol(0x40);       //表示位置2行目先頭
    Lcd_str(RamData);       //RAM領域の文字列を表示
    Lcd_cursol(0x46);       //表示位置2行目5文字目
    Lcd_putc('1');          //CGRAMアドレス表示
    Lcd_putc(0x01);         //横縞を表示
    Delay_ms(1000);         //2秒表示
    Delay_ms(1000);
    Lcd_clear();            //画面を消去して
    Delay_ms(1000);         //2秒待つ
    Delay_ms(1000);
    Lcd_cursol(0);          //同じ表示をもう一回繰り返す
    Lcd_str("ROM**");
    Lcd_cursol(0x06);
    Lcd_putc(C0);
    Lcd_putc(0);
    Lcd_cursol(0x40);
    Lcd_str("RAM!!");
    Lcd_cursol(0x46);
    Lcd_putc(C1);
    Lcd_putc(0x01);
    asm SLEEP;
    asm NOP;
}

 メインルーチンは作成したライブラリーの動作を確認する為のもので、内容に意味はありません。
 自作キャラクタとして市松模様と横縞を登録してあります。
 ポインターが何でも受け付けてしまうようですので表示データは定数と初期化された変数を用意しました。
 2秒間表示した後、2秒間消去し、同じ内容をもう一度表示します。
 その後CPUはスリープしますが、表示内容は維持されます。


プロジェクトの構成とビルド結果

プロジェクトの構成 ビルド結果


表示内容

表示内容


参考にした書籍

参考した書籍

 写真は10年以上前にH8−3002でI2Cメモリ(24LCXX)を読み書きしたとき参考にした書籍です。
 2001年に出版されたもので、現在も出版されているかは知りません。
 各種メモリの構造、特性、ピン配置、動作タイミング、読み書き手順等が解説されています。
 液晶表示器とメモリではコマンドの送り方は違いますが基本的なタイミングは同じです。

 

2014/12 追補

 I2C液晶は書き込みだけですので読み出し関数は不要でした。
 私自身の為のメモ書きとして読み出し関数を以下にUPしました。
 ただし、今のところ動作を確認する対象が無く、デバッグされていません。
/////////   読み出し基本関数
//          引数:1=ACKを返す0=NAKを返す、戻り値:読出データ
uchar i2c_read(uchar cmd){
    uchar i,ret;

    ret=0;
    SDA_IN;                         //データを入力方向に
    for(i = 0; i < 8; i++){
        SCL_ON;                     //クロック立ち上げ
        Delay_us(1);
        if(SDA_IN) ret |= 0x01;     //データ入力
        if(i < 7) ret = ret << 1;
        SCL_OFF;                    //クロック立ち下げ
        Delay_us(1);
    }
    if(cmd){SDA_OFF;}               //ACKを返す
    else SDA_ON;                    //NACKを返す
    asm NOP;
    SCL_ON;                         //クロック立ち上げ
    Delay_us(1);
    SCL_OFF;                        //クロック立ち下げ
    return(ret);
}

 I2C液晶表示器用ライブラリU

 ハードウエアI2C

 PIC12F1822はI2Cのハードウエアを持っています。
 液晶表示器では前述のソフトウエアI2Cで十分ですが、もう少し高速に大量のデータを送る場合はハードウエアを使用すれば 効率が上がります。
 ただし、実験ですので同じ回路を使います。
 前述のソフトウエアI2Cはピンの位置をハードウエアのSDA、SCLに合わせておいたので、プログラムの変更で 済みます。
 ソースはメインクロック4MHz、ボーレート100KHzを記しましたが、32MHz、400KHzでも動作の確認を しましたので、後で変更点を示します。
 回路と動作写真はソフトI2Cと同じですので省略します。

ヘッダーファイル

///////////////////////////////////////////////////////
//   i2lcdt1.h                                        //
//   IIC 液晶表示器 AQM0802A-RN-GBW 表示用ヘッダー   //
//   H26/01/19   MikroC Pro for PIC Ver 6.0.0        //
///////////////////////////////////////////////////////
#ifndef _I2LCDT1_H
#define _I2LCDT1_H

/////////   型の短縮名称
typedef unsigned char   uchar;
typedef unsigned int    uint;
typedef unsigned long   ulong;

/////////   ハードウエア依存部
#define S_ADDR      0x7c                //スレーブアドレス

/////////   関数のプロトタイプ宣言
extern void I2init(void);
extern void I2startCon(void);
extern void I2startRep(void);
extern void I2stop(void);
extern uchar I2write(uchar);
extern uchar I2read(uchar);

extern void Lcd_init(void);             //液晶表示器初期化
extern void Lcd_clear(void);            //画面消去
extern void Lcd_cmd(uchar);             //コマンド書き込み
extern void Lcd_cursol(uchar);          //カーソル位置のセット
extern void Lcd_putc(char);             //1文字表示
extern void Lcd_str(char *);            //文字列表示
extern void Lcd_setCG(uchar,char *);    //オリジナルキャラクタ登録

extern volatile uchar IntI2c;           //割り込みフラグのコピー

 SDA、SCLのピン位置は決められていて移動できないのでピンアサインは省かれました。
 各ピンの細かい動作は規定しなくてもよくなりました。
 割り込みフラグを即クリアしたいので割り込みフラグのコピーを用意しています。


ライブラリールーチン

/////////////////////////////////////////////////////
//   i2lcllib.C                                    //
//   IIC 液晶表示器 AQM0802A-RN-GBW ライブラリー   //
//   H26/01/19   MikroC Pro for PIC Ver 6.0.0      //
/////////////////////////////////////////////////////
#include "i2lcdt2.h"

//////// I2C初期化
// メインクロック4MHz: ボーレート100KHz
// SSPADD = X , 0.1 = 4/(4 * (X + 1)) , X = 9
void I2init(void){
    SSPCON1 = 0x8;      //マスターモード
    SSPCON2 = 0;        //リセット
    SSPSTAT = 0;
    SSP1ADD = 0x9;      //ボーレート100KHz
    SSPCON1.SSPEN = 1;  //MSSP使用
    PIE1.SSP1IE = 1;    //MSSP割り込み許可
    INTCON.PEIE = 1;    //周辺割り込み許可
    INTCON.GIE = 1;     //全割り込み許可
    IntI2c = 0;         //割り込みフラグのコピーをクリア
}

//////// スタートコンディション
void I2startCon(void){
    SSP1CON2.SEN = 1;       //スタート
    while(IntI2c == 0);     //終了待ち
    IntI2c = 0;             //割り込みフラグクリア
}

//////// スタートコンディション再送
void I2startRep(void){
    SSP1CON2.RSEN = 1;      //再スタート
    while(IntI2c == 0);     //終了待ち
    IntI2c = 0;             //割り込みフラグクリア
}

//////// 1バイト送信
// 引数:送信データ 戻り値 0:ACK,1:NACK
uchar I2write(uchar _data){
    while(SSP1STAT.BF);         //BUSY
    SSP1BUF = _data;            //データ送信
    while(IntI2c == 0);         //送信完了待ち
    IntI2c = 0;                 //割り込みフラグクリア
    return SSP1CON2.ACKSTAT;
}

//////// 1バイト受信
// 引数 0:ACKを返す、1:NACKを返す
// 戻り値 受信データ
uchar I2read(uchar ACK){
    uchar tmp;    

    SSP1CON2.ACKDT = ACK;
    SSP1CON2.RCEN = 1;          //受信許可
    while(IntI2c == 0);         //受信完了待ち
    tmp = SSPBUF;               //読み取り
    IntI2c = 0;                 //割り込みフラグクリア
    SSP1CON2.ACKEN = 1;         //ACKDT送信
    while(IntI2c == 0);         //ACK送信完了待ち
    IntI2c = 0;                 //割り込みフラグクリア
    return tmp;
}

//////// ストップシーケンス
void I2stop(void){
    SSP1CON2.PEN = 1;       //ストップ出力
    while(IntI2c == 0);     //終了待ち
    IntI2c = 0;             //割り込みフラグクリア
}

/////////   コマンド書き込み
//          引数:書き込みコマンド
//          戻り:0=成功、1=失敗
uchar Lcd_cmd(uchar cmd){
    I2startCon();                       //IIC 開始
    if(I2write(S_ADDR)) goto err;       //スレーブアドレス書き込み
    if(I2write(0b10000000)) goto err;   //コントロールバイト
    if(I2write(cmd)) goto err;          //コマンド書込
    I2stop();                           //IIC 終了
    Delay_us(26);
    return 0;
err:                                    //エラー
    I2stop();
    return 1;
}

/////////   表示位置
//          引数:表示位置(1行目0x0〜0x7、2行目0x40〜0x47)
void Lcd_cursol(uchar ddram_addr){
    uchar dummy;
    ddram_addr |= 0x80;
    dummy = Lcd_cmd(ddram_addr);
}

/////////   表示消去
void Lcd_clear(void){
    Lcd_cmd(0x01);
    Delay_ms(1);
    Delay_us(80);
}

/////////   液晶の初期化
void Lcd_init(){
     I2init() ;       //ポート初期化
     Delay_ms(40);      //                  電源ON後40ms待つ
     Lcd_cmd(0x38);     // function set     8ビットモード2行
     Lcd_cmd(0x39);     // function set     拡張コマンドを有効にする
     Lcd_cmd(0x14);     // バイアスの       選択と内部発振周波数の調整
     Lcd_cmd(0x70);     // Contrast set     コントラスト調整データ(下位4ビット)
     Lcd_cmd(0x56);     // Contrast set     昇圧回路有効、コントラスト調整データ(上位2ビット)
     Lcd_cmd(0x6C);     // Follower control フォロア回路をONし増幅率の調整を行う
     Delay_ms(200);     //                  電力が安定するまで待つ
     Lcd_cmd(0x38);     // function set     拡張コマンドを無効にする
     Lcd_cmd(0x0c);     // display control  画面表示はON・カーソル表示はOFF
     Lcd_cmd(0x01);     // Clear Display    画面消去
     Delay_ms(1);
     Delay_us(80);
}

/////////   1文字表示
void Lcd_putc(char c){
    uchar dummy;
    I2startCon();                   //スタートコンディション
    if(I2write(S_ADDR))goto err;    //スレーブアドレス
    dummy = I2write(0b11000000);    //コントロールバイト
    dummy = I2write(c);             //文字書き込み
err:
    I2stop();                       //ストップコンディション
    Delay_us(26);
}

/////////    文字列の表示
void Lcd_str(char *s){
    uchar dummy;
    I2startCon();                   //スタートコンディション
    if(I2write(S_ADDR))goto err;    //スレーブアドレス
    dummy = I2write(0b01000000);    //コントロールバイト
    while(*s){
        dummy = I2write(*s);
        *s++;
    }
err:
    I2stop();
    Delay_us(26);
}

/////////   自作キャラクタの登録
//          引数:登録アドレス(0〜5)、登録データへのポインタ
void Lcd_setCG(uchar addr,char *dp){
    uchar dummy, i;
    
    I2startCon();                   //IIC 開始
    if(I2write(S_ADDR))goto err;    //スレーブアドレス書き込み
    dummy = I2write(0b10000000);    //コントロールバイト(コマンド書き込み)
    addr = addr << 3;
    dummy = I2write(0x40 | addr);   //書き込み位置
    dummy = I2write(0b01000000);    //コントロールバイト(データ書き込み)
    for(i=0;i<7;i++){               //キャラクタデータを送る
        I2write(*dp);
        dp++;
    }
err:
    I2stop();
    Delay_us(26);
}

 液晶のライブラリーとしては同じですが、I2Cの基本関数が異なります。
 MikroCのライブラリーは使わず、直接レジスタを操作しています。
 初期化関数で割り込み関係の記述があります。
 メモリ等でアドレスを指定してデータを読むときはスタートコンディションを送ってアドレスを書き込み、再度スタート コンディションを送って読み込みます。
 この為、「スタートコンディションの再送」という関数が用意されています。
 液晶表示器では受信関数は使用されません。
 したがって動作の確認は出来ませんがPIC18Fで24C256の読み書きに使用した関数を移植したものですので 問題は無いと思います。
 詳細は別ページ「4CH温度記録計」のソースを見てください。
 上記は4MHz、ボーレート100KHzの場合ですが、32MHz、400KHzの時は初期化関数を以下のように 変更します。

//////// I2C初期化
// メインクロック32MHz: ボーレート400KHz
// SSPADD = X , 0.4 = 32/(4 * (X + 1)) , X = 19 (0x13)
void I2init(void){
    SSPCON1 = 0x8;      //マスターモード
    SSPCON2 = 0;        //リセット
    SSPSTAT = 0;
    SSP1ADD = 0x13;     //ボーレート400KHz
    SSPCON1.SSPEN = 1;  //MSSP使用
    PIE1.SSP1IE = 1;    //MSSP割り込み許可
    INTCON.PEIE = 1;    //周辺割り込み許可
    INTCON.GIE = 1;     //全割り込み許可
    IntI2c = 0;         //割り込みフラグのコピーをクリア
}

メインルーチン

///////////////////////////////////////////////////
//   i2test1.C                                   //
//   IIC 液晶表示器 AQM0802A-RN-GBW 表示テスト   //
//   H26/12/19   MikroC Pro for PIC Ver 6.0.0    //
///////////////////////////////////////////////////
#include "i2lcdt2.h"

// CLOCK 4MHz
// Oscillator INTOSC, Watchdog OFF, Power-up Timer ON,
// MCLR Pin ON, Code Protection OFF, Data Protection OFF,
// Brown-out Reset ON, Clock Out OFF, Int/Ext Switchover OFF,
// Fail-safe Clock Monitor OFF, F-Memory Self W-protection OFF, Pll OFF
// Stack Of/Uf Reset ON, Brown-out Reset 1.9V, Debug OFF, LVP OFF

volatile uchar IntI2c;
const char CG_DATA1[]={0x15,0x0a,0x15,0x0a,0x15,0x0a,0x15}; //市松模様
char CG_DATA2[] = {0x1f,0,0x1f,0,0x1f,0,0x1f};   //横縞
const char *RomData = "ROM**";
char *RamData = "RAM!!";
const char C0 = '0';
char C1 = '1';

void main(){
    OSCCON = 0x68;          //内部 4MHz
    OPTION_REG = 0xc0;      //タイマー0関連ダミー
    ANSELA = 0;             //ALL DIGITAL
    TRISA = 0xe;            //ポート入出力設定
    WPUA = 0;               //PULL UP OFF
    Delay_ms(100);          //電源の安定を待つ
    Lcd_init();             //液晶表示器初期化
    Lcd_setCG(0,CG_DATA1);  //市松模様を登録
    Lcd_setCG(1,CG_DATA2);  //横縞を登録
    Lcd_cursol(0);          //表示位置1行目先頭
    Lcd_str(RomData);       //ROM領域の文字列を表示
    Lcd_cursol(0x06);       //1行目5文字目
    Lcd_putc('0');          //CGRAMアドレス表示
    Lcd_putc(0);            //市松模様を表示
    Lcd_cursol(0x40);       //表示位置2行目先頭
    Lcd_str(RamData);       //RAM領域の文字列を表示
    Lcd_cursol(0x46);       //表示位置2行目5文字目
    Lcd_putc('1');          //CGRAMアドレス表示
    Lcd_putc(0x01);         //横縞を表示
    Delay_ms(1000);         //2秒表示
    Delay_ms(1000);
    Lcd_clear();            //画面を消去して
    Delay_ms(1000);         //2秒待つ
    Delay_ms(1000);
    Lcd_cursol(0);          //同じ表示をもう一回繰り返す
    Lcd_str("ROM**");
    Lcd_cursol(0x06);
    Lcd_putc(C0);
    Lcd_putc(0);
    Lcd_cursol(0x40);
    Lcd_str("RAM!!");
    Lcd_cursol(0x46);
    Lcd_putc(C1);
    Lcd_putc(0x01);
    asm SLEEP;
    asm NOP;
}

void interrupt(){       //MSSP割り込み
    PIR1.SSP1IF = 0;    //割り込みフラグクリア
    IntI2c = 1;         //コピーフラグセット
}

 メインルーチンはソフトI2Cと同じものですが、MSSP割り込みルーチンが追加されています。
 割り込みルーチンではフラグをクリアしてコピーをセットしています。
 上記のソースは4MHzのものですが、32MHzにする場合は8MHzをPLLで4倍にします。
  OSCCON = 0xf0; //内部 32MHz
 コンフィギュレーションでPLLをイネーブルにした場合
  OSCCON = 0x70; //内部 32MHz
 でも良いです。


プロジェクトの構成とビルド結果

プロジェクトの構成 ビルド結果


トップページ  「電子回路」のトップ