PIRセンサ+サーボ

今回はPIRセンササーボを連携させてみます。
ハードウェアPWMを使うのでサーボをデジタル出力0番ピンに、PIRセンサをデジタル入力1番ピンにつなぎます。

DSC01554配線

動くものを検知した時に動き、検知していない時は止まるようにプログラムします。

 // pir_servo.c sample program for RaspberryHabu
 // Licence CC 0 ( Public Domain )
 
 #include "stdio.h"
 #include "wiringPi.h"
 #include "unistd.h"

int main()
{
  int pir,pwm;
  if (-1 == wiringPiSetup())
    {
      printf("setup error!");
      exit(1);
    }
  pinMode(1,PWM_OUTPUT);
  pinMode(0,INPUT);
  while(1){
    pir=digitalRead(0);
    if(pir == 1)
    {
    pwmWrite(1,10);
    usleep(50000);
    pwmWrite(1,500);
    usleep(50000);
    pwmWrite(1,10);
    }else if(pir == 0){
    pwmWrite(1,0);
    sleep(5);
    }
    printf("channel 0 : %d servo : %d\n", pir,pwm);
    pwmWrite(1,0);
    sleep (1);
  }
}

動く物を検知したとき、アナログ入力1ピンにつながったRaspberryPi上のLEDが光ります。

DSC01556動いたものを検知した時

DSC01555検知していない時

人が動いたときに何かを動かすようなロボットが作れます。
例えば扉の片側にサーボで扉のカギを開け閉めできるように設置するとオートロックドアを作れますね。

距離センサ+モータ

距離センサを使うロボットの命題としては迷路探索などがあります。有名なものとしてはマイクロマウスがありますね。
今回は距離センサとモータを連動させてみます。使う部品は以前紹介したシャープ製IR距離センサFA130モータです。

距離センサをアナログ入力に、モータ回路をデジタル出力につなぎます。

DSC01553

近づくとゆっくりに、離れると速く動くようにプログラムします。

 // Licence CC 0 ( Public Domain )
 #include 
#include 
#include 
#include 

#define MOTORPWM 1
#define MOTOROUT1 2
#define MOTOROUT2 3

#define SPIBUFFSIZE 256

unsigned char spidata[SPIBUFFSIZE];

int MCP3008Read(int channel){
  int spireturn,data;
  spidata[0]= 1;
  spidata[1]= (0x80 | channel << 4);
  spidata[2]= 0;
  spireturn = wiringPiSPIDataRW(0, spidata, SPIBUFFSIZE);
  data = ((spidata[1]&3) << 8 ) + spidata[2];
  return(data);

int main()
{
  int distance;
  int spiresult;

  if (-1 == wiringPiSPISetup(0,1000000))
    {
      printf("SPI setup error!");
      exit(1);
    }

  wiringPiSetup();

  pinMode(MOTOROUT1,OUTPUT);
  pinMode(MOTOROUT2,OUTPUT);
  pinMode(MOTORPWM,PWM_OUTPUT);

  digitalWrite(MOTOROUT1,0);
  digitalWrite(MOTOROUT2,0);
  pwmWrite(MOTORPWM,0);
while(1){
  spiresult=MCP3008Read(7);
  digitalWrite(MOTOROUT1,1);
  if(spiresult<40){
    distance = 7;
    pwmWrite(MOTORPWM,256);
  }else if(spiresult<50){
    distance = 6;
    pwmWrite(MOTORPWM,128);
  }else if(spiresult<70){
    distance= 5;
    pwmWrite(MOTORPWM,64);
  }else if(spiresult<110){
    distance = 4;
    pwmWrite(MOTORPWM,32);
  }else if(spiresult<190){
    distance = 3;
    pwmWrite(MOTORPWM,16);
  }else if(spiresult<350){
    distance = 2;
    pwmWrite(MOTORPWM,8);
  }else if(spiresult<670){
    distance = 1;
    pwmWrite(MOTORPWM,1);
  }else{
  distance = 0;
  pwmWrite(MOTORPWM,0);
  }
  printf("readspi : %d distance : %d\n", spiresult,distance);
  sleep (1);
  pwmWrite(MOTORPWM,0);
  }
}

近い(約5cm)とゆっくり、遠い(約50cm)と速く回ります。
用途としてはいろいろありますが、モータの数とセンサの数を増やせば前出のマイクロマウスも作れますね。

周りの明るさを感知してLEDの強さを調整してみた

今回使うのは照度センサと緑色のLEDです。照度センサは以前にも使ったパナソニック製NaPiCaです。

アナログ入力でNaPiCaの検知する明るさの値を取得してPWMで緑色LEDの明るさを調整します。
NaPiCaをアナログ入力0ピンにつなぎ、緑色LEDのアノード側(+、足の長いほう)をデジタル出力1ピンにつなぎます。緑色LEDのカソード側(-、足の短いほう)には抵抗(10kΩ)をつないでその先をGNDにつなぎます。

DSC01552

明るい時をPWM100%に、暗い時を0%にします。

 // lednapica.c sample program for RaspberryHabu
 // Licence CC 0 ( Public Domain )
 
#include "stdio.h"
#include "stdlib.h"
#include "wiringPPI.h"
#include "wiringPi.h"

#define TEISU 20
#define SPIBUFFSIZE 256

unsigned char spidata[SPIBUFFSIZE];
int MCP3008Read(int channel){
  int spireturn,data;
  spidata[0]= 1;
  spidata[1]= (0x80 | channel << 4);
  spidata[2]= 0;
  spireturn = wiringPiSPIDataRW(0, spidata, SPIBUFFSIZE);
  data = ((spidata[1]&3) << 8 ) + spidata[2];
  return(data);
}

int main()
{
  int spiresult,led;
  if (-1 == wiringPiSPISetup(0,1000000))
    {
      printf("SPI setup error!");
      exit(1);
    }
  if (-1 == wiringPiSetup())
    {
      printf("setup error!");
      exit(1);
    }
  pinMode(1,PWM_OUTPUT);
  while(1){
    spiresult=MCP3008Read(0);
    led = 1023 - (spiresult * TEISU) ;
    if(led>1023){
    led = 1023;
    }else if(led<0){
    led = 0;
    }
    printf("channel 0 : %d led %d\n", spiresult,led);
    pwmWrite(1,led);
    usleep (50000);
  }
}

動かしてみると、少し見にくいですが緑のLEDの明るさが変化しているのがわかります。TEISUの値は実験環境に合わせて変えてみてください。

DSC01550暗い時

DSC01549明るい時

液晶のバックライトなどに応用できそうです。
PIRセンサと組み合わせて人がいるときだけ調整するデスクスタンドライトなどを作るのもよさそうですね。

圧電素子をセンサに使ってみた

圧電素子は電圧をかけると音が出ますが、逆に音(衝撃)を感じると電圧を生じます。
この性質を利用して、圧電素子を衝撃センサとしてLEDを光らせてみることにしました。

圧電素子はRaspberryHabuBasicについているものを使います。

DSC01535

RaspberryHabuの圧電素子はスピーカとして使えるように配置されていますが、そばのジャンパーピン(下の画像の黄色の線で囲ってあるところ。画像ではすでに外してある。)を外すことにより回路との接続が切れるようになっています。

DSC01537

画像の上側のピン(上の画像の赤い丸印)がRaspberryHabu上の抵抗(2kΩ)とつながっており、その先に圧電素子がつながっています。圧電素子のもう片方の端子はGNDにつながっています。画像の上側のピンから別に用意した抵抗(10kΩ)をつないでTD62703AGPを通して74HC02を使ったフリップフロップ回路(SRラッチ)につなぎます。
RaspberryHabuのデジタル出力についているTD62783は入力耐圧15V、出力耐圧が50Vと高く、電流を500mAに制限する入力抵抗も入っており、RaspberryHabuにつないだ機器の保護回路となっています。
圧電素子から発生する電圧がとても高いことがあるのですが、74HC02の入力耐圧は6V程度なので、圧電素子から高い電圧がかかった時の保護のためにこのTD62783APGを外してブレッドボードに刺して保護回路として使います。
DSC01541

フリップフロップの出力をデジタル入力につなぎます。
フリップフロップのリセット信号につなぐRaspberryHabuからの配線はデジタル出力ですが、TD62783APGを外しているため脇のRaspberryPiから直接つながっているポートを使います。画像では一列のピンソケットをはんだづけしてあります。

DSC01539

一定時間ごとにフリップフロップをリセットするようにします。
信号を検知してから4秒後に1秒間のリセット信号を流すようにしました。

/* Lisence CC 0*/
#include "stdio.h"
#include "wiringPi.h"
#include "unistd.h"

#define DIN 0
#define RESETPIN 3

int main(void)
{
        wiringPiSetup();

        int i = 0;
        pinMode(DIN,INPUT);
        pinMode(RESETPIN,OUTPUT);
        digitalWrite(RESETPIN,0);
        while(1){
                i=digitalRead(DIN);
                if(i == 1){
                        printf("ON %d n",i);
                        sleep(4);
                        digitalWrite(RESETPIN,1);
                        sleep(1);
                        digitalWrite(RESETPIN,0);
                }
        }

        return 0;
}

圧電素子を軽く叩いて衝撃を発生させます。

DSC01542

衝撃を検知すると5秒以内にON 1と表示され、そのあと放置すると画面はそのままになります。

DSC01546

圧電素子を衝撃センサとして窓につけて防犯システムに使うこともあります。
使い方次第でいろいろできそうです。

サーボモーターを使ってみた-その2(ハードウェアPWM編)

前回に引き続き、サーボモータの制御をRaspberryHabuで試します。
今回はハードウェアPWMを試しましょう。

DSC01521

基本的にはソフトウェアPWMの回と同じつなぎ方ですが、RaspberryPiのハードウェアPWMが使えるのはRaspberryHabuのデジタル出力1番ピンにつながっているところだけなので白(PWM)をRaspberryHabuのデジタル出力1ピン、赤をVCC、黒をGNDにつなぎました。
ソフトウェアPWMの信号は0から99の値で設定しますが、ハードウェアPWMの信号は0から1023の値で設定します。

/*
servo-hardpwm.c
Lisence CC0.
*/

#include "stdio.h"
#include "stdlib.h"
#include "wiringPi.h"
int main()
{
  if (wiringPiSetup() == -1)
    {
      printf("setup error!");
      exit(1);
    }
   pinMode(1, PWM_OUTPUT);
   while(1){
    pwmWrite(1,700);
    printf("channel 1:pwm 70\n");
    sleep(2);
    pwmWrite(1,100);
    printf("channel 1: pwm 10\n");
    sleep (2);
  }
}

今回はWiringPiライブラリの関数であるhardPWMを使ってみました。

pinModeでPWM出力の設定をし、pwmWriteで出力します。

DSC01522PWM出力約10%時

DSC01523PWM出力約70%時

動いているのがわかります。基本的にはソフトウェアPWMと同じです。出力を0→1023に変えていくと右回りに角度が変化します。
ソフトウェアPWMはCPUの負荷によってはガタ付きなどが発生するため、安定して動かすにはハードウェアPWMのほうが望ましいと思われます。

次回はソフトウェアPWMとハードウェアPWMを比較してみます。

照度センサを使ってみた

今回は照度センサを使ってみます。

明るさを測る方法のひとつにフォトレジスタを使うものがあります。フォトレジスタは光を入射すると電気抵抗が変化する素子です。フォトレジスタには様々な種類がありますが、以前はCdS(硫化カドミウムセル)といわれるものがよく使われていました。CdSは「抵抗値の変化の幅が大きい」、「反応する周波数が広い」などの利点がありましたが、カドミウムがRoHS指令の規制対象元素になったため、あまり使われなくなりました。

現在フォトダイオードやフォトICなどの代替品が各社から販売されていますが、今回はCdSの代わりとして使いやすいパナソニック製NaPiCa AMS302を使いました。千石電商で入手できます。
NaPiCaはフォトダイオードのパッケージに増幅回路を内蔵しており、人間の視感度に近い特性を持っているのが特徴です。印加電圧は1.5~6V、ピーク波長は580nmです。周囲の明るさに比例した光電流がリニアに出力されます。

DSC01510s
回路を組んでみました。写真のブレッドボード上の透明なLEDのような形をした素子がAMS302です。AMS302は上がアノード、下の切り欠きのある側がカソードです。アノードのほうが足が長くなっています。抵抗をアノードとGNDの間につなぐことにより抵抗とアノードの間から出力(電圧)が得られます。今回は330Ωの抵抗をつなぎました。RaspberryHabuBasic側はアナログ入力0ピンを使っています。

 // napica.c sample program for RaspberryHabu
 // Licence CC 0 ( Public Domain )
 
 #include "stdio.h"
 #include "stdlib.h"
 #include "wiringPiSPI.h"
 #include "unistd.h"
 #define SPIBUFFSIZE 256
 unsigned char spidata[SPIBUFFSIZE];
 int MCP3008Read( int channel ){
   int spireturn,data;
   spidata[0]= 1; 
   spidata[1]= ( 0x80 | channel << 4 )  ;
   spidata[2]= 0;
   spireturn = wiringPiSPIDataRW( 0, spidata , SPIBUFFSIZE );
   data = ((spidata[1]&3) << 8) + spidata[2];
 return(data);
 }

int main()
{
  int spiresult;
  if (-1 == wiringPiSPISetup(0,1000000))
    {
      printf("SPI setup error!");
      exit(1);
    }
  while(1){
    spiresult=MCP3008Read(0);
    printf("channnel 0 : %d\n", spiresult);
    sleep (1);
  }
}

AD変換された10bitデータがそのまま表示されるコードです。1から1024の数字が出ます。暗いと小さくて明るいと大きい数字になります。

DSC01511通常時です。すこし暗めですが、数値は110付近ですね。

DSC01512センサを手で覆ってみました。数値は15付近。だいぶ暗いです。

DSC01514白いLEDで照らしてみました。数値は250付近でした。

このセンサを使えば明るさの変化に対応したシステムが組めます。
今後、いろいろ使って紹介していきたいと思います。

モーター制御してみた

今回はDCモータをRaspberryPiで制御してみます。ミニ四駆でおなじみのFA130モータを用意しました。

DSC01529

DCモータの回転を制御しながら駆動させる回路にはトランジスタやFETを使ったフルブリッジ回路がよく使われます。今回はフルブリッジ回路が内蔵されているモータドライバIC TA7291P を使いました。

DSC01530

TA7291Pは小電力モータ用で内部にフルブリッジと保護回路が入っています。このICを使うとDCモータの「正転」、「逆転」、「ブレーキ」、「ストップ」、「電圧の制御」の制御がでます。このICで使えるモータの電流は平均0.4A、ピーク1.0A、モータ電圧は20Vまで、ICの電源は4.5Vから20Vです。
モータドライバICと電池、モータをつなぎます。画像では電池が入っていませんが、実験ではアルカリ単3乾電池を2本使用しました。

DSC01527

モータードライバICへの信号はすべてRaspberryHabuのデジタル出力につなぎます。TA7291Pの4ピンに電圧をかけたりPWM信号を送ることでモータの速度を調整できます。今回は電圧制御ではなくPWM信号を試します。ハードウェアPWMを使うのでRaspberryHabuのデジタル出力1ピンにICのモータ出力制御ピン(ICの4ピン)、モータ回転制御ピン(ICの5ピンと6ピン)はRaspberryHabuのデジタル出力2ピンと3ピンにつなぎます。ICの5ピンにLOW、6ピンにHIGHを入力すると正転、5ピンにHIGH、6ピンにLOWを入力すると逆転、両方にHIGHを入力するとブレーキ、両方にLOWを入力すると停止の信号を送ることができます。

DSC01528

とりあえず回すだけのプログラム。PWM信号は約50%(512)に設定しました。正転と逆転を切り替えるときに一度停止した状態を作らないと逆起電力で回路が壊れることがあるので注意です。

 // Licence CC 0 ( Public Domain )

#include "stdio.h"
#include "stdlib.h"
#include "wiringPi.h"

#define MOTORPWM 1
#define MOTOROUT1 2
#define MOTOROUT2 3

int main()
{
  if (wiringPiSetup() == -1)
    {
      printf("setup error!");
      exit(1);
    }
  pinMode(MOTOROUT1,OUTPUT);
  pinMode(MOTOROUT2,OUTPUT);
  pinMode(MOTORPWM,PWM_OUTPUT);

  digitalWrite(MOTOROUT1,0);
  digitalWrite(MOTOROUT2,0);
  digitalWrite(MOTORPWM,0);
  while(1){
    printf("foward\n");
    digitalWrite(MOTOROUT1,1);
    pwmWrite(MOTORPWM,512);
    sleep(5);
    pwmWrite(MOTORPWM,0);
    digitalWrite(MOTOROUT1,0);
    usleep(50000);
    printf("back\n");
    digitalWrite(MOTOROUT2,1);
    pwmWrite(MOTORPWM,512);
    sleep(5);
    pwmWrite(MOTORPWM,0);
    digitalWrite(MOTOROUT2,0);
    printf("STOP\n");
    sleep(5);
  }
  return 0;
}

DSC01531正転

DSC01532逆転

DSC01533停止

動きました。正転5秒、一瞬停止、逆転5秒、停止5秒の順で動いています。

モータ出力制御ピンに5V、モータ用電源に3.1Vの電圧をかけた場合、モータへの出力電圧は1.36Vでした。データシート(8p,左上の表)にもありますがIC内部ロスがあるため、モータ用電源はそのロスも加味したうえで決定する必要があります。

電池を直接モータにつなぎ可変抵抗などで電圧を変化させることで制御することもできますが、その場合電圧が下がるとトルクが小さくなるという欠点があります。TA7291Pを使って電圧で速度を制御する場合、制御端子にかける電圧とモータ用電源の電圧との差はIC内で熱に変換されるため、電圧差が大きければ大きいほどICの発熱が増えてしまうという欠点があるため制御用電圧はモーター電圧よりも少なくする必要があります。
それに対し、PWMで制御するとモータのトルクの変化が少ないことやモータとの電圧が少ないのでICの発熱も抑えることができるという利点があります。
いっぱい使えば、ロボットにも応用できます。無線を使えばラジコンカーも作れそうですね。

サーボモータを使ってみた-その1(softPWM編)

今回はサーボモータの制御をRaspberryHabuで試してみます。 用意したサーボモータは秋月電子通商で購入した台湾GWS社のPIC+F/BB/F(¥900)です。電圧は4.8から6V、トルクは0.79kg/cm(4.8V)から0.90kg/cm(6V)、スピードは0.12sec/60deg(4.8V)から0.10sec/60deg(6V)です。端子がフタバ配列(でっぱりのある端から白:PWM,赤:VCC,黒:GND)になっています。 DSC01516s 今回は白(PWM)をRaspberryHabuのデジタル出力1ピン、赤をVCC、黒をGNDにつなぎました。サーボにかかる負荷が大きい時や電圧を安定させたい場合は電源を別途用意することをおすすめします。 RaspberryPiで使えるPWMにはハードウェアで発生させる方法とソフトウェアで発生させる方法がありますが、今回はソフトウェアPWMを試します。

/*
servo-softpwm.c
Lisence CC0.
*/

#include "stdio.h"
#include "stdlib.h"
#include "wiringPi.h"


int main()
{
  if (wiringPiSetup() == -1)
    {
      printf("setup error!");
      exit(1);
    }
    softPwmCreate(0,0,100);
  while(1){
    softPwmWrite(0,70);
    printf("channel 0:pwm 50\n");
    sleep(2);
    softPwmWrite(0,10);
    printf("channel 0: pwm 10\n");
    sleep (2);
  }


今回はWiringPiライブラリの関数であるsoftPWMを使ってみました。 softPwmCreateでPWM出力の設定をし、spftPwmWriteで出力します。 DSC01517PWM出力10%時 DSC01518PWM出力70%時 動いているのがわかります。出力を0→100に変えていくと右回りに角度が変化します。 今後このサーボモータといろいろなセンサを組み合わせて試作をしていきたいと思います。

温度計作ってみた

今回は熱電対を使って温度計を作ってみます。

異なる2種類の金属線をつないで、二つの接した部分に温度差を与えると電圧が発生します。この現象をゼーベック効果といいます。熱電対とはこの現象を利用したセンサで、一端の温度が分かれば発生する電圧と既知の金属の特性からもう一方の接点の温度を求めることができます。

絶対的な温度を計る場合は熱電対の測定に使う接点を温接点、端子側を基準接点とし、その温度(基準接点温度)を測り測定点の温度を求める必要があります。基準接点温度を測定するときはサーミスタや測温抵抗体などを使います。

試作には秋月電子で購入したK型熱電対ステンレス管タイプを使いました。この熱電対は-200℃~+600℃の広範囲の温度を測定することができます。温度差1℃当たり約40.7μVの起電力が発生します。

RaspberryHabuのアナログポートに入力するには電圧変化が小さすぎるのでオペアンプで増幅します。一般的に信号を増幅するためによく使われるLM358では誤差が大きすぎるので今回は精度の高いオペアンプNJM2119Dの1回路分を使い、1kΩと100kΩの抵抗で100倍に増幅し、RaspberryHabuのアナログ1番ピンに入力しました。NJM2119Dは秋月電子で手に入ります。

2V2A6612

熱電対の端子は商品では樹脂の端子がついていますが、ブレッドボードに指すために分解してあります。ケーブルは単芯なので被膜を取るだけでブレッドボードにさせます。
写真は2か所の温度を計るため熱電対を2つ使い、2チャンネル分の回路を作っています。

熱電対の出力はアナログなのでRaspberryHabuBasicのアナログ入力ピンからMCP3008を通してSPIでRaspberryPiに入力します。
以下のコードはサーミスタも使い室温を出したうえで熱電対で測定した結果の温度差を足して計測対象の温度を出しています。

 // thermocouple.c sample program for RaspberryHABU
 // Licence CC 0 ( Public Domain )
 
 
 #include "stdio.h"
 #include "stdlib.h"
 #include "wiringPi.h"
 #include "unistd.h"
 #define SPIBUFFSIZE 256
 #define THERMISTORCHANNEL 7
 #define THERMISTOR 10000 // 10k ohm
 #define B 3380 // 
 #define DIVR 10000 // 10k ohm
 
 unsigned char spidata[SPIBUFFSIZE];
 int MCP3008Read( int channel ){
   int spireturn,data;
   spidata[0]= 1; 
   spidata[1]= ( 0x80 | channel << 4 )  ;
   spidata[2]= 0;
   spireturn = wiringPiSPIDataRW( 0, spidata , SPIBUFFSIZE );
   data = ((spidata[1]&3) << 8) + spidata[2];
 return(data);
 }
 
 int main()
 {
   int spiresult,spiresult7;
   double thermistor_r,baseTemp,TCTemp,t1;
   if ( -1 ==  wiringPiSPISetup(0,1000000) )
   {
     printf("SPI setup error!");
     exit(1);
   }
   while (1){
     spiresult7=MCP3008Read(THERMISTORCHANNEL);
     thermistor_r = ( DIVR * spiresult7 )/ (1024 -spiresult7 );  // thermistor is lower
     t1 =   log( thermistor_r / THERMISTOR ) ;
     baseTemp = ((298*B) / ( B + ( 298 * t1 ))) - 273;
   
     spiresult=MCP3008Read(0);
     TCTemp = (3.3/1024.0*(double)spiresult*1.010)/0.00407;
 
     printf("temp: %3.f c  (room temp: %3.f c : A0 value0 %d)\n",TCTemp+baseTemp,baseTemp,spiresult);
     sleep(10);
   }
 
 }

入力した値はAD変換され10bitのデータとしてRaspberryPiに入力されます。その値は3.3Vを10bit(1024)分割された値なので1Vあたりの数値を出し、それを40.7μVで割ることで温度差を出しています。NJM2119Dは5V電源を試用していますが、出力は4V程度までしか出ないため、1.01をかけて補正してあります。

上記のプログラムとは出力が違いますが、別の実験で熱電対と基準接点温度を測定するためにサーミスタを使ったときの出力結果は以下のようになりました。この実験ではコップのお湯の温度を測ってみました。

IMG_20140326_141717

今回使ったK型熱電対は対温度性が1250℃(樹脂の端子カバーを残して使う場合は600℃)と高いのでオーブン作ったりリフロー機作ったりできそうですね。

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

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