さくらのジャンク箱ロゴ

Sakura87がほぼ月刊でお届けするPCや電子工作と写真の備忘録てきなブログ @なんと20周年

Raspberry Pi 2でキャラクタ液晶の制御(2.5)

この記事は9年ほど前に投稿されました。内容が古くなっている可能性がありますので更新日時にご注意ください。

IMG_4645_20150607

(同じ画像3回使い回し)

前回、色々な文字を液晶に転送してみましたが、いちいちコードを調べて転送用コマンドに送信するのは正直手間ですよね。そこで今回は文字コードを転送するコマンドを実装してみたいと思います。

仕組み

code

まず、この液晶の文字コードと、ASCIIコードは同じ(水色の部分)でカナも含めるとJISコードの冒頭8bit分 (JIS X 0201)に準拠しています。(薄い緑色の部分)

ただし、未定義領域にオリジナルの文字が入っているのと一部の文字が違う文字に置き換わっているので厳密に言うと違います。例えばASCIIコードだと本来「~」がくるところに「→」、制御文字(DEL)が来るはずの所に「←」がそれぞれ割り当てられています。(おそらく「^」と「~」が5ドットでは区別できないのと、制御文字(DEL)がそもそも必要ないからでしょう。)

要するに、C言語で入力された文字の文字コードを調べて、その文字コードを液晶に転送してやる関数を作れば、ユーザーは転送したい文を関数に転送するだけで楽に液晶に文字を転送できると言うことですね。

そこで今回はその関数を作ります。

コーディング

ベースのコードは前回・前々回と同じものです。そのコードを変更する形になります。

始めに関数を定義します。

int LCD_TEX(int line,char SendText[40]){

line変数で書き込み先の行を指定、SendTextは実際に表示する文字列を入れます。
一度に表示可能な文字数は16文字ですが、液晶のバッファ最大値である40文字分確保します。

渡された変数の他に使用する変数を定義します。

int i,n,bin[8];char dec;

次に指定された行によってアドレス指定をかえます。

    //書き込みアドレス指定
    if(line==1){LCD_SET(0,0,1,0,0,0);LCD_SET(0,0,0,0,0,0);}
    if(line==2){LCD_SET(0,0,1,1,0,0);LCD_SET(0,0,0,0,0,0);}

1行目の場合と、2行目の場合。それぞれの行頭のアドレスを定義します。
私の買った液晶では&h00が1行目行頭、&h40が2行目行頭でしたのでそれを転送します。

次に、読み取ったデータを1文字ずつ液晶に転送します。

    // 読み取ったデータを1文字ずつ液晶に転送
    for(n=0;n<strlen(SendText);n++){ 
        dec=SendText[n];
        
        // Char型を2進数に変換して配列に格納
        bin[0]=(dec%2);dec/=2;
        bin[1]=(dec%2);dec/=2;
        bin[2]=(dec%2);dec/=2;
        bin[3]=(dec%2);dec/=2;
        bin[4]=(dec%2);dec/=2;
        bin[5]=(dec%2);dec/=2;
        bin[6]=(dec%2);dec/=2;
        bin[7]=(dec%2);dec/=2;
        
        //データを液晶に送る
        LCD_SET(1,0,bin[7],bin[6],bin[5],bin[4]);
        LCD_SET(1,0,bin[3],bin[2],bin[1],bin[0]);
    }

このデータでは、char変数の先頭から1文字ずつ抜き出して、それを2進数に変換して、転送しています。

最後に転送後に残った文字バッファを全て空白で埋めます。

for(n=n;n<40;n++){LCD_SET(1,0,0,0,1,0);LCD_SET(1,0,0,0,0,0);}

以下の通りのコードになるはずです。

int LCD_TEX(int line,char SendText[40]){
    
    int i,n,bin[8];char dec;
    

    //書き込みアドレス指定
    if(line==1){LCD_SET(0,0,1,0,0,0);LCD_SET(0,0,0,0,0,0);}
    if(line==2){LCD_SET(0,0,1,1,0,0);LCD_SET(0,0,0,0,0,0);}
    
    // 読み取ったデータを1文字ずつ液晶に転送
    for(n=0;n<strlen(SendText);n++){ 
        dec=SendText[n];
        
        // Char型を2進数に変換して配列に格納
        bin[0]=(dec%2);dec/=2;
        bin[1]=(dec%2);dec/=2;
        bin[2]=(dec%2);dec/=2;
        bin[3]=(dec%2);dec/=2;
        bin[4]=(dec%2);dec/=2;
        bin[5]=(dec%2);dec/=2;
        bin[6]=(dec%2);dec/=2;
        bin[7]=(dec%2);dec/=2;
        
        //データを液晶に送る
        LCD_SET(1,0,bin[7],bin[6],bin[5],bin[4]);
        LCD_SET(1,0,bin[3],bin[2],bin[1],bin[0]);
    }
    
    // 残った文字を空白でうめる
    for(n=n;n<40;n++){LCD_SET(1,0,0,0,1,0);LCD_SET(1,0,0,0,0,0);}

    
    }

使い方

例えば1行目に「Sakura87.net」を転送するコマンドはこうなります。

    LCD_TEX(1,"Sakura87.net");

実行すると以下の通りになるはずです。

IMG_4657_20150610

次に2行目に「サクラノハナビラ.net」を転送するコードを追加します。
※カナを扱う為にはソースコードおよび入力の文字コードをShift_JISにする必要があります。

    LCD_TEX(2,"サクラノハナビラ.net")

これで以下の通りの表示になると思います。

IMG_4658_20150610

文字コードについて

英数字データを表示するだけなら文字コード指定は関係ありませんが、カナを出力するときはJISコードもしくはShift_JISコードでソースファイルおよび入力データを作成する必要があります。ただし、内容によってはJISコードでは表示がおかしくなる場合がありますので、基本的にShift_JISで作成してください。

例えば先ほどの表示をソースファイルの文字コードを変えてみるとどうなるかというと。

  • Shift_JIS(正常表示)
    IMG_4658_20150610
  • JIS(正常に表示できない)
    IMG_4656_20150609
  • EUC-JP(変なスペースが入る)
    IMG_4655_20150609
  • UTF-8(正常に表示できない)
    IMG_4654_20150609

このように、正常に表示できなくなります。
ですのでカナを扱う場合、文字コードはShift_JISで作成しましょう。(英数字のみの場合は何も気にしなくて問題ないです。)

ちなみに、JISコードで未定義の、液晶オリジナルの文字を表示する場合はsprintfにて文字コードを指定してそれをくっつけてやります。

例えば、「ゴウケイ「1200万円」デス」と表示させたい場合「万」と「円」のコードは0xFBと0xFCなのでこうなります。

    char Gaiji[16];
    sprintf(Gaiji,"%s%c%c%s","ゴウケイ「1200",0xFB,0xFC,"」デス");
    LCD_TEX(1,Gaiji);

コレを実行するとこうなります。

IMG_4659_20150610

以上、データ送信コマンドを作って、実際に表示操作を簡略化する事に成功しました。

それでは最後に、「ゴウケイ「1200万円」デス」と表示した時のソースコードを貼り付けておきますね。

#include <stdio.h>
#include <wiringPi.h>
#include <string.h>

//LCDのピンを指定
// 4bit Mode
#define LCD_D7 13 // ここから
#define LCD_D6 12
#define LCD_D5 3
#define LCD_D4 2 // ここまでがデータ用
#define LCD_EN 0 // リード/ライト イネーブル信号
#define LCD_RW 7 // リード/ライト 選択信号
#define LCD_RS 9 // レジスタ選択信号
#define LCD_BK 8 // LCDのバックライト電源オンオフ用
#define LCD_ON 25 // LCDの電源オンオフ用

int main(void){
    
    // WiringPi初期化
    wiringPiSetup();

    // GPIOポートの設定
    pinMode(LCD_D7,OUTPUT);
    pinMode(LCD_D6,OUTPUT);
    pinMode(LCD_D5,OUTPUT);
    pinMode(LCD_D4,OUTPUT);
    pinMode(LCD_EN,OUTPUT);
    pinMode(LCD_RS,OUTPUT);
    pinMode(LCD_RW,OUTPUT);
    pinMode(LCD_ON,OUTPUT);
    pinMode(LCD_BK,OUTPUT);

    // 液晶リセット
    LCD_RES();
    
    // データ表示クリア
    LCD_SET(0,0,0,0,0,0);LCD_SET(0,0,0,0,0,1);
    char Gaiji[16];
    sprintf(Gaiji,"%s%c%c%s","ゴウケイ「1200",0xFB,0xFC,"」デス");
    LCD_TEX(1,Gaiji);

    
    
    
    }
    
    
int LCD_RES(void){
        
    digitalWrite(LCD_ON,0); // LCD電源オフ
    digitalWrite(LCD_BK,0); // LCDバックライトオフ
    delay(1);
    digitalWrite(LCD_ON,1); // LCD電源オン
    digitalWrite(LCD_BK,1); // LCDバックライトオン
    delay(40);

    LCD_SET(0,0,0,0,1,1); // 8bitモードに設定
    delay(4.1);
    LCD_SET(0,0,0,0,1,1); // 8bitモードに設定
    usleep(100);
    LCD_SET(0,0,0,0,1,1); // 8bitモードに設定
    LCD_SET(0,0,0,0,1,0); // 4bitモードに設定

    LCD_SET(0,0,0,0,1,0);LCD_SET(0,0,1,0,0,0); // 2行 普通フォントに設定
    LCD_SET(0,0,0,0,0,0);LCD_SET(0,0,1,0,0,0); // 液晶表示OFF
    LCD_SET(0,0,0,0,0,0);LCD_SET(0,0,0,0,0,1); // データクリア
    LCD_SET(0,0,0,0,0,0);LCD_SET(0,0,0,1,1,0); // カーソル右移動 左シフトに設定        
    LCD_SET(0,0,0,0,0,0);LCD_SET(0,0,1,1,0,0); // 液晶表示ON
        
}

int LCD_SET(int rs,int rw,int db7,int db6,int db5,int db4){
    
    // 一旦全ポートに0を書き込む
    digitalWrite(LCD_RW,0);
    digitalWrite(LCD_RS,0);
    digitalWrite(LCD_EN,0);
    nanosleep(60);
    digitalWrite(LCD_D7,0);
    digitalWrite(LCD_D6,0);
    digitalWrite(LCD_D5,0);
    digitalWrite(LCD_D4,0);
    usleep(40);
    
    // データ転送
    digitalWrite(LCD_RW,rw);
    digitalWrite(LCD_RS,rs);
    nanosleep(60);
    digitalWrite(LCD_EN,1);
    nanosleep(60);
    digitalWrite(LCD_D7,db7);
    digitalWrite(LCD_D6,db6);
    digitalWrite(LCD_D5,db5);
    digitalWrite(LCD_D4,db4);
    digitalWrite(LCD_EN,0);
    
    // 表示クリア、初期位置復帰命令の実行時間が
    // 1.52msと長いので、RSとR/Wの数値が0の命令は
    // 待ち時間を長く設定する。
    if((rw+rs)==0)usleep(1520);
    if((rw+rs)!=0)usleep(40);

}

int LCD_TEX(int line,char SendText[40]){
    
    int i,n,bin[8];char dec;
    

    //書き込みアドレス指定
    if(line==1){LCD_SET(0,0,1,0,0,0);LCD_SET(0,0,0,0,0,0);}
    if(line==2){LCD_SET(0,0,1,1,0,0);LCD_SET(0,0,0,0,0,0);}
    
    // 読み取ったデータを1文字ずつ液晶に転送
    for(n=0;n<strlen(SendText);n++){ 
        dec=SendText[n];
        
        // Char型を2進数に変換して配列に格納
        bin[0]=(dec%2);dec/=2;
        bin[1]=(dec%2);dec/=2;
        bin[2]=(dec%2);dec/=2;
        bin[3]=(dec%2);dec/=2;
        bin[4]=(dec%2);dec/=2;
        bin[5]=(dec%2);dec/=2;
        bin[6]=(dec%2);dec/=2;
        bin[7]=(dec%2);dec/=2;
        
        //データを液晶に送る
        LCD_SET(1,0,bin[7],bin[6],bin[5],bin[4]);
        LCD_SET(1,0,bin[3],bin[2],bin[1],bin[0]);
    }
    
    // 残った文字を空白でうめる
    for(n=n;n<40;n++){LCD_SET(1,0,0,0,1,0);LCD_SET(1,0,0,0,0,0);}

    
    }

 

総閲覧数:299 PV

“Raspberry Pi 2でキャラクタ液晶の制御(2.5)” への1件のコメント

  1. […] 前回までGPIOピンを直接切り替えて液晶を制御していましたが。実はwiringPiにはキャラクタ液晶制御用のライブラリが用意されているので、今回はそれを使ってみたいと思います。 […]

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください