7セグメントLEDやLEDマトリクスは、LEDを複数並べて1つのパッケージにしたデバイスです。これらのデバイスを制御するには少し工夫が必要です。今回は、シフトレジスタ(74HC595)やLEDディスプレイドライバ(MAX7219)を使用したプログラム例について紹介します。
7セグメントLED
7セグメントLEDは、さまざまなデバイスで数値表示に使用されています。名前の由来は、点灯する箇所が7個ある構成から来ています。小数点のドット「.」も含んだ、8セグメントディスプレイもありますが、同じ部品群・素子群・コンポーネントと分類されます。RGB LEDと同様に、複数のLEDを1つの筐体にまとめ、カソードを1つの端子で共有しています。Arduinoには十分な出力ピンがあるので、各LEDを直接(直列抵抗を介して)駆動できます。しかし、複数のピンを持つ部品を使用する場合には、問題が生じる場合があります。この問題を解決するために、シフトレジスタという方法があります。74HC595はシフトレジスタを1パッケージにまとめたデバイスです。データはビット単位で次々とデバイスに「押し込む」ことができます。最後の8ビットは8ピンを介して出力されます。
シフトレジスタの制御はArduinoの3ピンあれば十分です。 Arduinoのデータラインは、実際のビット値を次々と送信し、クロックラインはビット値を決定するためのクロックを供給します。すべてのビットが転送されると、ラッチライン上のパルスは、ビットパターンがシフトレジスタの各々の出力ピンにルーティングできます。
以下のプログラムでは、0~9の数字が連続して表示されています。
const int latchPin = 8; // (1) const int clockPin = 12; const int dataPin = 11; byte digits[] = { // (2) 0b11111010, 0b01100000, 0b11011100, 0b11110100, 0b01100110, 0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11100110, }; void setup() { pinMode(latchPin, OUTPUT); // (3) pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); } void clearDisplay() { setDisplay(0b00000000); } byte period = 0b00000001; byte getDigit(int i, bool period = false) { if(i >= 0 && i < 10) { if(period == false) { return digits[i]; }else { return digits[i] + period; } } } void loop() { clearDisplay(); for(int i = 0; i < 10; i++) { setDisplay(getDigit(i)); //(4) delay(500); clearDisplay(); delay(500); } } void setDisplay(byte code) { //(5) digitalWrite(latchPin, LOW); //(6) shiftOut(dataPin, clockPin, LSBFIRST, code); //(7) digitalWrite(latchPin, HIGH); //(8) }
- 読みやすくするために、シフトレジスタに接続されているピンには定数を使用しています。
- 10個の要素を持つバイト型の変数を定義します。その中で、表現可能な各桁に対してビットパターンが格納され、最終的にどのセグメントが点灯するか、どのセグメントが点灯しないかを決定します。ビットを変更すると、どのような動きになるか、観察してみてください。
- シフトレジスタへのデータラインは OUTPUT に設定する必要があります。
- メインループでは、変数番号のみを0から9まで1秒ごとにカウントし、関数setDisplay()で表示し、clearDisplay()で消灯します。
- この関数を宣言することで、シフトレジスタへの実際のデータ転送が行われるようになります。
- ラッチ端子をLOWにすると、シフトレジスタの出力ピンが「フリーズ」すなわち出力保持するので、新しいビットを「押し込んで」も現在の表示を妨げることはありません。
- 関数 shiftOut() はシフトレジスタのためのものです。初めの引数でデータピンとクロックピンの番号を渡し、次の引数を使ってどの順番でビットを転送するかの情報を渡します。(ここではLSB first とは Least Significant Bit firstの略)最後の引数は対応するビットパターンを指定します。この指定を行うには、プログラムの最初(2)で対応する桁の配列に格納されていたバイト型の変数を呼び出します。
- 最後にラッチ端子をHighにする。すなわちラッチ解除すると、送信されたビットパターンが表示できます。
LEDマトリクス
LEDマトリクスは名前の通り、LEDを格子状に並べた表示装置です。たとえば、エレベーターのフロアディスプレイとして使用されています
以下の写真では多数の個々のLEDが格子状に組み合わされ、アノードとカソードが行または列で接続されています。
対応する行列のアノードとカソードに電圧を印加することで、任意のピクセルを個別に点灯できるようになります。すべてのLEDピンをArduinoに接続しようとすると、Arduinoの接続可能数を超えてしまいます。そのために標準的なコントローラが用意されています。以下の例では、8×8ピクセルのマトリクスとこの素子に対応する機能を持つMAX7219コントローラを使用します。
コントローラはSPIのような接続で制御されています。そのためのライブラリがあり、まずインターネットからロードしなければなりません。ダウンロードは、Arduino IDEのライブラリマネージャで「LedControl」を検索して直接行えます
それでは、LEDマトリクスを制御して、プログラムアップロード後、LEDマトリクス上に「A-r-d-u-i-n-o」の文字が次々と現れるプログラムを作成してみましょう。
#include "LedControl.h" //(1) #define DATA_IN 12 #define CS 11 #define CLK 10 LedControl Display = LedControl(DATA_IN, CLK, CS, 1); //(2) void setup() { Display.shutdown(0,false); //(3) Display.setIntensity(0,8); //(4) Display.clearDisplay(0); //(5) } void loop() { Display.setRow(0,0,B00000000); // A //(6) Display.setRow(0,1,B00111100); Display.setRow(0,2,B01000010); Display.setRow(0,3,B01111110); Display.setRow(0,4,B01000010); Display.setRow(0,5,B01000010); Display.setRow(0,6,B01000010); Display.setRow(0,7,B00000000); delay(500); Display.setRow(0,1,B00000000); // r Display.setRow(0,2,B00000000); Display.setRow(0,3,B00111110); Display.setRow(0,4,B01000000); Display.setRow(0,5,B01000000); Display.setRow(0,6,B01000000); delay(500); Display.setRow(0,1,B00000010); // d Display.setRow(0,2,B00000010); Display.setRow(0,3,B00111110); Display.setRow(0,4,B01000010); Display.setRow(0,5,B01000010); Display.setRow(0,6,B00111100); delay(500); Display.setRow(0,1,B00000000); // u Display.setRow(0,2,B00000000); Display.setRow(0,3,B01000010); Display.setRow(0,4,B01000010); Display.setRow(0,5,B01000010); Display.setRow(0,6,B01111100); delay(500); Display.setRow(0,1,B00001000); // i Display.setRow(0,2,B00000000); Display.setRow(0,3,B00001000); Display.setRow(0,4,B00001000); Display.setRow(0,5,B00001000); Display.setRow(0,6,B00011100); delay(500); Display.setRow(0,1,B00000000); // n Display.setRow(0,2,B00000000); Display.setRow(0,3,B01111100); Display.setRow(0,4,B01000010); Display.setRow(0,5,B01000010); Display.setRow(0,6,B01000010); delay(500); Display.setRow(0,1,B00000000); // 0 Display.setRow(0,2,B00000000); Display.setRow(0,3,B00111100); Display.setRow(0,4,B01000010); Display.setRow(0,5,B01000010); Display.setRow(0,6,B00111100); delay(500); Display.clearDisplay(0); delay(500); }
- このヘッダは、ダウンロードしたばかりのライブラリを統合して、LEDコントローラを制御するものです。
- 統合ライブラリはオブジェクトベースでプログラムされ、クラスLedControlを提供しています。ここでは、このクラスのインスタンスをDisplayで定義します。このオブジェクトは、LEDマトリクスを表示するためのもので、自動的に呼び出される関数であるコンストラクタ:LedControl()でLEDマトリクスを初期設定します。引数で使用されている接続ピンの番号と、LEDマトリクスの数(LEDマトリクスはカスケードされている可能性があります)を渡します。
- 引数が 0 の関数 Display.shutdown()は、プログラムの開始時に満杯になっているLEDコントローラをリセットし、メモリ内の古いデータを削除します。
- ここでは、明るさは中程度の値に設定されています。0から15までの値が使用できます。
- 表示をクリアします。この場合、多くの想定されるシナリオでは必要ないとしても、コントローラ起動前に”クリーンアップ”することは、プログラムの考え方の良い例です。
- 関数 setRow() は、特定の LED 行にビットパターンを出力するようになりました。最初の引数は、LED マトリクスの現在の番号(通常 0 から始まりますが、1つのマトリクスしか使わないので今回は常に 0 です)です。次の引数は適切な行番号(0 から始まります)で、最後の引数は実際のデータです。この関数でデータはマトリックスコントローラに送られ、すぐに出力されます。
このようにして、すべての文字が次から次へと転送され、それぞれが0.5秒の区切りをつけて転送されていきます。スケッチのビットパターンをよく見ると、すでに文字が入っていることがわかります。
ライブラリには更なる機能が用意されています。興味のある方は、他のライブラリと同様に、オンラインレファレンスを参照してください。
シミュレーション
TINKERCADで7セグメントLEDの回路を組みました。「シミュレーションを開始」のボタンを押してみてください。
コメントを残す