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


前回、16チャンネルLED専用ドライバーのTLC5940を 使って8セグメントLEDを表示する方法を紹介しました。
このチップはそもそもPWMを使ってLEDの明るさを制御するためのチップです。
そこで、今回はPWM機能を使って8セグメントLEDの明るさを制御してみます。
結線は前回と同じです。

ソースコードは以下の通りです。
前回から変更したのは赤字の部分です。

TLC5940のPWM機能は4095回のパルスの中で、何%の割合でLEDを光らせるかを指定します。
ソースコードの中で「bright=0xfff」とすれば、4095回のパルスの中でLEDが4095回光りますので
明るさは 4095/4095*100=100% となります。
「bright=0x7ff」とすれば、4095回のパルスの中でLEDが2047回光りますので
明るさは 2047/4095*100=50% となります。

/*

 tlc5940.c
 
 Raspberry Pi PWM 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(GSCLK);
    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, unsigned short bright)
{
  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;
      gsdata[segment] = bright;
    else
      gsdata[segment] = 0x0;
  }
}

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

  for (digit = 0 ; digit < Digs; ++digit) {
    digitalWrite (D0 + digit, 1) ;
    c1 = digits [digit] ;
    DisplayDigit(c1,gsdata,bright);
    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];
  unsigned short bright;

  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");
  bright=0xfff;
  for(i=0;i<4095;i++){
    DisplayDigits(digits,gsdata,bright--);
  }

  strcpy(digits,"ABC");
  bright=0xfff;
  for(i=0;i<4095;i++){
    DisplayDigits(digits,gsdata,bright--);
  }

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

  exit(0);
}

次回は汎用の定電流LEDドライバーのDM13Aを紹介します。