アノードコモンの8セグメントLEDへ表示する(TLC5940を使う)


今回は16チャンネルLED専用ドライバーのTLC5940を 使って8セグメントLEDを表示する方法を紹介します。
このチップは8セグメントLED専用ではなく、そもそもPWMを使って16個のLEDの明るさを制御するためのチップですが、
無理やり8セグメントLEDで使ってみます。

以下のページで使い方が紹介されています。
http://asumism.hatenablog.com/entry/2013/09/27/014202
http://garretlab.web.fc2.com/arduino/lab/led_driver/index.html

いずれもArduinoでの使い方が紹介されていますが、逆に言うとRaspberryでの使い方を紹介したページは
英語のページを含めてほとんど見つけられませんでした。





結線は以下の通りです。
20番ピン(IREF)とGNDの間には、「逆方向電流」制限用の抵抗を挟んで使用し ます。
最初はてっきりカソードコモンのLEDで使える(つまりOUTnには2Vとか3Vが出力される)と思っていたのですが
以下のページの回路図を見てアノードコモン用であることに気が付きました。
http://tronixstuff.com/2013/10/21/tutorial-arduino-tlc5940-led-driver-ic/

使用する抵抗値は以下の式で求めます。
R=1.24/逆方向電流*31.5
私は2KΩの抵抗を使いましたので、逆方向電流として20mAぐらいが流れるはずです。

TLC5940ピン番号 LEDへの接続(ピン番号) Raspberryへの接続(ピン番号)
1(OUT1) Segment b
2(OUT2) Segment c
3(OUT3) Segment d
4(OUT4) Segment e
5(OUT5) Segment f
6(OUT6) Segment g
7(OUT7) Segment D.P
8(OUT8)

9(OUT9)

10(OUT10)

11(OUT11)

12(OUT12)

13(OUT13)

14(OUT14)

15(OUT15)

16(XERR)

17(SOUT)

18(GSCLK)
18(GPIO24)
19(DCPRG)
3.3V
20(IREF)
2KΩの抵抗を介してGNDに接続
21(VCC)
3.3V
22(GND)
GND
23(BLANK)
16(GPIO23)
24(XALT)
15(GPIO22)
25(SCLK)
11(GPIO17)
26(SIN)
12(GPIO18)
27(VPRG)
13(GPIO27)
28(OUT0) Segment a

このチップは汎用の定電流LEDドライバーなので、Segment制御しかできません。
複数桁のLEDを使う場合、桁の制御は独自に行う必要があります。
桁の制御としては以下のピンを使います。
いずれのピンも電流制限用に100オームの抵抗を挟んでいます。
LEDへの接続(ピン番号) Raspberryへの接続(ピン番号)
Digit 3 Common 100Ω抵抗-24(GPIO8)
Digit 2 Common 100Ω抵抗-26(GPIO7)
Digit 1 Common 100Ω抵抗-19(GPIO10)

ソースコードは以下の通りです。

/*

 tlc5940.c
 
 Raspberry Pi driving the TLC5940

 to compile : cc tlc5940.c -o tlc5940 -lwiringPi


*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <wiringPi.h>

#define    SCLK    0
#define    SIN       1
#define    VPRG    2
#define    XLAT    3
#define    BLANK    4
#define    GSCLK    5

#define Digs    3
#define D0      10

int firstCycleFlag=1;

static const uint8_t segmentDigits [] =
{
// a  b  c  d  e  f  g  p       Segments
// 0  1  2  3  4  5  6  7       wiringPi pin No.
   1, 1, 1, 1, 1, 1, 0, 0,      // 0
   0, 1, 1, 0, 0, 0, 0, 0,      // 1
   1, 1, 0, 1, 1, 0, 1, 0,      // 2
   1, 1, 1, 1, 0, 0, 1, 0,      // 3
   0, 1, 1, 0, 0, 1, 1, 0,      // 4
   1, 0, 1, 1, 0, 1, 1, 0,      // 5
   1, 0, 1, 1, 1, 1, 1, 0,      // 6
   1, 1, 1, 0, 0, 0, 0, 0,      // 7
   1, 1, 1, 1, 1, 1, 1, 0,      // 8
   1, 1, 1, 1, 0, 1, 1, 0,      // 9
   1, 1, 1, 0, 1, 1, 1, 0,      // A
   0, 0, 1, 1, 1, 1, 1, 0,      // b
   1, 0, 0, 1, 1, 1, 0, 0,      // C
   0, 1, 1, 1, 1, 0, 1, 0,      // d
   1, 0, 0, 1, 1, 1, 1, 0,      // E
   1, 0, 0, 0, 1, 1, 1, 0,      // F
   0, 0, 0, 0, 0, 0, 0, 0,      // blank
} ;

static void TLC5940pulse(int port)
{
  digitalWrite(port,HIGH);
  digitalWrite(port,LOW);
}

static void TLC5940sendDC(unsigned char * dcdata)
{
  int i,j;
  int pos;
  unsigned char wk[16];
  unsigned int mask;

  pos=15;
  for(i=0;i<16;i++) {
    wk[pos--]=dcdata[i];
  }

  digitalWrite(VPRG,HIGH);
  digitalWrite(XLAT,LOW);
  for(i=0;i<16;i++) {
    for(j=6;j>0;j--) {
      mask=1<<(j-1);
      if (wk[i] & mask)
        digitalWrite(SIN, 1);
      else
        digitalWrite(SIN, 0);
      TLC5940pulse(SCLK);
    }
  }
  TLC5940pulse(XLAT);
}

static void TLC5940sendGS(unsigned short * gsdata)
{
  int i,j;
  int pos;
  unsigned short wk[16];
  unsigned int mask;


  pos=15;
  for(i=0;i<16;i++) {
    wk[pos--]=gsdata[i];
  }

  digitalWrite(VPRG,LOW);
  digitalWrite(XLAT,LOW);
  for(i=0;i<16;i++) {
    for(j=12;j>0;j--) {
      mask=1<<(j-1);
      if (wk[i] & mask)
        digitalWrite(SIN, 1);
      else
        digitalWrite(SIN, 0);
      TLC5940pulse(SCLK);
      TLC5940pulse(GSCLK);
    }
  }

  digitalWrite(BLANK,HIGH);
  TLC5940pulse(XLAT);
  digitalWrite(BLANK,LOW);

  if (firstCycleFlag) {
    TLC5940pulse(SCLK);
    firstCycleFlag=0;
  }
}


static void TLC5940feedPorts(int cnt)
{
  int loop;
  int i;

  for (loop=0;loop<cnt;loop++) {
    TLC5940pulse(BLANK);
    for(i=0;i<4096;i++){
      TLC5940pulse(GSCLK);
    }
  }
}

static void DisplayDigit (char digit, unsigned short* gsdata)
{
  int i;
  uint8_t segment ;
  uint8_t index, d, segVal ;

  d = toupper (digit) ;
  if ((d >= '0') && (d <= '9'))        // Digit
    index = d - '0' ;
  else if ((d >= 'A') && (d <= 'F'))        // Hex
    index = d - 'A' + 10 ;
  else
    index = 16 ;                          // Blank

  for (segment = 0 ; segment < 8 ; ++segment) {
    segVal = segmentDigits [index * 8 + segment] ;
    if(segVal)
      gsdata[segment] = 0xfff;
    else
      gsdata[segment] = 0x0;
  }
}

static void DisplayDigits (char* digits, unsigned short* gsdata)
{
  uint8_t digit ;
  char    c1 ;

  for (digit = 0 ; digit < Digs; ++digit) {
    digitalWrite (D0 + digit, 1) ;
    c1 = digits [digit] ;
    DisplayDigit(c1,gsdata);
    TLC5940sendGS(gsdata);
    TLC5940feedPorts(1);
    digitalWrite (D0 + digit, 0) ;
  }
}

main(){
  int i,j;
  unsigned char dcval;
  unsigned int gsval;
  unsigned char dcdata[16];
  unsigned short gsdata[16];
  char digits[8];

  if (wiringPiSetup () == -1) exit(1);

  pinMode(SCLK, OUTPUT);
  pinMode(SIN, OUTPUT);
  pinMode(VPRG, OUTPUT);
  pinMode(XLAT, OUTPUT);
  pinMode(BLANK, OUTPUT);
  pinMode(GSCLK, OUTPUT);

  digitalWrite(SCLK,LOW);
  digitalWrite(XLAT,LOW);
  digitalWrite(BLANK,HIGH);
  digitalWrite(GSCLK,LOW);

  for(i=0;i<Digs;i++) {
    pinMode(D0+i, OUTPUT);
    digitalWrite(D0+i, 0);
  }

//Send DC Data
  dcval=0x0f;
  for(i=0;i<16;i++){
    dcdata[i]=dcval;
  }
  TLC5940sendDC(dcdata);

//Clear GS Data
  gsval=0x0;
  for(i=0;i<16;i++){
    gsdata[i]=gsval;
  }

//Set GS Data
  strcpy(digits,"123");
  for(i=0;i<1000;i++) DisplayDigits(digits,gsdata);

  strcpy(digits,"ABC");
  for(i=0;i<1000;i++) DisplayDigits(digits,gsdata);

  digitalWrite(SCLK,LOW);
  digitalWrite(XLAT,LOW);
  digitalWrite(BLANK,LOW);
  digitalWrite(GSCLK,LOW);

  exit(0);
}

このチップは出力が16ポート有るので、1つのチップで2個の8セグLEDを制御することができます。
8セグLEDを2個制御する場合、2番目のLEDはOUT8から15を使います。

次回はこのチップの最大の特徴であるPWM機能の使い方を紹介します。