Ryosuke Nakagawaのブログ

まなびをシェア

HUB75規格を深掘りしてみる

前回記事の紹介

前回の記事でLEDマトリックスディスプレイのデモを紹介しました. ryosukeeeee.hatenablog.com

このLEDディスプレイに使われているHUB75という規格について解説します.

HUB75規格

HUB75には16本のピンがあります. 説明のためにピンを3つのグループにわけます.

グループ名 ピン
Addr ピンA,ピンB,ピンC,ピンD
LED ピンR1,ピンG1,ピンB1,ピンR2,ピンG2,ピンB2
Utils ピンCLK,ピンLAT,ピンOE,ピンGND※

※GNDのみ3本ある

Addrはセクションの指定に用います.セクションについては後述します.

LEDは該当するLEDの色を指定するために用います.

Utilはその他の命令を送るために用います.もちろん,ピンGNDは接地です.

説明用の図

私が購入したこの商品を例にとりあげて説明します. 縦横のLEDの数は商品によって異なります. ディスプレイを使うときはデータシートを確認しましょう.

この商品は横64列,縦32行のLEDが並んでいます. 説明のためにすべてのLEDに下の図のように番号を振ります. 例えば,上から5行目,左から3列目のLEDは5-3と表記することにします. f:id:ryosukeeeee:20190429221535p:plain

Fig 1. 64列32行のLEDマトリックスディスプレイ

Addrグループの役割

すべてのLEDを同時に点灯することはできません. なのでいくつかのセクションに分割し,人間の眼では認識できないほどの短い時間で点滅させるセクションを切り替えることでディスプレイ全体に映像を映し出します. すなわち,同時に点灯しているのは1つのセクションです.

この商品は2行分のLEDを1つのセクションを構成します. 全部で32行あるので16つのセクションに分けられます. 具体的には,

1,17行でセクション1,

2.18行でセクション2,

3.19行でセクション3,

・・・

16,32行でセクション16 といった具合です.

Addrグループのピンは点灯させるセクションを選択するために用いらます.

ABCDの4ビットでセクションを指定します.

LEDグループの役割

フルカラーのディスプレイなので,RGBのLEDのON・OFFを指定する必要があります.

R1,G1,B1で上半分側のLEDの色を指定します.

R2,G2,B2で下半分側のLEDの色を指定します.

加法混合になるので,RGB全部点灯すると白になります.

ja.wikipedia.org

Utilグループの役割

ピンCLK,ピンLAT,ピンOEの役割は実際のコードを見てもらったほうがわかりやすいのでCのコードをみてください

gpio.h

/* -*- coding: utf-8 -*- */
#ifndef GPIO
#define GPIO

// ピン番号に名前をつける
#define pinA 22
#define pinB 23
#define pinC 24
#define pinD 25
#define pinR1 11
#define pinR2 8
#define pinG1 27
#define pinG2 9
#define pinB1 7
#define pinB2 10
#define pinClock 17
#define pinOE 18
#define pinStrobe 4

// アドレスから特定のビットをとりだすビットマスク
#define addressA 0b0001
#define addressB 0b0010
#define addressC 0b0100
#define addressD 0b1000

void setup(void);

void allPinLow(void);

#endif

gpio.c

/* -*- coding: utf-8 -*- */
#include "gpio.h"
#include <stdio.h>
#include <wiringPi.h>

// GPIOの初期設定.すべてのピンを出力で使う.
void setup(void) {
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
  pinMode(pinD, OUTPUT);
  pinMode(pinR1, OUTPUT);
  pinMode(pinR2, OUTPUT);
  pinMode(pinG1, OUTPUT);
  pinMode(pinG2, OUTPUT);
  pinMode(pinB1, OUTPUT);
  pinMode(pinB2, OUTPUT);
  pinMode(pinClock, OUTPUT);
  pinMode(pinOE, OUTPUT);
  pinMode(pinStrobe, OUTPUT);

  printf("setup done\n");
}

// すべてのピンをLowにする
void allPinLow(void){
  digitalWrite(pinA, 0);
  digitalWrite(pinB, 0);
  digitalWrite(pinC, 0);
  digitalWrite(pinD, 0);
  digitalWrite(pinR1, 0);
  digitalWrite(pinR2, 0);
  digitalWrite(pinG1, 0);
  digitalWrite(pinG2, 0);
  digitalWrite(pinB1, 0);
  digitalWrite(pinB2, 0);
  digitalWrite(pinClock, 0);
  digitalWrite(pinOE, 0);
  digitalWrite(pinStrobe, 0);

  printf("all pin low\n");
}

main.c

/* -*- coding: utf-8 -*- */
#include <wiringPi.h>
#include <stdio.h>
#include "gpio.h"

 // ディスプレイの横幅
#define DISPLAY_WIDTH 64
 // for文を繰り返す回数.点灯時間に相当する.大きい値にすれば点灯する時間が長くなる
#define LOOPSIZE 1000000

int main(void) {
  int i, j, address;

  if(wiringPiSetupGpio() == -1) return 1;
  setup(); //GPIOの初期設定をする
  allPinLow(); //一度すべてのピンをLowにする

  for (j = 0; j < LOOPSIZE; j++) {
    address = j % 16; // jを16で割ったときの余り.0から15までの値をとる.

 // ディスプレイの横幅と同じ回数繰り返す
    for (i = 0; i < DISPLAY_WIDTH; i++) {
      // R1, G1, B1, R2, G2, B2に値を設定する.
      // iは列に相当する.

      //  試しに上半分は赤にする
      digitalWrite(pinR1, 1);
      // digitalWrite(pinG1, 1);
      // digitalWrite(pinB1, 1);

      // 下半分は緑にする
      // digitalWrite(pinR2, 1);
      digitalWrite(pinG2, 1);
      // digitalWrite(pinB2, 1);

      // pinClockをHighにすると,そのときのグループLEDの値がキャプチャされる
      digitalWrite(pinClock, 1);
      // 次に備えてLowにする
      digitalWrite(pinClock, 0);
    }
    
    // 前のセクションから移るためにLEDをオフにする
    digitalWrite(pinOE, 1);
    
    // どのセクションにデータを書き込むか設定する.
    digitalWrite(pinA, address & addressA);
    digitalWrite(pinB, address & addressB);
    digitalWrite(pinC, address & addressC);
    digitalWrite(pinD, address & addressD);

    // データがそろったのでLEDを光らせる
    digitalWrite(pinStrobe, 1);
    
    // 次に備えてLowにする
    digitalWrite(pinStrobe, 0);

    //  次に備えてLowにする
    digitalWrite(pinOE, 0);
  }

  allPinLow();
  return 0;
}

wiringPiを使ってるので-lwiringPiをつけてコンパイルします.

gcc -o main main.c gpio.c -lwiringPi

以下のコマンドで実行すると,ディスプレイが点灯します.

sudo ./main

ドット欠けしてますが,こんな風になるはず. f:id:ryosukeeeee:20190511152042j:plain

特定の列のLEDだけを点灯してみます. main.cを一部変更します.

main.c(一部抜粋)

 // ディスプレイの横幅と同じ回数繰り返す
    for (i = 0; i < DISPLAY_WIDTH; i++) {
      // R1, G1, B1, R2, G2, B2に値を設定する.
      // iは列に相当する.
      if (i == 1 || i == 5 || i == 35) {
        digitalWrite(pinR1, 1);
        digitalWrite(pinG2, 1);
      } else {
        digitalWrite(pinR1, 0);
        digitalWrite(pinG2, 0);
      }

      // Clock High
      digitalWrite(pinClock, 1);
      // Clock Low
      digitalWrite(pinClock, 0);
    }

2列目,6列目,36列目のLEDが点灯してます. f:id:ryosukeeeee:20190511152036j:plain

特定の行のLEDだけを点灯してみます.

main.c(一部抜粋)

 // ディスプレイの横幅と同じ回数繰り返す
    for (i = 0; i < DISPLAY_WIDTH; i++) {
      if (address == 3 || address == 15) {
        digitalWrite(pinR1, 1);
        digitalWrite(pinG2, 1);
      } else {
        digitalWrite(pinR1, 0);
        digitalWrite(pinG2, 0);
      }
      // Clock High
      digitalWrite(pinClock, 1);
      // Clock Low
      digitalWrite(pinClock, 0);
    }

4行目,16行目,20行目,32行目のLEDが点灯してます. f:id:ryosukeeeee:20190511152028j:plain

ソースコードGithubにあげました. github.com

参考資料

LEDドットマトリクスパネル HUB75規格について調べてみた - Qiita

https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf

https://learn.adafruit.com/32x16-32x32-rgb-led-matrix/how-the-matrix-works