2014年7月1日火曜日

I2C小型液晶を動かす

最近、秋葉原のaitendoが閉店セールか何かで50%OFFセールをしています。なんか店舗を移転するそうですね。
そこで、16X2-SPLC792-I2CというI2C接続の液晶が売っていました。無論、液晶モジュール単体だけでは使い勝手が悪いので、変換基板セットで買いました。
それにしても、変換基板セットで税抜き375円。だいぶ安いです。3枚以上買おうとすると通常価格になるようなので、1枚当たりの価格が一気に跳ね上がるという"逆数割"ですが、まあ個人で使う分にはなかなかそんなに大量に買わないので問題ないでしょう。

 

買ってきたものがこんなかんじです。部品は全部自分で実装しますが、チップ部品も比較的大きめのものを採用してくれているので、配線はし易いと思います。 ただ、液晶の裏表は間違えないように気をつけてください。バックライトモジュールに上手くはまる方向を意識しながら組み立てれば大丈夫です。


組み上げるとこんなかんじになります。インターフェースにはピンヘッダを取り付けておきました。

ところで、この液晶モジュールにはSPLC792Aという液晶コントローラーが使われているようですが、どうも秋月で売っているI2C小型液晶AQM0802Aのコントローラーと互換性があるらしいです。実はこのAQM0802A、NTP時計を作る前に作ったプロトタイプで使っていたんですね。面白いことに、このaitendoの液晶変換基板のピンアサインまで秋月の液晶のピンアサインと同じになっています。どちらが先か知りませんが、互換性を意識して作ったんですかねw

というわけで、プロトタイプの基板に差し替えて使ってみましたが、上手く動きません…

I2Cスレーブアドレスが違うんじゃないかとか思ってデータシートを見たところ、コントローラーのピンを2つ分使って2bit分のアドレスを自由にカスタマイズできるとかいてありましたが、コントローラーのピンが表に出ているわけもなく、結局4通り手当たり次第にやってみることにしましたが、やはり動きません。

そしていろいろとコードを眺めていたが末にわかったのですが、一連のI2Cのシーケンスを送った後に27usのディレイを、コマンドの方には入れていたのですが、データの方には入れていませんでした。秋月の液晶のほうはそれで動いてくれていたんですが、それを入れている記事等が見つかったので、実際に入れてみました。

見事動きました。秋月の液晶のほうが、コントローラーチップの処理速度が速いってことなんですかね。まあ、なんて言うか、規格外の動かしかたを今までしていたようです。データシートをよく読んでなかったからこんなことろで苦労してしまったんですね(汗

結果、プログラムはこんなかんじになっています。

#include <p24FJ64GA002.h>
#include <stdint.h>
#include "i2c_lcd.h"
#define FCY 16000000UL  //32MHz/2
#include <libpic30.h>

#define LCD_SLAVE_ADDR  (0x3E << 1)

void i2cl_WaitForBusy(void)
{
    while((I2C1CON & 0b0000000000011111) | I2C1STATbits.TRSTAT);
}

void i2cl_Start()
{
    i2cl_WaitForBusy();
    I2C1CONbits.SEN = 1;
}

void i2cl_Stop()
{
    i2cl_WaitForBusy();
    I2C1CONbits.PEN = 1;
}

uint8_t i2cl_Write(uint8_t data)
{
    i2cl_WaitForBusy();
    I2C1TRN = data;
    i2cl_WaitForBusy();

    return I2C1STATbits.ACKSTAT;
}


void i2cl_SendCmd(uint8_t cmd)
{
    i2cl_Start();
    i2cl_Write(LCD_SLAVE_ADDR);
    i2cl_Write(0x00);
    i2cl_Write(cmd);
    i2cl_Stop();
    __delay_us(27);
}

void i2cl_SendData(uint8_t data)
{
    i2cl_Start();
    i2cl_Write(LCD_SLAVE_ADDR);
    i2cl_Write(0x40);
    i2cl_Write(data);
    i2cl_Stop();
    __delay_us(27);
}

void i2c_Init()
{
    TRISB |= 0x0300;
    I2C1BRG = 0x0013;
    I2C1CON = 0x8000;
}

void i2cl_Init()
{
    i2c_Init();
    __delay_ms(40);
    i2cl_SendCmd(0x38);
    i2cl_SendCmd(0x39);
    i2cl_SendCmd(0x14);
    i2cl_SendCmd(0x70);
    i2cl_SendCmd(0x56);
    i2cl_SendCmd(0x6C);
    i2cl_SendCmd(0x38);
    i2cl_SendCmd(0x0C);
    i2cl_SendCmd(0x01);
    __delay_ms(1);
}

void i2cl_Write1stLine(char *text)
{
    i2cl_SendCmd(0x03);
    while(*text)
        i2cl_SendData(*text++);
}

void i2cl_Write2ndLine(char *text)
{
    i2cl_SendCmd(0xC0);
    while(*text)
        i2cl_SendData(*text++);
}

あ、プロセッサはPIC24FJ64GA002です。NTP時計は表面実装にしたかったので004を採用しましたが、この2つはアーキテクチャが非常に似ているのでかなりプログラムが移植しやすいです。

これで、見事ソフトウェアの変更なしで液晶を差し替えるだけで動いてくれるようになりました。



ソフトウェアの変更なしで差し替えるだけで動くってことはI2Cスレーブアドレスも同じなんですよね…。なんていうか、せっかくなら同じI2Cバスに並べて動かしたかったと思うと、うーん、違ってもよかったような…。

1 件のコメント:

  1. はじめまして、nomatanと申します。そのLCDユニットに、ジャンパとかDIPスイッチとかでアドレスを設定するとかいう機能があるといいですね。または、隠しコマンドで変更できるとか?
    市販のデバイスって、こういう痒いところに手が届かないのが多いですよね(^^;
    それなら、自分で作ってしまえば?ってことで・・・私の場合は4桁7セグ表示ユニットですが、セカンドディスプレイとして同じI2Cバス上に接続できることを狙って、アドレスを書き換えられるように配慮してみました(^^)
    http://www1.techno-brain.com/?eid=8

    返信削除