キャラクタ液晶使ってみた

Arduinoでも良く使われるキャラクタ液晶モジュールをRaspberryPiで使ってみました。
今回使ったのは台湾サンライク社(SUNLIKE)液晶モジュールSD1602HULB-XA-G-Gです。若松通商でGR-SAKURA用として販売されています。秋月電子でも販売されています。
16文字x2行の液晶でLEDバックライトも内蔵しています。

この液晶モジュールに内蔵されているインターフェースICはHD44780互換になっています。HD44780は、80年代前半に日立製作所(現ルネサス エレクトロニクス)から発売されたキャラクタ液晶用のコントローラICです。現在、ほとんどのキャラクタ液晶モジュールでHD44780またはその互換ICが使用されています。HD44780は「MPUにバス接続してコマンドによる制御が可能」「80文字(40桁×2行)分の表示データ・バッファを内蔵」「キャラクタ・ジェネレータを内蔵」「LCDドライバを内蔵しLCDパネルを直結駆動可能」などの特徴があり、カナや外字の表示も可能です。

この液晶インターフェースを動かすにはシンク電流が流れるようにしておく必要がありますが、RaspberryHabuのTD62783AGPを通すとシンク電流が流れないため、基板上のRaspberryPiのピンから直結されているポートにコネクタをつけます。
DSC01441s
この液晶にデータを書き込む方法は4bitモードと8bitモードがありますが、今回はピン数を節約するため4bitモードで使います。4bitモードでは8bitの信号を上位4bit下位4bitの2回に分けて書き込みます。
ピンを液晶にはんだづけしてブレッドボードに差し、以下のように繋ぎます。
DSC01446s

左下の半固定抵抗は10kΩでコントラスト調整用です。だいたい3kΩくらいが見やすい値でした。液晶側15、16ピンはバックライト用で15ピンはVcc、16ピンは330Ωの抵抗を通してGNDにつなぎます。

/*
lcdout.c
Lisence CC0.
*/
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "wiringPi.h"

#define RS 4
#define E 6
#define ESETUPTIME 10
#define NEXTTIME 50
#define EPULSETIME 60

int WriteLCDLCommand( int command ){
  int i,pair=0x80;
  usleep(NEXTTIME);
  digitalWrite(RS,LOW);
  for ( i = 3; i >= 0 ; i--){
    if ( 0 < ( pair & command ) )
    {
      digitalWrite(i,HIGH);
    } else {
      digitalWrite(i,LOW);
      }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);
  for ( i = 3; i >= 0 ; i--){
    if ( 0 < ( pair & command ) )
    {
  digitalWrite(i,HIGH);
    } else {
      digitalWrite(i,LOW);
      }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);
  }

int WriteLCDLData( int data ){
  int i,pair=0x80;
  usleep(NEXTTIME);
  digitalWrite(RS,HIGH);
  for ( i = 3; i >= 0 ; i--){
    printf("%d %d %d:",data,pair,i);
    if ( 0 < ( pair & data ) )
      {
      digitalWrite(i,HIGH);
      printf("1\n");
      } else {
        digitalWrite(i,LOW);
        printf("0\n");
        }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);
  for ( i = 3; i >= 0 ; i--){
    printf("%d %d %d:",data,pair,i);
    if ( 0 < ( pair & data ) )
      {
      digitalWrite(i,HIGH);
      printf("1\n");
      } else {
      digitalWrite(i,LOW);
      printf("0\n");
      }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);

  }

  int WriteLCDCommand( int command ){
  int i;
  digitalWrite(RS,LOW);
  for ( i = 0; i < 4 ; i++){
    if ( 0 > command % 2 )
      {
      digitalWrite(i,HIGH);
      } else {
      digitalWrite(i,LOW);
      }
    command = command / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);

  }

  int WriteLCDData( int data ){
  int i;
  digitalWrite(RS,HIGH);
  for ( i = 0; i < 4 ; i++){
  if ( 0 > data % 2 )
    {
    digitalWrite(i,HIGH);
    } else {
    digitalWrite(i,LOW);
    }
  data = data / 2;
  }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);

  }

int main()
  {
  wiringPiSetup();
  pinMode(0,OUTPUT);
  pinMode(1,OUTPUT);
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  /*
  WriteLCDCommand( 0x02 );
  WriteLCDCommand( 0x02 );

  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x08 );

  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x01 );

  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x04 );

  WriteLCDCommand( 0x07 );
  WriteLCDCommand( 0x00 );

  WriteLCDData( 0x08 );
  WriteLCDData( 0x00 );

  WriteLCDData( 0x03 );
  WriteLCDData( 0x03 );

  usleep(NEXTTIME);

  WriteLCDCommand( 0x03 );
  WriteLCDCommand( 0x03 );

  usleep(NEXTTIME);

  WriteLCDCommand( 0x03 );
  WriteLCDCommand( 0x02 );

  usleep(NEXTTIME);

  WriteLCDCommand( 0x02 );
  WriteLCDCommand( 0x08 );

  usleep(NEXTTIME);
  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x0C );

  usleep(NEXTTIME);
  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x06 );

  usleep(NEXTTIME);
  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x01 );

  usleep(NEXTTIME);
  usleep(2000);

  WriteLCDCommand( 0x08 );
  WriteLCDCommand( 0x00 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x03 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x04 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x05 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x06 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x07 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x08 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x09 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x0A );

  WriteLCDLCommand( 0x33 );
  WriteLCDLCommand( 0x32 );
  WriteLCDLCommand( 0x28 );
  WriteLCDLCommand( 0x0C );
  WriteLCDLCommand( 0x06 );
  WriteLCDLCommand( 0x01 );
  WriteLCDLCommand( 0x80 );

  WriteLCDLData( 0x32 );
  WriteLCDLData( 0x33 );
  WriteLCDLData( 0x34 );
  WriteLCDLData( 0x35 );
  WriteLCDLData( 0x33 );
}

WriteLCDLCommandでLCDの初期設定やモードなどを書き込み、WriteLCDLDataで表示する文字のデータを2回に分けて書き込みます。

DSC01437ss
出力結果です。WriteLCDLDataで書き込まれた数字が表示されています。

LCD表示ができるとセンサで計測した数値をリアルタイムで確認したり本体の動作の確認に使えたりいろいろ便利そうですね。