勝手な電子工作・・

勝手なオリジナル電子工作に関する記事を書きます

TM1637-LEDをライブラリーなしで簡単表示

f:id:a-tomi:20200725160057j:plain

4桁の7セグメントLEDを直接ダイナミック点灯する場合は、少なくとも11本以上のピンを使います。このTM1637というICを用いたディスプレイなら2ピンしか使わずにすみ、見やすく廉価。色々な機会にこれを使っていますが、使い方を質問されることが結構多い部品です。

外出自粛の週末ですが、おまけにすごい雨です。こういう機会に、ごく簡単ですがこれの要点と簡単なプログラムの例を書いておこうと思います。

次の写真は10年ほど前にPCの元電源オン表示の代わりとして、ちょこっと作ってみた温湿度計です。8ピンマイコンで作りましたが今でも明るく動いています。8ピンなのに温湿度センサーの他に、明るさ表示変更用のボタンなどもつけています。

f:id:a-tomi:20200725161457j:plain

TM1637というICはずいぶん前に出たものですが、最初の頃はとくにライブラリーもなく、中国語のデータシートしかなくて苦労しましたが、その後は文書類もLED用のライブラリーなども整ったので世界で普及したと思います。

第一に4桁LED+TM1637IC込みで値段が1ドル程度と圧倒的に安いし、Duty比が可変で電流消費も少なくできたり、接続やプロトコルがシンプルだったり。7セグメントが自由自在(これはあたりまえか^^;)。

とはいえ、デバイス1つ毎にIOピンを2つも(!?)使うので、本当はI2C接続のものが欲しかったわけですが、最近になってHT16K33+4桁LEDのモジュールが出回り始めたので早速注文中。単価はこの約3倍ほどします。そのうちに記事で紹介したいと思いますが。

TM1637を用いた4桁LED表示器の種類(大きさ、表示色、コロンとピリオドの有無など)は色々あります。

f:id:a-tomi:20200725161853j:plain

今eBayを覗いてみると、現時点はコロナの影響もあって送料がかかるものが多く少々高いかもしれませんが、それなりに経済的。

f:id:a-tomi:20200725161946j:plain

Arduinoとは試作では例えば次のようにつなぎます。

f:id:a-tomi:20200725162137j:plain

各7セグメント表示用のデータは次の形のバイナリー形式です。

f:id:a-tomi:20200725162504j:plain

pで示したものはピリオドだけの場合もコロンだけの場合もありますが、両方表示できても予めハードウェア回路で固定され、変更できないものが殆どです。ちなみにピリオドだけのは次のもの。写真がちょっとぼけていてすみませんが。

f:id:a-tomi:20200725162718j:plain

Arduinoでプログラムを組むときは、今ではTM1637用ライブラリー(例えばTM1637Display)が数種類揃っています。しかし、ライブラリーの使い方を確認するのが面倒なら、必要な機能だけを自分でコーディングしてもこのデバイスなら比較的単純にできます。例えば次です。

/* *********************************************************
   Simple roll-your-own TM1637 operations without library
      Sample sketch V00  July 25, 2020 (c) Akira Tominaga 
 *  ********************************************************/
#define lDIO 6              	// DIO for TM1637 LED
#define lCLK 7              	// CLK for TM1637 LED
#define lBrt 0x02           	// duty-r 1/16x 02:4,03:10,05:12,07:14
#define lTu 50              	// time unit in micro-second
byte lChr;                  	// single byte sent to LED
byte Data[] = { 0x00, 0x00, 0x00, 0x00 }; // LED initial value 0000

void setup() { // ***** Arduino setup *****
  pinMode(lCLK, OUTPUT);
  pinMode(lDIO, OUTPUT);
  digitalWrite(lCLK, HIGH);
  digitalWrite(lDIO, HIGH);
  lDispData();              	// display 0000
  delay(1000);
}

void loop() { // ****** Arduino Loop *****
  // example 
  for (int k = 0; k < 4; k++) {
    uint8_t Rand = random(0, 15);
    Data[k] = Rand;
  }
  lDispData();
  delay(1000);
}

/**************************************
      User defined functions
* *********************************** */
// *** lDispData *** display data to 4dig LED
void lDispData(void) {
#define showDat 0x40          	// show this is data
#define showAd0 0xC0          	// LED data addr is zero
#define showDcB 0x88+lBrt     	// show dCtl + brightness
  lStart();                   	// start signal
  lChr = showDat;             	// identifier for data
  lSend();                    	// send it
  lStop();                    	// stop signal
  lStart();                   	// and restart
  lChr = showAd0;             	// identifier for address
  lSend();                    	// send it
  for (int j = 0; j < 4; j++) { // for Data[0] to Data[3]
    byte edChr = Data[j];     	// set a byte to edChr for edit
    switch (edChr) { 
      case 0x00: lChr = 0x3F; break; // 0
      case 0x01: lChr = 0x06; break; // 1
      case 0x02: lChr = 0x5B; break; // 2
      case 0x03: lChr = 0x4F; break; // 3
      case 0x04: lChr = 0x66; break; // 4
      case 0x05: lChr = 0x6D; break; // 5
      case 0x06: lChr = 0x7D; break; // 6
      case 0x07: lChr = 0x07; break; // 7
      case 0x08: lChr = 0x7F; break; // 8
      case 0x09: lChr = 0x6F; break; // 9
      case 0x0A: lChr = 0x77; break; // A
      case 0x0B: lChr = 0x7C; break; // b
      case 0x0C: lChr = 0x39; break; // C
      case 0x0D: lChr = 0x5E; break; // d
      case 0x0E: lChr = 0x79; break; // E
      case 0x0F: lChr = 0x71; break; // F
      case 0x10: lChr = 0x00; break; // blank
      default:   lChr = 0x7B;        // e for error
    }
    lSend();                    // send each byte continuously
  }                             // end of four bytes
  lStop();                      // stop signal
  lStart();                     // restart
  lChr = showDcB;               // identifier for display brightness
  lSend();                      // send it
  lStop();                      // stop signal
}

// *** lSend *** send a charater in lChr
void lSend(void) {  
#define LSb B00000001           // Least Significant bit
  for (int i = 0; i < 8; i++) { // do the following for 8bits
    if ((lChr & LSb) == LSb) {  // if one then
      digitalWrite(lDIO, HIGH); // set lDIO high
    } else {                    // else
      digitalWrite(lDIO, LOW);  // set lDIO low
    }
    lCLKon();                   // clock on to show lDIO
    lChr = lChr >> 1;           // shift bits to right
  }
  digitalWrite(lDIO, LOW);      // pull down during Ack
  lCLKon();                     // clock on to simulate reading
}

// *** lStart *** send start signal 
void lStart(void) {
  digitalWrite(lDIO, LOW);
  delayMicroseconds(lTu);
  digitalWrite(lCLK, LOW);
  delayMicroseconds(lTu);
}

// *** lStop *** send stop signal
void lStop(void) {
  digitalWrite(lCLK, HIGH);
  delayMicroseconds(lTu);
  digitalWrite(lDIO, HIGH);
  delayMicroseconds(lTu);
}

// *** lCLKon ** clock on to show data
void lCLKon(void) {
  digitalWrite(lCLK, HIGH);
  delayMicroseconds(lTu);
  digitalWrite(lCLK, LOW);
  delayMicroseconds(lTu);
}
/* End of program */

 上では表示するコードを7セグに変えるためswitch-case-defaultのロジックで行っていますが、固定byte列をコード値でインデクシングしてもよいでしょうね。その場合は、インデクシング前に0x0Fでandをとるなどしてコード値を制限しないといけませんね。

こういう勝手で単純な”Roll-Your-Own"と呼ばれるプログラムは、ライブラリーの使い方を調べなくてよいのと、マイコン容量消費の最小化ができる利点があるかも^^;  上のプログラムは、pのセグメントを使う場合には適当に加工して応用いただくと良いかと思います。

この場合、CLKとDIOは次の図のように動かしています。下は0000を表示している時のロジックアナライザー表示です。簡便法としてI2Cとして分析していますが、I2Cとは逆に、TM1637での約束は各バイトを下位ビット(つまりLSb)から順に送るので、各バイトごとにビットの並びが逆転しているので注意がいります。またスレーブアドレスなどはありません。

 

f:id:a-tomi:20200725163834j:plain

TM1637側は受信バイトに対してAck以外の応答をしませんから、DIOピンのモードをいちいち送信から受信に切り替えなくとも、早めのタイミングで自分でLOWにすれば送信モードのまま変えずにいけます。もしLOWにするタイミングが遅すぎて、スレーブが先にLOWを出す場合は正負で引きあうので注意。もし仮にそういう間違いをしても数マイクロセカンドだけですが心配ならDIOへの接続に数百オームの抵抗をいれれば安心でしょう。上のコーディングの場合は不要です。

 

その他もろもろの情報が必要な場合、TM1637のDatasheetをググってご確認いただくと良いと思います。

 

今回は超簡単な解説記事でしたが、このへんまでにしたいと思います。TM1637をお知りになりたい方々へ、少しでもお役に立つなら幸いです。

 

©2020 Akira Tominaga, All rights reserved.