SHARP製HR-TFTモノクロメモリ液晶ダイレクトドライブのデモプログラム。 ライブラリの説明: 秋月電子などで販売されているSHARP製HR-TFTモノクロメモリ液晶を、直接駆動するためのライブラリです。 図形、文字列の描画が可能です。 日本語のフォントも内包していますが、FlashサイズやRAMサイズが小さいものだと扱いきれないかもしれません。 既存のライブラリとは違い、貴重なSPIポートを占拠しません。DigitalOut端子3本でSPIモドキを実現しています。

Dependencies:   SH_MLCD_J mbed

シャープ製メモリ液晶直接駆動用ライブラリ

実験時全景

秋月電子などで販売されている、シャープ製のモノクロメモリ液晶を
直接駆動させるためのライブラリとデモプログラムです。

図形や文字列を比較的簡単に表示させることが可能です。 また、メモリに余裕があれば日本語(全角文字)も描画可能です。

文字描画のアルゴリズムは、こちらのページで公開されていた
日本語ビットマップフォント表示アルゴリズムを改変して使用しています。
松浦光洋様、素晴らしいアルゴリズムを公開していただきありがとうございます。
現在ソースコードの公開は停止されている模様です。

また、ビットマプフォントにはM+ BITMAP FONTSで公開されている
Mplus-gothic-medium-R-normal 12pxを使用しています。

本体に搭載されているメモリ(RAM)のサイズをご確認ください!

このライブラリでは、ライブラリを通して描かれた全画素の情報ををchar型の一次元配列として記憶します。
故に、小さなRAMしか搭載していないものではOutOfMemoryになり、うまく動作しません

内部画素記憶配列のサイズは、((表示幅[px] / 8) * 表示高さ[px])[byte]です。
表示幅400px、表示高さ240pxの場合は 12Kbyte(12,000byte) の領域を要します。
表示幅128px、表示高さ128pxの場合は 2Kbyte(2,048byte)

文字列を扱う場合はさらにメモリ使用量が増えるので、表示幅400px、表示高さ240pxで使用する場合は
参考値として16KB以上のメモリ(RAM)を搭載した製品でお使いください

mbed LPC1114FN28ではもちろんのことながら動作しませんでした・・・
青mbedでも場合によってはちょっと厳しいかも・・・?NUCLEO F401クラスであれば余裕です。


使用できる液晶製品

LS027B7DH01Aと同一の駆動方式であれば駆動可能です。

対応済みと思われる製品(テストはLS027B7DH01Aで行っています)

LS012B7DD01とLS013B7DH06は駆動方式が異なるため使用できません。

直接結線して駆動することを前提としてコードを書いているので、
間にSRAMやEEPROMなどを挟んだり、4線式SPIの使用を前提としたものでは動作しません。


結線方法

端子一覧

端子一覧
液晶を表示面側から見たとき、右側の端子が1番左側の端子が10番になります。
データシートには逆っぽく書いてますが、実際コレで大丈夫です。
参考:http://l52secondary.blog.fc2.com/blog-entry-18.html
というかデータシートの書き方がわかりにくすぎ。さすが目の付け所が・・・。

画像は秋月電子の変換基板を使用していますが、コネクタ直接接続でも並び順は一緒です。


一番簡単な結線

一番簡単な結線は、vSCK, vSI, vCS電源+GNDの5本線を結線する方法です。

一番簡単な結線

もし、プログラム側で

SHMLCD_J mlcd(p26, p25, p24);

とした場合は、

1番端子(SCLK)とp26を接続、2番端子(SI)とp25を接続、3番端子(SCS)とp24を結線し、
5,6,7の端子を全部ショート(つなげて)させて、電源+(mbedの3v3や5V)に接続
8,9,10の端子を全部ショート(つなげて)させて、GND(mbedのGND)に接続


外部信号を使う結線

外部信号を使う結線は下記画像の通りです。
外部信号を使っても使わなくても表示機能自体に変化はありません。
dispOFF関数とかが使えるか使えないかの差です。

全機能を使う結線

この場合、プログラム側では5つの引数のコンストラクタを使用します。

プログラム側で

SHMLCD_J mlcd(p26, p25, p24, p23, p22);

とした場合は、

1番端子(SCLK)とp26を接続、2番端子(SI)とp25を接続、3番端子(SCS)とp24を結線し、
4番端子(EXTCOMIN)とp23を接続、5番端子(DISP)とp22を接続、
6,7,8をの端子を全部ショート(つなげて)させて、電源+(mbedの3v3や5V)に接続
9,10の端子を全部ショート(つなげて)させて、GND(mbedのGND)に接続


外部から液晶の表示を付けたり消したりしたいなら、外部信号結線を使ってください。
それ以外なら簡単結線で問題ありません。


使用準備

このライブラリはSPIポートを占拠しません
DigitalOutができるピンであればどれでも使用可能です。

前述の一番簡単な結線をした場合、以下のような宣言でSHMLCD_Jクラスの使用準備(インスタンス化)ができます。

#include "SH_MLCD_J.h" //SHMLCD_Jクラスをこれから使うからinclude(読み込む)

SHMLCD_J mlcd(p26, p25, p24); //mlcdの名前は自由、ピン番号は各自環境に合わせて変更

実際にプログラムとして書いてみると、

main.cpp

#include "mbed.h"
#include "SH_MLCD_J.h"

SHMLCD_J mlcd(p26, p25, p24); //←mlcdという名前で使用準備(インスタンス化)

int main(){
    mlcd.init(400, 240); //←液晶の初期化命令
    mlcd.pixel(5, 5); //←座標(5, 5)に点を打つ
}

このようになります。


init関数について

init関数は、液晶を使い始める前に必ず1回だけ呼ぶ必要があります。 そして、呼び出す際には液晶のサイズを指定します。

mlcd.init(400, 240); //←液晶の初期化命令

指定する数値は使用する液晶のサイズによって数値が変わります。
LS010B7DH01を使う場合は
幅128ピクセル、高さ128ピクセルの表示領域なので、

mlcd.init(128, 128); //←液晶の初期化命令

このようになります。

ちなみに、init関数は戻り値として「液晶の初期化に成功したがどうか」を返します。
初期化に成功したら true 、失敗したら false を返します。

成功失敗で処理を分けたい場合は、以下のようにして問題を回避してください。

bool success = mlcd.init(128, 128); //←液晶の初期化命令(bool型のsuccess変数に結果が入る)

if(success == true){
    //初期化に成功したときの処理
}false{
    //初期化に失敗したときの処理
}

 


図形描画関数について

SH_MLCD_Jクラスは、さまざまなグラフィック描画関数を備えています。

  • pixel関数:指定した座標に1ピクセルの点を描きます
  • drawLine関数:指定した座標から指定された座標まで線を引きます
  • drawRect関数、drawRect2関数:指定された座標、サイズで四角形を描きます
  • fillRect関数、fill2Point関数:指定された座標、サイズで塗りつぶされた四角形を描きます
  • drawCircle関数:指定された中心座標に、指定された半径の円を描きます
  • fillCircle関数:指定された中心座標に、指定された半径の塗りつぶされた円を描きます
  • drawChar関数:指定された1文字を、指定された座標に描きます
  • writeString関数、ws関数:指定された文字列を、指定された座標に描きます

引数:modeについて

いずれの関数も引数の中にmodeというものが存在します。
modeには、描画モードを指定します。

  • SHMLCD_J_BLACK:黒く描画します
  • SHMLCD_J_ERASE:白く描画します
  • SHMLCD_J_INVERT:画素を反転させます(fillCircleではうまく動作しません)

引数:immidiateについて

いずれの関数も引数の中にimmidiateというものが存在します。
immidiateには、即時描画を行うかどうかをtruefalseで指定します。

例えばpixel関数で1個打点したあと、immidiatetrueであればすぐに液晶に反映されます。
immidiatefalseの場合、内部画素記憶配列のみを更新し、液晶には反映しません。

1行だけの反映であれば大した時間はかかりませんが、反映する行が増えれば増えるほど
処理の時間がかかってしまいますので、書きたい情報を全部内部画素記憶配列に書き込んでから
一気にドバっと反映するほうが効率的で処理時間の短縮が見込めます。

なので、文字や四角形や格子模様などを複数行広範囲にわたって書き込む場合はimmidiatefalseにして
すべての描画処理が完了したあとにwriteArrayN関数やwriteArrayA関数を使用して
ドバっと更新するほうがお得です。

ちなみに、各関数のimmidiateのデフォルト値はtrueです。
引数を省略した場合は即時描画されてしまいますのでご注意ください。


サンプル

描画パターンは何千通りもあるので、各自実際にどのような描画になるのか試してみてください。

mbed LPC1768でのサンプル

main.cpp

#include "mbed.h"
#include "SH_MLCD_J.h"

SHMLCD_J mlcd(p26, p25, p24); //インスタンス化

int main(){
    wait(20.0); //結線完了までの待ち時間(不要であれば削除)

    //初期化(引数にはデータシートに書いてある表示横幅と表示高さを指定する)
    mlcd.init(400, 240);

    //四角形(即時描画)
    mlcd.drawRect(15, 15, 20, 20, SHMLCD_J_BLACK, true);
    mlcd.fill2Point(105, 15, 125, 35, SHMLCD_J_BLACK, true);

    //円(あとで描画):第5引数がfalseだと即時描画しない
    mlcd.drawCircle(25, 55, 10, SHMLCD_J_BLACK, false);
    mlcd.fillCircle(55, 55, 10, SHMLCD_J_BLACK, false);

    //小さい文字(あとで描画):第5引数がfalseだと即時描画しない
    char str1[] = "small text! 小さい文字は余裕。\n改行も有効です。タブは無理。";
    mlcd.ws(str1, 10, 80, SHMLCD_J_BLACK, false);

    //大きい文字(即時描画):第4引数にズーム倍率(整数)で倍角可能
    char str2[] = "Large Text! 2倍角も余裕。";
    mlcd.ws(str2, 10, 160, 2, SHMLCD_J_BLACK, true);

    wait(3.0); //3秒待つ

    //表示画素全部更新(ここで円と小さい文字が描画されます)
    mlcd.writeArrayA();

    wait(10.0); //10秒待つ

    mlcd.cls(); //表示クリア(内部記憶配列はクリアされない)

    //表示画素全部更新(さっき消したものが再現される)
    mlcd.writeArrayA();

    wait(10.0); //10秒待つ

    mlcd.cls(); //表示クリア
    mlcd.cla(); //内部記憶配列もクリア

    //表示画素全部更新(内部記憶配列を消したので真っ白になる)
    mlcd.writeArrayA();

    //プログラムが終わらないための処理
    for(;;);
}

 


NUCLEOボード用のサンプル

main.cpp

#include "mbed.h"
#include "SH_MLCD_J.h"

SHMLCD_J mlcd(D7, D6, D5, D4, D3); //SHMLCD_Jインスタンス化(D7, D6, D5, D4, D3の5ピンを使用)
DigitalIn btn(USER_BUTTON); //青ボタン

int main(){
    //初期化(引数にはデータシートに書いてある表示横幅と表示高さを指定する)
    mlcd.init(400, 240);
    
    //青いボタンが押されるまで待ち続ける
    while(btn);
    delay(1.0); //1秒待つ

    //Nucleoの文字を3倍角で描画(即時描画)
    mlcd.ws("ST Nucleo Board", 0, 0, 3);
    
    wait(5.0); //5秒待つ
    
    //液晶の表示をオフにする(画面が消える)
    mlcd.dispOFF();
    
    //青いボタンが押されるまで待ち続ける
    while(btn);
    delay(1.0); //1秒待つ
    
    //液晶の表示をオンにする(画面が点灯する)
    mlcd.dispON();
    
    wait(5.0); //5秒待つ

    //小さい文字(あとで描画):第5引数がfalseだと即時描画しない
    char str1[] = "small text! 小さい文字は余裕。\n改行も有効です。タブは無理。";
    mlcd.ws(str1, 10, 80, SHMLCD_J_BLACK, false);

    //大きい文字(即時描画):第4引数にズーム倍率(整数)で倍角可能
    char str2[] = "Large Text! 2倍角も余裕。";
    mlcd.ws(str2, 10, 160, 2, SHMLCD_J_BLACK, true);

    wait(10.0); //10秒待つ

    //表示画素全部更新(ここで小さい文字が描画されます)
    mlcd.writeArrayA();

    wait(3.0); //3秒待つ
    
    //表示をクリア
    mlcd.cls();
    
    //内部配列もクリア
    mlcd.cla();

    //設定された表示幅と高さを取得
    int width_size = mlcd.getWidth();
    int height_size = mlcd.getHeight();

    //グリッドを表示
    //垂直線を等間隔にXOR表示(描画はあとで):第4引数は描画モード
    //描画モード(fillCircleはSHMLCD_J_INVERTが使えません):
    // SHMLCD_J_BLACK (0): 黒で描画します
    // SHMLCD_J_ERASE (1): 白で描画します
    // SHMLCD_J_INVERT (-1): 画素を反転(XOR)させます(白なら黒、黒なら白)
    for(int x=10; x<width_size; x+=20){
        mlcd.drawLine(x, 0, x, height_size-1, SHMLCD_J_INVERT, false);
    }
    //水平線を等間隔にXOR表示(描画はあとで):第4引数は描画モード
    for(int y=10; y<height_size; y+=20){
        mlcd.drawLine(0, y, width_size-1, y, SHMLCD_J_INVERT, false);
    }

    //表示画素特定部分だけ更新:ライン80からライン160まで更新
    mlcd.writeArrayN(80, 160);

    wait(3.0); //3秒待つ

    //表示画素全部更新
    mlcd.writeArrayA();
    
    //プログラムが終わらないための処理
    for(;;);
}

 


全関数一覧

このページでは紹介していない関数もありますので、使用してみたい関数を見つけて
動くかどうかを試してみてください。

Import library

Public Member Functions

SHMLCD_J (PinName vSCK, PinName vSI, PinName vCS, PinName vCOM, PinName vDISP)
コンストラクタ:SHMLCD_Jクラスのインスタンスを作成します
SHMLCD_J (DigitalOut *vSCK, DigitalOut *vSI, DigitalOut *vCS, DigitalOut *vCOM, DigitalOut *vDISP)
コンストラクタ:SHMLCD_Jクラスのインスタンスを作成します
SHMLCD_J (PinName vSCK, PinName vSI, PinName vCS)
コンストラクタ:SHMLCD_Jクラスのインスタンスを作成します(COM端子とDISP端子は使用しません)
SHMLCD_J (DigitalOut *vSCK, DigitalOut *vSI, DigitalOut *vCS)
コンストラクタ:SHMLCD_Jクラスのインスタンスを作成します(COM端子とDISP端子は使用しません)
~SHMLCD_J ()
デストラクタ:内部配列と使用した変数を削除します(ユーザーが呼ぶ必要はありません)
bool init (unsigned short dispWidth, unsigned short dispHeight)
初期化:使用する配列や端子の状態を初期化します
unsigned short getWidth ()
初期化時に指定した表示ピクセル幅を返す
unsigned short getHeight ()
初期化時に指定した表示ピクセル高さを返す
void clear ()
液晶の表示をクリアする:内部画素記憶配列はクリアされない
void cls ()
液晶の表示をクリアする:内部画素記憶配列はクリアされない( clear() のエイリアス)
void clearArray ()
内部画素記憶配列をクリアする:表示はクリアされない
void cla ()
内部画素記憶配列をクリアする:表示はクリアされない( clearArray() のエイリアス)
void dispON ()
DISP端子をONにする:外部DISP信号を使用しない場合は何も起きない
void dispOFF ()
DISP端子をOFFにする:外部DISP信号を使用しない場合は何も起きない
void invertCOM ()
液晶寿命を延ばすためにCOM信号を反転させる
void regCOMTimer (float tickTime=0.25)
液晶寿命を延ばすためのCOM信号反転をタイマーに登録して自動的に行う
void deregCOMTimer ()
液晶寿命を延ばすためのCOM信号反転のタイマーを解除する
void updateArray1 (unsigned char ln, const char *data)
内部画素記憶配列の特定の行にデータを上書きする
void updateArrayN (unsigned char sn, unsigned char en, const char *data)
内部画素記憶配列の特定の範囲にデータを上書きする
void updateArrayA (const char *data)
内部画素記憶配列を全て上書きする
void writeArray1 (unsigned char ln)
内部画素記憶配列の特定の行をメモリ液晶に表示する
void writeArrayN (unsigned char sn, unsigned char en)
内部画素記憶配列の特定の範囲をメモリ液晶に表示する
void writeArrayA ()
内部画素記憶配列を全てメモリ液晶に表示する
void write1 (unsigned char ln, const char *data)
データをメモリ液晶の特定行に表示する(内部画素記憶配列を介さない)
void writeN (unsigned char sn, unsigned char en, const char *data)
データをメモリ液晶の特定の範囲に表示する(内部画素記憶配列を介さない)
void writeA (const char *data)
データをメモリ液晶全域に表示する(内部画素記憶配列を介さない)
void pixel (unsigned short x, unsigned short y, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶の特定の座標に1ピクセルのドットを表示する
void drawLine (unsigned short fromX, unsigned short fromY, unsigned short toX, unsigned short toY, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に線を表示する
void drawRect (unsigned short left, unsigned short top, unsigned short width, unsigned short height, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に四角形を表示する
void drawRect2 (unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に四角形を表示する(対角点指定)
void fillRect (unsigned short left, unsigned short top, unsigned short width, unsigned short height, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に塗りつぶされた四角形を表示する
void fill2Point (unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に塗りつぶされた四角形を表示する(対角点指定)
void drawCircle (unsigned short centerX, unsigned short centerY, unsigned short r, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に円を表示する
void fillCircle (unsigned short centerX, unsigned short centerY, unsigned short r, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に塗りつぶされた円を表示する
signed char drawChar (const char *s, unsigned short x, unsigned short y, unsigned char zoom, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に文字を表示する
signed char writeString (const char *str, unsigned short x, unsigned short y, unsigned char zoom, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に文字列を表示する
signed char writeString (const char *str, unsigned short x, unsigned short y, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に文字列を表示する
signed char ws (const char *str, unsigned short x, unsigned short y, unsigned char zoom, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に文字列を表示する(writeStringのエイリアス)
signed char ws (const char *str, unsigned short x, unsigned short y, signed char mode=SHMLCD_J_BLACK, bool immidiate=true)
メモリ液晶に文字列を表示する(writeStringのエイリアス)

COM反転信号について

COM反転は、液晶の寿命を延ばすために(焼き付き防止?)人間に見えない速度で液晶を明滅させる仕組みです。
COM反転信号はCOM反転を行うタイミングを液晶に伝達するもので、外部信号と内部信号の2種類があります。
このライブラリでは呼ばれたコンストラクタによって処理を変えており、
引数が3つのコンストラクタで呼ばれたらCOM反転は内部信号を使用します。
引数が5つのコンストラクタで呼ばれたらCOM反転は外部信号を使用します。
(ただし、引数が5つでもDigitalOutができないピンであれば内部信号に切り替わる)

引数が3つのコンストラクタを呼ぶ場合は、EXTCOMの端子VSS(GND)に接続し 引数が5つのコンストラクタを呼ぶ場合は、EXTCOMの端子VDD(3.3-5V)に接続してください。

COM反転信号はTickerを使って自動的に送出される仕組みになっていますが
init関数を呼ぶまではタイマーは作動しません。ユーザーがderegTimer関数でタイマーを解除した場合も、
regTimer関数で再度タイマーを開始するまでは止まったままになります。

また、int main()が終了した場合もSH_MLCD_Jクラスのインスタンスそのものが削除されて
COM反転信号が止まりますので、プログラムの終了を意図的に遅延させるか、プログラム終了後は
速やかに液晶を取り外してください。


質問など

質問などあればこのページに議題を立ててわかりやすく簡潔に記載してください。
このページに書いただけでは私が気付かない可能性がありますので、返答が遅い場合は
このブログのmbedカテゴリの記事(どれでもいいです)に何かコメントを書いてください。

ここまでまとめるのに5時間。もう疲れました。

no such method: docs