フォト
2024年9月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          
無料ブログはココログ

« グラフィック液晶 Nokia5110(PCD8544)で日本語フォント表示 | トップページ | aitendo 16x16LEDマトリックスの制御 (2) »

2016年5月29日 (日)

aitendo 16x16LEDマトリックスの制御 (1)

以前やった16x16LEDマトリックスの制御の再挑戦です。

今回はaitendo製のM1571616Cを使ってみました。

LEDドットマトリクス [M1571616C]
LEDマトリックス


実際の製品

Dscn5244

16x16 LEDマトリックスって意外と販売されていなくて、私の知る限り秋月電子と
aitendoしかないです。秋月電子のはブレッドボードに乗せたれない変なピン配置でしたが
aitendoのはストレートで使いやすいですね。

動作確認

Dscn5267

側面にRが明記されている方のPIN並びが1~16のようです(裏面ピン番号16,32が記載)。

下記が製品ページに公開されているピン割り付けです。

02

動作確認すると何か変です。
ブレッドボード上で1ピンを5V、17ピンにGND接続したらCOL1、ROW1が点灯しました。
アノードとカソードが逆っぽい。上の図は間違っているみたいです。
このあたりは、aitendoクォリティだから仕方ない。と諦めます^^

これで、ピンの割り付けが把握出来ました。

次にダイナミック駆動にて制御してみます。
以前作成したのもを修正しました。

ブレッドボード上に実装した様子
Dscn5255

上の写真の16x16LEDマトリックス、左側がピン1~ピン16、右側がピン17~ピン32となります。
また、黒いICがTB62706です。ピンピッチ変換の基板を利用しています。

動いている様子


全点の点灯チェック、パターン表示、向き確認するための漢字表示の動作テストです。
問題なしです(実際は、文字の鏡表示が発覚して配線を逆にしました)。

回路図

※回路図ではR1の抵抗、4.7kとなっていますが2.2kが正しいです。

03_2

利用部品
・TB62706   16ビットLEDドライバ
   シフトレジスタ兼LEDドライバみたいなやつです。抵抗1本で定電流量指定出来ます。
   ダイナミック駆動でカラム選択として利用しています(1ポートのみがセレクトされる)。
   また、シングとして定電流制御を行っています。

   このIC、DIP版が無くてSDIP(1.778mmピッチ)です。
   ピッチ変換基板を使ってブレッドボード上に乗せました。

・74HC595   8ビットシフトレジスタ
   おなじみのシフトレジスタです。連結して16ビット長で利用しています。
   表示パターンデータを流し込みます。
   1ピン当たり35mA、全体で75mA流せます。
   今回は各ICにつき同時に8ポート点灯(電流を流す)ので、1ポート当たり、
            75mA÷8 = 9.475mA 以下
   にする必要があります。取りあえず1ピン当たり8mAと決めます。

・2.2kΩ抵抗
   TB62706用の定電流制御に利用します。
   1つのLEDに流す電流を指定しています。
   TB62706の定電流制御で抵抗値の決定は下記の式を使います。
      IOUT = ( 1.26 / REXT) x 14.7

   今回はLEDに8mA(IOUT)流したいので、抵抗REXTはこの式より約2.2kΩとなります。

  TB62706、74HC595は同じインタフェースのシフトレジスタであるため、
  連結して利用しています。Arduinoからは4本の線で32ビットのデータを流し込んでいます。

スケッチ

Arduino IDE 1.6.9 を利用して作成しました。

MsTime2ライブラリによるタイマ割り込みを使ってLEDのダイナミック駆動を行っています。

  04

 バックグラウンド処理(タイマー割り込み)で表示用データ(uint16_t fbuf[16])の内容を
表示しています。10msec間隔で割り込みを発生し、そのタイミングで16x16ドットの
パターンを表示しています。割り込み処理中のみ、LEDを表示し割り込みを抜けると
LEDを消しています。

ダイナミック駆動の表示では、
  (1)1回の割り込みで1ライン表示し16回の割り込みで1画面分表示する方法
  (2)1回の割り込みで1画面(16ライン分)表示を行う方法

どちらでも人間の目の残像を利用して全画面表示しているように見えます。

(1)の場合は、1回の割り込み当たりの処理は少ない分、(2)より16倍早い周期で
割り込みを行う必要があります。また常に1ライン点灯出来るため(2)より明るいです。
(実際やってみると明るい。しかし1msec間隔で割り込みしないとチラつきました)

(2)の場合は、1回の割り込み当たりの処理が多い分、遅い周期で済みます。
1画面分16ライン表示後、全画面を消す必要があります。
(消さないと最後のラインだけが長い時間の点灯となり均等な点灯でなくなります)。
そのため、(1)より若干暗くなります。

どちらとも試して問題なく動作しましたが、今回は(2)の1回の割り込みで1画面分
表示することにしました。単位時間当たりの割り込み回数が少ない分、オーバーヘッド
にかかる処理が少なくなると考えました。

今後、他の割り込み処理やSPI、I2C通信との併用した場合、どちらが良いか
再度検討したいと思います(この文書いている途中で、(1)の方が良い気がしてきた.. OTZ)。

フォアグランド処理では、配列のパターンデータを表示用データに突っ込んでいます。

2016/05/30 追記
  やはり、1回の割り込みで1ライン描画の方が表示が良好です。
  ただし、1msec間隔での割り込みが必要で処理が追い付いていない感じです。

スケッチ: ダウンロード sample.zip (2.3K)

//
// aitendo 16x16LEDドットマトリックスの制御サンプル
// 2016/05/29 たま吉さん
//
#include <arduino.h>
#include <MsTimer2.h>
#include <string.h>

#define DATAPIN	   (7)	// TB62706のSERIAL-INへ
#define LATCHPIN   (9)	// TB62706のLATCHへ
#define CLOCKPIN  (8)	// TB62706のCLOCKへ
#define ENABLEPIN  (6)  // TB62706のENABLEへ

uint16_t fbuf[16];    // 表示パターンバッファデータ

// 文字データ "こんにちは埼玉県"
uint16_t fnt[11][16]= {
 {// ""
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff },
  {// こ
  0x0000,0x0000,0x1ff8,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x2000,0x3000,0x1c00,0x07fc,0x0000,0x0000 },
 {// ん
  0x0200,0x0200,0x0600,0x0400,0x0c00,0x0800,0x0800,0x1b80,
  0x1440,0x1840,0x3040,0x2042,0x2046,0x604c,0x4038,0x0000 },
 {// に
  0x0000,0x1000,0x1000,0x31fc,0x2000,0x2000,0x2000,0x2000,
  0x2000,0x2000,0x2200,0x2200,0x2b00,0x31fe,0x1000,0x0000 },
 {// ち
  0x0100,0x0100,0x0100,0x7ffc,0x0200,0x0600,0x0400,0x0ff0,
  0x1808,0x3004,0x0004,0x0004,0x000c,0x0038,0x07e0,0x0000 },
 {// は
  0x0000,0x2020,0x2020,0x6020,0x47fe,0x4020,0x4020,0x4020,
  0x4020,0x4020,0x43e0,0x4438,0x542c,0x6466,0x23c0,0x0000 },
 {// 埼
  0x2020,0x2020,0x23fe,0x2050,0xf8d8,0x218c,0x2000,0x27ff,
  0x2004,0x21e4,0x3924,0x6124,0xc124,0x01e4,0x0004,0x001c},
 {// 玉
  0x0000,0x7ffe,0x0100,0x0100,0x0100,0x0100,0x0100,0x3ffc,
  0x0100,0x0100,0x0118,0x010c,0x0104,0x0100,0xffff,0x0000 },
 {// 県
  0x07f8,0x2408,0x2408,0x27f8,0x2408,0x2408,0x27f8,0x2408,
  0x2408,0x27f8,0x2000,0x3fff,0x0888,0x188c,0x7087,0x0080 },
 {// ブランク
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 },
 {// 格子
  0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,
  0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555 }
};

//
// 行の指定
//
void selectRow(byte no) {
    uint16_t val = _BV(15-no);

    // ビット列データの出力
    for( byte i = 0; i < 16; i++ ){
      digitalWrite(DATAPIN, val & _BV(i) ? 1:0);			
      digitalWrite(CLOCKPIN, HIGH);
      digitalWrite(CLOCKPIN, LOW);
    }
}

//
// 行フォントパターンの送信
//
void dataOut(uint16_t val ) {       
	for( uint8_t i = 0; i <16; i++ ){					
    digitalWrite(DATAPIN, val & _BV(i) ? 1:0);      
		digitalWrite(CLOCKPIN, HIGH);
		digitalWrite(CLOCKPIN, LOW);
	}
}

//
// バッファ内データを表示する
//
void fontout() {
    // 点灯LEDが移動するパターン
    digitalWrite(ENABLEPIN,LOW);            // OUTを有効にする
    for( byte i = 0; i < 16; i++ ) {
       digitalWrite(LATCHPIN, LOW);		//送信開始        
       selectRow(i);            
       dataOut(fbuf[i]);
       digitalWrite(LATCHPIN, HIGH);		//送信開始        
     }
    digitalWrite(ENABLEPIN,HIGH);            // OUTを無効にする
}

//
// バッファにフォントパターンをセット
//
void setfont(uint16_t* fptr) {
  memcpy(fbuf, fptr, 32);  
}

//
// バッファ内の指定座標に点をセット
//
void setdot(uint8_t x, uint8_t y, byte dot) {
  fbuf[y] = dot ? fbuf[y]| (0x8000>>x): fbuf[y] & ~(0x8000>>x); 
}

void testdotset() {
  for (byte y=0; y<16; y++) {
    for (byte x=0; x<16; x++) {
      setdot(x,y,1);
      delay(10);
    }
  }
  for (byte y=0; y<16; y++) {
    for (byte x=0; x<16; x++) {
      setdot(x,y,0);
      delay(10);
    }
  }
}

//
// 指定座標にフォントパターンをセット
//
void setfontat(uint16_t* fptr, uint8_t x, uint8_t y) {
  uint16_t w;
  
  if (x>15 || y >15)
    return;     
  for (byte j=y,i=0; j < 16; j++,i++)
    fbuf[j] = (fbuf[j]>>(16-x))<<(16-x) | fptr[i]>>x;
}

void test01() {
  for (byte i=0; i <11; i++) {
    for (byte x=15; x > 0; x--) {
      setfontat(fnt[i],0,x);
      delay(20);
    }
  }
}

//
// ドット表示チェック(デバッグ用)
//
void dottest() {
  for (byte y=10; y < 11;y++) 
    for (byte x=0;x <16;x++) {
      fbuf[y]= 0x8000>>x;
     delay(50);
      fbuf[y]= 0;
    }        
}

//
// バッファーデータのスクロール
// h_mode : 0 なし,1 左 ,2 右 
// v_mode : 0 なし,1 上, 2 下      
//
void scroll(uint8_t h_mode, uint8_t v_mode) {
  if (h_mode ==1) 
    for (byte i = 0; i < 16; i++) 
      fbuf[i] = fbuf[i]<<1;
  if (h_mode ==2)
    for (byte i = 0; i < 16; i++)
      fbuf[i] = fbuf[i]>>1;
  if (v_mode ==1) {
    for (byte i = 0; i < 15; i++)
     fbuf[i]= fbuf[i+1];
    fbuf[15]=0;
  }
  if (v_mode == 2) {
    for (byte i = 15; i >0; i--)
     fbuf[i]= fbuf[i-1];
    fbuf[0] = 0;    
  }
}

// スクロールテスト
void test02() {
    byte i;
    setfont(fnt[6]);
    for (i=0; i<16;i++) { 
      scroll(1,0);
      delay(50);
    }
    delay(200);

    setfont(fnt[6]);
    for (i=0; i<16;i++) { 
      scroll(2,0);
      delay(50);
    }
    delay(200);

    setfont(fnt[6]);
    for (i=0; i<16;i++) { 
      scroll(0,1);
      delay(50);
    }
    delay(200);
        
    setfont(fnt[6]);
    for (i=0; i<16;i++) { 
      scroll(0,2);
      delay(50);
    }
    delay(200);
   
    setfont(fnt[6]);
    for (i=0; i<16;i++) { 
      scroll(1,1);
      delay(50);
    }
    delay(200);

    setfont(fnt[6]);
    for (i=0; i<16;i++) { 
      scroll(2,2);
      delay(50);
    }
    delay(200);
}

//
// スクロールしながらパターンを表示
//
void setfontscl(uint16_t* fptr, uint16_t dly) {
  for (byte i=0; i<16; i++) {
    scroll(1, 0);
    setfontat(fptr, 15-i, 0) ;
    delay(dly);
  }
}  

void setup() {
    pinMode(ENABLEPIN,OUTPUT);
    pinMode(DATAPIN, OUTPUT);
    pinMode(LATCHPIN, OUTPUT);
    pinMode(CLOCKPIN, OUTPUT);

    digitalWrite(ENABLEPIN,HIGH);
    digitalWrite(CLOCKPIN, LOW);
    digitalWrite(LATCHPIN, HIGH);
 
     digitalWrite(ENABLEPIN,LOW);         // OUTを有効にする
     digitalWrite(ENABLEPIN,HIGH);        // OUTを無効にする

     setfont(fnt[9]); // フォントバッファに初期パターン設定 
     
     // 割り込み開始
     MsTimer2::set(10, fontout); // 1/60秒程度で1文字を表示 
     MsTimer2::start();
     setdot(0,0,1);
}

void loop(){
  testdotset();  // ドット単位アクセス表示
  test02() ;     // スクロールテスト

  // 配列格納文字パターンを順番に表示する
  for (byte i =0; i < 11; i++)
    setfontscl(fnt[i],40);
}


以前よりも、あっさりと回路が簡略化出来ました。 以前の回路、縦横変えれば
トランジスタアレイは不要でしたね。なんておバカさんなことをしていたのでしょう。

消費電力の検証

消費電力の測定のためArduinoから表示部に流れ込む電流を測定してみました。

Dscn5272_2

最大で14.4mAでした。電圧は5Vなので消費電力は72mWとなります。
256点点灯の割には意外と少ないですね。
(最初 「瞬間的に最大16個点灯だから、8mA x 16 = 128mAのはずでは?おかしい!」と
おバカな勘違いをしていました。定電流制御でシンク1ライン8mAを流しているのに.. OTZ)

その2に続きます...

« グラフィック液晶 Nokia5110(PCD8544)で日本語フォント表示 | トップページ | aitendo 16x16LEDマトリックスの制御 (2) »

arduino」カテゴリの記事

表示器制御関連」カテゴリの記事

コメント

こんにちは。昔の内容で恐縮です、覚えていたら教えていただきたいのですが、
本記事を参考に回路配線しましたら、鏡文字になりました。
記事の中で配線を入れ替えたとありますが、TB62706の配線を1-16を入れ替えれば良いでしょうか?

ソフトで対応できないか考えましたが、列と行を順番に制御しているようなので、混乱しました(笑)

まっちさん

ソフトの方で対応できると思います。
ビットデータは、下位ビット(0~)から送信しているので、
下記の処理を上位ビットからの送信するように修正すれば良いと思います。


// 行フォントパターンの送信
void dataOut(uint16_t val ) {
for( uint8_t i = 0; i <16; i++ ){
digitalWrite(DATAPIN, val & _BV(i) ? 1:0);
digitalWrite(CLOCKPIN, HIGH);
digitalWrite(CLOCKPIN, LOW);
}
}

試していませんが、上記の
digitalWrite(DATAPIN, val & _BV(i) ? 1:0);

digitalWrite(DATAPIN, val & (0x8000>>i) ? 1:0);
で行けるかもです。

1年越しですが、試してみましたら、ご教授の通りで反転できました。
遅くなりましたが、ありがとうございました!

まっちさん

ご報告ありがとうございます.
問題が解決されてなによりです.

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: aitendo 16x16LEDマトリックスの制御 (1):

« グラフィック液晶 Nokia5110(PCD8544)で日本語フォント表示 | トップページ | aitendo 16x16LEDマトリックスの制御 (2) »