概要

PIC18F46K22のI2Cモジュール1にI2Cキャラクタ液晶モジュール(8桁*2行)AQM0802A-RN-GBWを接続し文字の表示とコントラストの調整を実施するサンプルである。
電源はUSBから供給するので5Vである。液晶モジュールは標準電圧が3.3Vなので他の3.3V系のI2Cデバイスも接続できるように3.3V電源回路とレベル変換回路を設けた。液晶モジュール自体の最大定格は5V以上あるため、5Vを直接接続できるのではないかと思うが、試していない。
コントラスト調整は、プログラム制御できる。
本サンプルではコントラスト20~40を自動的に変更するようにしている。
秋月電子 PIC18F46K22使用 マイコンボードをベースとし半田付けされている水晶20MHzをH8/3048ボードの16MHzと交換し64MHzで動作可能とした。このボードはICSP端子を備えておりPICKIT 3で書き込みができ、電源はミニUSBで供給可能である。またユニバーサル基板になっているので簡単に回路を追加することができる。
ちなみに水晶が20MHzの場合は、動作が遅くなるだけである。
回路は次のとおりである。
cir.svg
回路図(PDF) 回路図(DXF)

プログラムの説明

ソースファイル

以下のファイルで構成されている
lcd1c.asm ・・・ メインプログラムとLCD制御の関数

ソースファイルのダウンロード lcd1c.zip

/*
 * I2C接続液晶 AQUM0802A-RN-GBWの表示とコントラスト調整サンプル Version 1.00
 * File:        lcd1c.c
 * Target:      PIC18F46K22 64MHz
 * コンパイラ:   Microchip MPLAB XC8 C Compiler V1.20
 * 書き込み:     PICKit 3
 * リリース:     2014/01/25 14:00
 * 表示例(2行目の26は現在のコントラスト値を表す サンプルでは20~40まで周期的に変化する)
 *   AQUM0802A
 *   CONT   26
 * 使用端子
 *   SCK1(RC3),SDA1(RC4)
*/

#include <stdio.h>
#include <stdlib.h>
#include <p18f46k22.h>
#include <plib\delays.h>
#include <plib\i2c.h>

#pragma config  FOSC = HSHP,PRICLKEN=ON,PLLCFG=ON,WDTEN=OFF,LVP=OFF

#define LED0 PORTBbits.RB5
#define LCD_SADS 0x7c   //  液晶のスレーブアドレス
#define LCD_RSDATA  0x40
#define LCD_RSCMD  0x0
#define LCD_C01  0x80
#define LCD_C00  0x80
#define lcd_putc(c) lcd_data(c) // LCDへ1文字出力

signed char i2c_write(unsigned char d); // i2cへ1byte送信
void lcd_cmd(unsigned char cmd); //  LCDへコマンドを1byte送信
void lcd_clear(void); //  LCDをクリア
void lcd_init(void); //  LCD初期化
void lcd_cont(unsigned char c); //  LCDコントラスト変更(0?63)
void lcd_data(unsigned char c); //  LCDへデータを1byte送信
void lcd_ddram(unsigned char ads); //  LCDの表示アドレスを設定
void lcd_puts(const char* buf); //  LCDに文字列を表示

void main(void) {
    char buf[4];
    ANSELCbits.ANSC3=0;
    ANSELCbits.ANSC4=0;

    Delay10KTCYx( 64);  //  40ms/(64MHz/4)=  640000

    OpenI2C(MASTER,SLEW_ON);    // マスター
    SSPADD=39;  //  400kHz

    lcd_init();
    lcd_puts("AQM0802A\nCont");

    unsigned char c;    //  コントラスト
    for(;;){
        for(c=20;c<40;c++){
            sprintf(buf,"%.2i",(int)c);
            lcd_ddram(6);
            lcd_puts(buf);
            lcd_cont(c);
            Delay10KTCYx( 255);
        }
        for(;20<=c;c--){
            sprintf(buf,"%.2i",(int)c);
            lcd_ddram(6);
            lcd_puts(buf);
            lcd_cont(c);
            Delay10KTCYx( 255);
        }
    }
}

// i2cへ1byte送信

signed char i2c_write(unsigned char d){
    signed char ret;
    ret=WriteI2C(d);
    IdleI2C();
    return ret;
}

//  LCDへコマンドを1byte送信

void lcd_cmd(unsigned char cmd){
    SSPCON1bits.WCOL=0;
    IdleI2C();
    StartI2C();
    while(SSPCON2bits.SEN);
    i2c_write( LCD_SADS);
    i2c_write( LCD_RSCMD | LCD_C01 );
    i2c_write(cmd);
    StopI2C();
    while(SSPCON2bits.PEN);
}

//  LCDをクリア

void lcd_clear(void){
    lcd_cmd(0x01);    //  Clear Display
    Delay1KTCYx( 17);  //  1.06ms/(64MHz/4)=  17000
}

//  LCD初期化

void lcd_init(void){
    lcd_cmd(0x38);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x39);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x14);    //  Internal OSC frequency
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x73);    //  Contrast set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x56);    //  Power/ICON/Contrast control
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x6c);    //  Follower control
    Delay10KTCYx( 160);  //  100ms/(64MHz/4)=  1600000
    Delay10KTCYx( 160);  //  100ms/(64MHz/4)=  1600000
    lcd_cmd(0x38);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x0c);    //  Display On/Off
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_clear();
}

//  LCDコントラスト変更(0?63)

void lcd_cont(unsigned char c){
    lcd_cmd(0x39);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x70 | c);    //  Contrast set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x54 | (c>>4));    //  Power/ICON/Contrast control
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430

}

//  LCDへデータを1byte送信

void lcd_data(unsigned char c){
    SSPCON1bits.WCOL=0;
    IdleI2C();
    StartI2C();
    while(SSPCON2bits.SEN);
    i2c_write(LCD_SADS);
    i2c_write( LCD_RSDATA | (LCD_C01) );
    i2c_write(c);
    StopI2C();
    while(SSPCON2bits.PEN);
}

//  LCDの表示アドレスを設定

void lcd_ddram(unsigned char ads){
    lcd_cmd(0xc0 | ads);
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
}

//  LCDに文字列を表示

void lcd_puts(const char* buf){
    char* p=buf;
    while(*p){
        if(*p=='\n')
            lcd_ddram(0x40);   //2行目
        else{
           lcd_data(*p);
            Delay10TCYx( 43);  //  26.3μs*(64MHz/4)=  430
        }
        ++p;
    }
}