How to Use a Shift Register
シフトレジスタの使い方について、説明します。 What is Shift Register? LPC824には、デジタル入出力に使えるピンが22本あります。これだけあれば、足りなくなることはないような気がしますよね。しかし、7セグLEDを使うと8本のデジタルピンを使ってしまいます。4桁の数字の表示器を作ろうと思ったら、単純な回路だと32本のピンが必要となり、足りません。そこで登場するのが、シフトレジスタです。 シフトレジスタ(shift register)は、マイコンのデジタル出力を増やすためのデバイスです。デジタル入力やPWM出力を増やすことはできないので、注意してください。ここでは、595や74×595、あるいは74HC595と呼ばれているシフトレジスタについて説明します。 シフトレジスタの中は、以下に示す図のようになっていると思ってください。 図中の「操作」と書かれているところは、マイコンのデジタル出力ピンに接続されます。「デジタル出力」と書かれているところが、増えたデジタル出力ピンです。つまり、1つシフトレジスタを使うと、8本 – 3本 = 5本、デジタル出力が節約できたことになります。さらにすごいことに、シフトレジスタは連結して使うことができます。つまり2個シフトレジスタを使っても、操作に使うデジタルピンは3本のままなのです。 シフトレジスタの操作は、以下の手順で行います。 クロック(clock)とラッチ(latch)をLOW(0)にする。 データレジスタ(data register)に、0か1を書き込む。 クロックをHIGH(1)にする。この時、R0からR7までのレジスタに格納されていた値は、それぞれ右にシフトする。つまり、R7の値は破棄され、R6の値がR7にコピーされる。これがR0まで繰り返される。さらに、データレジスタの値がR0にコピーされる。 クロックをLOWにする。 R0からR7まで値をセットし終わったら、ラッチをHIGH(1)にする。この時、R0からR7までの値に応じて、Q0からQ7までのデジタル出力ピンがHIGHまたはLOWになる。 ラッチをLOWにする。 この手順を見ると、なぜこのデバイスがシフトレジスタと呼ばれているのか分かると思います。 シフトレジスタは、コンピュータのあらゆるところに使われています。表示器やシリアル通信デバイス(UART)などです。 ここまでの話では、シフトレジスタはとても便利なデバイスで、良いことづくめのように思えますよね。しかし、これを使う時には、それなりの代償を払う必要があります。それは、スピードです。シフトレジスタではなく、マイコンのピンを直接使って8つのデジタル出力の状態を変化させるのには大した時間はかかりません。マイコン内部のレジスタの書き換えだけで済みます。ところがシフトレジスタを使った場合、8つのレジスタのセットを待たなくてはならず、しかもclockやlatchをHIGHにしてからLOWに戻すまでに、100nsから200nsほどの時間を置く必要があります。8つのデジタルピンの状態を変化させるのに、約1μsから2μsくらいの時間が、シフトレジスタを使わなかった時にかかる時間に加算されることになります。 How to Use それでは、シフトレジスタを使って7セグLEDに数字を表示してみましょう。7セグLEDの使い方は、TipsにあるHow to Use a Seven Segments LEDを参照してください。以下のように回路を作ります。ただし、シフトレジスタと7セグLEDを結ぶ線は、見にくくなるので省略してあります。 オレンジ色の線(dp17)がクロック、茶色の線(dp18)がラッチ、白い線(dp19)がデータレジスタです。シフトレジスタと7セグLEDは、ピン15(Q0)がピン1へ、ピン1(Q1)がピン2へ、ピン2(Q2)がピン3へと接続されます。 実際にブレッドボードを使って回路を作ってみると以下のようになります。 あとは、クロックとラッチ、データレジスタの操作だけで7セグLEDに数字を表示させることができます。シフトレジスタを操作するためのライブラリを作って見ましょう。ライブラリの作り方は、第13回の講義内容を見てください。まず、ShiftRegister595.hから作っていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include "mbed.h" #define HIGH 1 #define LOW 0 class SR595 { private: DigitalOut clock_pin; DigitalOut latch_pin; DigitalOut data_pin; public: SR595(PinName, PinName, PinName); void set(int); void shift(); void latch(); }; |
set()でデータレジスタへ値をセットし、shift()でクロックの操作をします。8bit分のデータをセットし終わったら、latch()でラッチの操作をします。 ShiftRegister595.cppは、以下の通りです。
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 |
#include "ShiftRegister595.h" SR595::SR595(PinName _clock_pin, PinName _latch_pin, PinName _data_pin): clock_pin(_clock_pin), latch_pin(_latch_pin), data_pin(_data_pin) { } void SR595::set(int x) { clock_pin = LOW; latch_pin = LOW; data_pin = x; wait_us(1); } void SR595::shift() { clock_pin = HIGH; wait_us(1); clock_pin = LOW; } void SR595::latch() { latch_pin = HIGH; wait_us(1); latch_pin = LOW; } |
クロックやラッチの操作をする時に、1μsのwaitを入れています。これは、少し時間をかけ過ぎですので、用途によってはもう少し小さい値で書き換えた方が良いでしょう。 このライブラリを使って7セグLEDに数字を表示させるプログラムを書いて見ましょう。
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include "mbed.h" #include "ShiftRegister595.h" void disp_num(SR595, int[][8], int); void clear_num(SR595); SR595 sr(dp17, dp18, dp19); int led_pattern[11][8]={ {0,0,0,1,0,0,0,1}, // 0 {0,1,1,1,1,1,0,1}, // 1 {0,0,1,1,0,0,1,0}, // 2 {1,0,0,1,0,0,1,0}, // 3 {1,1,0,1,0,1,0,0}, // 4 {1,0,0,1,1,0,0,0}, // 5 {0,0,0,1,1,1,0,0}, // 6 {1,1,0,1,0,0,1,1}, // 7 {0,0,0,1,0,0,0,0}, // 8 {1,0,0,1,0,0,0,0}, // 9 {1,1,1,0,1,1,1,1} // dot }; int main() { int i = 0; while(1) { disp_num(sr, led_pattern, i); i = (i + 1) % 10; wait(0.5); } } void disp_num(SR595 _sr, int _led_pattern[][8], int x) { int i; clear_num(_sr); for(i = 7; i >= 0; i--) { _sr.set(_led_pattern[x][i]); _sr.shift(); } _sr.latch(); } void clear_num(SR595 _sr) { int i; for(i = 0; i < 8; i++) { _sr.set(0); _sr.shift(); } _sr.latch(); } |
上記のプログラムで注意する点は、データをセットする順番です。8bit分のデータをセットする必要がありますが、最初にセットしたデータは最後のレジスタ(Q7)に入り、最後にセットしたデータは最初のレジスタ(Q0)に入ります。 本当は、7セグLEDを操作する関数も、クラスを使ってライブラリ化する方が良いと思います。興味がある人は、挑戦してみてください。 — by 飯田周作、専修大学