PSoCで「低電圧I2C液晶モジュール(3.3V I2C接続)SB1602B」を利用する

_DSC4009.JPG
ストロベリーリナックスでキャラクタ液晶モジュール「低電圧I2C液晶モジュール(3.3V I2C接続)(型番:SB1602B)」(700円)が販売されていた。

CPUとたったの2線で接続でき、3.3Vのみならず5Vでも利用可能、1mA以下と低消費電力、2行16列+9個のアイコンを表示可能という点が特徴。

バックライトなし、むき出しの基板で外部からの衝撃に弱そうな外見、固定用のねじ穴が用意されていないという点が欠点。

  (2009/06/06 13:30:28, NIKON D200, 絞り優先, F11.7, 1/60sec, 0.0, ISO500, 60mm)

_DSC4017.JPG
10ピンの接続用ピンが用意されている。

基板右側やピンにはバックライトLED用の「A」や「K」がある。しかし液晶の下に光を反射するプラスチックが配置されていないためここにLEDを実装してもバックライトにはならない。

  (2009/06/06 13:35:44, NIKON D200, 絞り優先, F22.6, 1/60sec, 0.0, ISO500, 60mm)

_DSC4016.JPG
このモジュールはコントローラーチップ「ST7032i」を採用した液晶「DSG101246C」と、それを固定するための基板からなる。

コンデンサは基板に実装されているため、必要な外付け部品はI2C用のプルアップ抵抗2つだけだ。

  (2009/06/06 13:32:06, NIKON D200, 絞り優先, F22.6, 1/60sec, 0.0, ISO500, 60mm)

_DSC4019.JPG
用意されている接続用のピンヘッダーはモジュールをケースへ固定することを考慮してなのか、リードが非常に短い。そのため注意してハンダ付けする。まずはどちらか片方を仮付け。

  (2009/06/06 13:39:01, NIKON D200, 絞り優先, F22.6, 1/60sec, 0.0, ISO500, 60mm)

_DSC4021.JPG
ピンヘッダーがきちんと垂直になっていることを確認したら全ピンをハンダ付けする。

  (2009/06/06 13:41:23, NIKON D200, 絞り優先, F22.6, 1/60sec, 0.0, ISO500, 60mm)

lcd_i2c.gif
今回このI2C液晶をテストするための回路図。
プルアップ抵抗を入れた2線をPSoCと接続するだけでいい。

_DSC4023.JPG
実際にPSoCと接続した。この液晶モジュールはそのままブレッドボードに挿して利用できるのでテストに便利。

抜き差ししていると液晶のガラスに無理な力をかけすぎて液晶を割ってしまいそうだが。。。

  (2009/06/07 14:51:25, NIKON D200, 絞り優先, F90.5, 1/60sec, 0.0, ISO500, 60mm)

_DSC4029.JPG
これで液晶モジュールに文字やアイコンを表示できた。

ソースコードは以下のようにした。
PSoC Designer 5を利用。I2C通信用のユーザーモジュール「I2Cm」を使うことで簡単にこの液晶モジュールに文字を出力で来た。

  (2009/06/07 14:55:41, NIKON D200, 絞り優先, F90.5, 1/60sec, 0.0, ISO500, 60mm)



//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------

#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules

#define LCD_I2C_ADDR 0x3E

#include "stdlib.h"
#include "string.h"

//
// LCDへデータを流す(プラーベート関数)
//
BYTE LCD_I2C_WriteCBytes(const BYTE* pcbData,int nLen)
{
return I2Cm_bWriteCBytes(LCD_I2C_ADDR,pcbData,nLen,I2Cm_CompleteXfer);
}

//
// LCDへデータを流す(プラーベート関数)
//
BYTE LCD_I2C_WriteBytes(BYTE* pcbData,int nLen)
{
return I2Cm_bWriteBytes(LCD_I2C_ADDR,pcbData,nLen,I2Cm_CompleteXfer);
}

//
// LCDへコマンドを送信(プラーベート関数)
//
BYTE LCD_I2C_WriteCmd(BYTE cbCmd)
{
I2Cm_fSendStart(LCD_I2C_ADDR,I2Cm_WRITE);
I2Cm_fWrite(0x00);
I2Cm_fWrite(cbCmd);
I2Cm_SendStop();

return (BYTE)1;
}


//
// LCDへデータを送信(プラーベート関数)
//
BYTE LCD_I2C_WriteDataCBytes(const BYTE* pcbData,int nLen)
{
int i;

I2Cm_fSendStart(LCD_I2C_ADDR,I2Cm_WRITE);
I2Cm_fWrite(0x40);
for(i = 0; i < nLen; i++)
{
I2Cm_fWrite(pcbData[i]);
}
I2Cm_SendStop();

return (BYTE)nLen;
}


//
// LCDへデータを送信(プラーベート関数)
//
BYTE LCD_I2C_WriteDataBytes(BYTE* pcbData,int nLen)
{
int i;

I2Cm_fSendStart(LCD_I2C_ADDR,I2Cm_WRITE);
I2Cm_fWrite(0x40);
for(i = 0; i < nLen; i++)
{
I2Cm_fWrite(pcbData[i]);
}
I2Cm_SendStop();

return (BYTE)nLen;
}


//
// LCDへデータを1バイト送信(プラーベート関数)
//
BYTE LCD_I2C_WriteDataByte(BYTE cbData)
{
return LCD_I2C_WriteDataBytes(&cbData,1);
}


//
// LCDへアイコンコマンドを送信(プライベート関数)
//
BYTE LCD_I2C_WriteIconCmd(int nIconAddr,BYTE cbData)
{
LCD_I2C_WriteCmd(0x39); //ファンクションセット(Instruction table select)
LCD_I2C_WriteCmd(0x40 + nIconAddr); //アイコンアドレス

return LCD_I2C_WriteDataByte(cbData); //データセット
}

//////////////////////////////
// アイコンインデックス
//

//0x00~0x0Fまでの値はLCD_I2C_WriteIconCmdに渡すアイコンのアドレスとしてそのまま利用可能
#define LCD_I2C_ICON_ANT 0x00 //0x10(←このコメント値はLCD_I2C_WriteIconCmdで表示時に渡すデータ値)
#define LCD_I2C_ICON_TEL 0x02 //0x10
#define LCD_I2C_ICON_VOL 0x04 //0x10
#define LCD_I2C_ICON_IN 0x06 //0x10
#define LCD_I2C_ICON_UPDOWN 0x07 //0x10(上)/0x08(下)
#define LCD_I2C_ICON_LOCK 0x09 //0x10
#define LCD_I2C_ICON_MUTE 0x0B //0x10
#define LCD_I2C_ICON_BATT 0x0D //0x10(最小側)、0x08(真ん中)、0x04(最大側)、0x02(枠)
#define LCD_I2C_ICON_SLEEP 0x0F //0x10

//(アイコン消去用インデックス)
#define LCD_I2C_ICON_ANT_CLEAR 0x10 //0x10(←このコメント値はLCD_I2C_WriteIconCmdで表示時に渡すデータ値)
#define LCD_I2C_ICON_TEL_CLEAR 0x12 //0x10
#define LCD_I2C_ICON_VOL_CLEAR 0x14 //0x10
#define LCD_I2C_ICON_IN_CLEAR 0x16 //0x10
#define LCD_I2C_ICON_UPDOWN_CLEAR 0x17 //0x10(上)/0x08(下)
#define LCD_I2C_ICON_LOCK_CLEAR 0x19 //0x10
#define LCD_I2C_ICON_MUTE_CLEAR 0x1B //0x10
#define LCD_I2C_ICON_BATT_CLEAR 0x1D //0x10(最小側)、0x08(真ん中)、0x04(最大側)、0x02(枠)
#define LCD_I2C_ICON_SLEEP_CLEAR 0x1F //0x10

//(アイコン段階表示用インデックス)
#define LCD_I2C_ICON_UPDOWN_ALL 0x20 //(0x10 | 0x08)
#define LCD_I2C_ICON_UPDOWN_UP 0x21 //0x10
#define LCD_I2C_ICON_UPDOWN_DOWN 0x22 //0x08
#define LCD_I2C_ICON_BATT_MAX 0x23 //(0x02 | 0x10 | 0x08 | 0x04)
#define LCD_I2C_ICON_BATT_MID 0x24 //(0x02 | 0x10 | 0x08)
#define LCD_I2C_ICON_BATT_LOW 0x25 //(0x02 | 0x10)
#define LCD_I2C_ICON_BATT_NONE 0x26 //(0x02)

//
// LCDのアイコンを表示
//
BYTE LCD_I2C_ShowIcon(int nIconIndex)
{
BYTE cbBuff;

//「バッテリ」と「アップダウン」のアイコンは複数パターンある。
//これらのアイコンが指定された場合は全表示する
//(段階表示用のインデックスが指定された場合は段階表示する)
if(nIconIndex == LCD_I2C_ICON_BATT)
nIconIndex = LCD_I2C_ICON_BATT_MAX;
else if(nIconIndex == LCD_I2C_ICON_UPDOWN)
nIconIndex = LCD_I2C_ICON_UPDOWN_ALL;

//インデックスが0x10以下の場合はインデックスそのものをアドレスとして、データに0x10を渡して表示
if(nIconIndex < 0x10)
return LCD_I2C_WriteIconCmd(nIconIndex,0x10); //アイコン表示

//インデックスが0x20以下の場合はインデックス-0x10をアドレスとして、データに0x00を渡して消去
if(nIconIndex < 0x20)
return LCD_I2C_WriteIconCmd(nIconIndex - 0x10,0x00); //アイコン消去

//段階表示処理
cbBuff = 0;
switch(nIconIndex)
{
case LCD_I2C_ICON_UPDOWN_ALL:
return LCD_I2C_WriteIconCmd(LCD_I2C_ICON_UPDOWN,0x10 | 0x08);

case LCD_I2C_ICON_UPDOWN_UP:
return LCD_I2C_WriteIconCmd(LCD_I2C_ICON_UPDOWN,0x10);

case LCD_I2C_ICON_UPDOWN_DOWN:
return LCD_I2C_WriteIconCmd(LCD_I2C_ICON_UPDOWN,0x08);

case LCD_I2C_ICON_BATT_MAX:
cbBuff |= 0x04;
case LCD_I2C_ICON_BATT_MID:
cbBuff |= 0x08;
case LCD_I2C_ICON_BATT_LOW:
cbBuff |= 0x10;
case LCD_I2C_ICON_BATT_NONE:
cbBuff |= 0x02;
return LCD_I2C_WriteIconCmd(LCD_I2C_ICON_BATT,cbBuff);
}

return 0;
}


//
// コントラスト設定(値:0~15)
//
BYTE LCD_I2C_SetContrast(int nValue)
{
if(nValue >= 0x10)
nValue = 0x0F;

return LCD_I2C_WriteCmd(0x70 | nValue); //コントラスト
}

//
// 画面クリア
//
//アイコンはクリアされない点に注意
//
BYTE LCD_I2C_Clear(void)
{
return LCD_I2C_WriteCmd(0x01); //クリア
}


//
// LCDの初期化
//
void LCD_I2C_Init(int nContrast)
{
LCD_I2C_WriteCmd(0x38); //ファンクションセット

LCD_I2C_WriteCmd(0x39); //ファンクションセット(Instruction table select)

LCD_I2C_WriteCmd(0x14); //内蔵OSC周波数(1/5bias freq=192Hz@5V)

LCD_I2C_SetContrast(nContrast); //コントラスト(5V電源なら2で十分?。3.3Vなら調整すること)

LCD_I2C_WriteCmd(0x5E); //電源・アイコン・コントラスト制御(アイコン有効、ブースト回路有効、コントラスト=2)

LCD_I2C_WriteCmd(0x6A); //Followerコントロール(Folower回路有効、増幅率=2)

LCD_I2C_WriteCmd(0x0C); //ディスプレイON(表示有効、カーソル無効、カーソル位置無効)

LCD_I2C_Clear(); //クリア

LCD_I2C_WriteCmd(0x06); //エントリーモードセット(カーソル移動方向=右)
}


//
// カーソル移動
//
//nYは0/1以外は無視
//
BYTE LCD_I2C_MoveCursor(BYTE nX,BYTE nY)
{
BYTE cbPos;

cbPos = (nY == 0) ? 0x00 : 0x40;
cbPos += nX;

return LCD_I2C_WriteCmd(0x80 | cbPos);
}


//
// カーソル移動
//
//※x,y指定を間違えやすいのでLCD_I2C_MoveCursorの利用を推奨
//
void LCD_I2C_Position(BYTE bRow,BYTE bCol)
{
LCD_I2C_MoveCursor(bCol,bRow);
}

//
// RAM文字列の出力
//
void LCD_I2C_PrString(char* sRamString)
{
LCD_I2C_WriteDataBytes(sRamString,strlen(sRamString));
}

//
// ROM文字列の出力
//
void LCD_I2C_PrCString(const char* sRomString)
{
LCD_I2C_WriteDataCBytes((const BYTE*)sRomString,cstrlen(sRomString));
}

//
// 整数の出力
//
//左詰めで数値を単純出力
//「100」->「2」という順に出力すると表示が「200」になる
//(「100」を出力したときの「00」が消去されない点に注意)
//
void LCD_I2C_PrInt(int nData)
{
char pBuff[6];
itoa(pBuff,nData,10);
LCD_I2C_PrString(pBuff);
}

//
// 桁数を指定した整数の出力
//
//右詰で数値を出力
//nLenが示す桁数になるように左側に空白を配置する
//nLenがnDataに対して小さい場合は指定された桁数に収まらない点に注意
//
void LCD_I2C_PrIntWithAlign(int nData,int nLen)
{
int nDataLen;
char pBuff[6];
itoa(pBuff,nData,10);

nDataLen = strlen(pBuff);
for(; nDataLen < nLen; nDataLen++)
LCD_I2C_PrCString(" ");

LCD_I2C_PrString(pBuff);
}


//
// 16進数(2桁)の出力
//
//「00」~「ff」として出力
//
void LCD_PrHexByte(BYTE bValue)
{
BYTE pszBuff[3];
if(bValue < 0x10)
LCD_I2C_PrCString("0");
itoa(pszBuff,bValue,16);
LCD_I2C_PrString(pszBuff);
}

//
// 16進数値(4桁)の出力
//
//「0000」~「ffff」として出力
//
void LCD_PrHexInt(unsigned int iValue)
{
BYTE pszBuff[5];

if(iValue < 0x10)
LCD_I2C_PrCString("000");
else if(iValue < 0x100)
LCD_I2C_PrCString("00");
else if(iValue < 0x1000)
LCD_I2C_PrCString("0");

itoa(pszBuff,iValue,16);
LCD_I2C_PrString(pszBuff);
}

//適当にウエイト(0.5sec程度?@CPU3MHz(=24MHz/8))
void wait1000()
{
int i;
int j;
for(i = 0; i < 50; i++)
{
for(j = 0; j < 1000; j++)
{
}
}
}

void main()
{
int i;

I2Cm_Start();

LCD_I2C_Init(2);

LCD_I2C_PrCString("abcdefghij");

LCD_I2C_Clear();

LCD_I2C_MoveCursor(0,1);

LCD_I2C_PrCString("2Lines");


i = 0;
while(1)
{
// if(i >= 0x10)
// i = 0;
// LCD_I2C_SetContrast(i);
i++;

LCD_I2C_MoveCursor(3,0);
LCD_I2C_PrIntWithAlign(i,4);
wait1000();

if(i % 2)
LCD_I2C_ShowIcon(LCD_I2C_ICON_MUTE);
else
LCD_I2C_ShowIcon(LCD_I2C_ICON_MUTE_CLEAR);

if(i % 3)
LCD_I2C_ShowIcon(LCD_I2C_ICON_LOCK);
else
LCD_I2C_ShowIcon(LCD_I2C_ICON_LOCK_CLEAR);

switch(i % 5)
{
case 0:
LCD_I2C_ShowIcon(LCD_I2C_ICON_BATT_NONE);
break;

case 1:
LCD_I2C_ShowIcon(LCD_I2C_ICON_BATT_LOW);
break;

case 2:
LCD_I2C_ShowIcon(LCD_I2C_ICON_BATT_MID);
break;

case 3:
LCD_I2C_ShowIcon(LCD_I2C_ICON_BATT_MAX);
break;

case 4:
LCD_I2C_ShowIcon(LCD_I2C_ICON_BATT_CLEAR);
break;
}
}
}


カテゴリー「電子工作」 のエントリー