はじめに
Arduinoなどのマイコンで入出力のためのピンが足りなくなった場合、ICを使って増やすことができます。
デジタルアウトピンを増やす場合は、汎用のシフトレジスタである74HC595がよく使われている様子。
今回は74HC595を使ってArduinoで大量のLEDを出力しようという話。
74HC595 とは
概要
74HC595のピン配列は上の通り。パッケージによっては配列は違うのでデータシートを要確認。駆動電圧は2-6 Vと広いため、5Vでも3.3Vでも駆動する。
基本的にはSER(シリアル入力)に入ってきた1 byte (8bit)のシリアルデータをQA-QHまでのピンにそれぞれHIghかLowで出力する。ので、シリアルパラレル変換と呼ばれる。
SERの入力に対してQA-QHまでの8出力のデジタルアウトが増えるので、ArduinoのI/Oピンの拡張に持ってこれる。実際には最低でもSERの他にSRCLKとRCLKの3ピンを制御に使うのでデジタルピン3つを使ってデジタルアウトを8つにすることができるということ。きちんと動作させたい場合はSER、SRCLK、SRCLRとRCLK、OEの5ピンで制御させる必要があるものの、8ピンの拡張に5ピン使ってしまう。
さらに74HC595は複数個をつなげ合わせることで、デジタルピン3つだけでどんどんデイジーチェーンしていくことができるので8個、16個…とデジタルアウトをどんどん増やすことができる。
74HC595自体はシリアルのソフトウェア制御またはSPI通信で処理するが、ArduinoなどのGPIOピンと比べて処理に時間がかかる(数ns)ので早い処理が必要な時は74HC595を使わずGPIOピンで直接制御するのが良い。
74HC595 の動作
74HC595にはシリアルをパラレルに変換する「シフトレジスタ」とパラレルに出力したものをIOピンから出力する「ストレージレジスタ」からなる。
SER (Serial Input)、SRCLK (Shift Register Clock)、SRCLR (Shift Register Clear)のピンおよびQH’ピンはシフトレジスタに関わるピンで、RCLK(Storage Register Clock)、OE (Output Enable)ピンはストレージレジスタに関わるピン。QAからQHは出力ピン。
SRCLKやRCLKはクロックと書いていますが、実際に一定の周波数で送る必要はないです。
シフトレジスタの動作
シフトレジスタ部分の動作です。時間軸に沿って。
はじめにSRCLRがLOWになったタイミングで、それまで保持していたQAからQHまでの出力はHighでもLowでも全てLowにします。SRCLRはHIghに戻します。
次に1 byteのシリアルデータをSERに送るわけですが、SRCLKがHighになったタイミングでのSERの値はQAに送られます。QAにある値はQBに…と順次ずれながら送られていくので、最終的にQAからQHまでにSERに送られたシリアルデータがパラレルに送られることになります。(“QA”とか”QB”とか書いてるけど74HC595ま実際の出力ピンの話ではなくてシフトレジスタ内の出力の話)
QAからQHまでの値は次にSRCLRがLowになるタイミングかあるいはSERとSRCLKでデータが送られてくるまで値は保持されます。
ストレージレジスタの動作
次にストレージレジスタの動作について。
シフトレジスタ部だけで動作させようとすると、QAからQHまでのピンはSERからシリアルデータを受けるたびにHighになったりLowになったりとコロコロと変わってしまいます。
人の目にわかる速さより早いスパンで行われるので LEDなどの出力の場合は人が認知できない程度の一瞬点灯を繰り返します。
LEDの場合などのように気にするほどではない場合は置いておいて、後段でさらに値のやり取りを行ったりする場合には、この一瞬の切り替えも起こしたくないです。
そのような時に使うのがストレージレジスタです。シフトレジスタから出力される値を受け取るまで実際のピンから出力しないようにします。
RCLKピンがHighになったタイミングでシフトレジスタの出力ピンをストレージレジスタの出力ピン(つまり74HC595の実際の出力ピン)に値が転送されます。
RCLKがLowの間はストレージレジスタの出力ピンはシフトレジスタの出力にかかわらず一定です。
74HC595を使う時の処理まとめ
内部処理に関する理解が少しできたので、実際に74HC595を使う時には
- SRCLRをLowにして出力を初期化
SRCLRをHighに戻す - SERとSRCLKを使ってシリアルデータをパラレルに変換
- RCLKをHighにして74HC595の出力ピンからパラレルデータを出力
RCLKをLowに戻す
複数個の74HC595をデイジーチェーンする場合は1つ目の74HC595の「QH’」端子と2つ目の74HC595の「SER」端子をつなげてやればいいということがわかります。
SRCLR、SRCLK、RCLKに関しては74HC595の内部処理的な観点からすべて共通のピンから取れば良い(つまり74HC595のSRCLR、SRCLK、RCLKをそれぞれつなぎ合わせる)ということもわかりますね。
ついでに74HC595に対するノイズ対策としてコンデンサを挟むという方法をとるのがよくあるらしいですね。
新回路に使うIC(74HC595)が雑音に影響されちゃう理由を調べた : https://blog.goo.ne.jp/hmoshinjyuku/e/8a2422676c252c2cce7b794e5bbd9cd5
Arduinoで74HC595を使う
はじめに
今回はArduinoと74HC595を使って8つのLEDをチカチカさせます。
用意するもの
Arduino本体 (今回はArduino Uno互換機)
Akizuki : http://akizukidenshi.com/catalog/g/gM-07385/
74HC595 (今回はSN74HC595N)
Akizuki : http://akizukidenshi.com/catalog/g/gI-08605/
LED(今回は青色LED)
Akizuki : http://akizukidenshi.com/catalog/g/gI-01321/
抵抗(220Ω)
Akizuki : http://akizukidenshi.com/catalog/g/gR-25221/
ブレッドボードとケーブル
Akizuki : http://akizukidenshi.com/catalog/g/gP-00315/
Akizuki : http://akizukidenshi.com/catalog/g/gC-05371/
Arduinoボード
配線はこんな感じ (Fritzing使うの面倒くさくなったなんて言わない)。
74HC595に関して言えば、
- SER : D2 (OUTPUT)
- OE : GND
- RCLK : D3 (OUTPUT)
- SRCLK : D4 (OUTPUT)
- SRCLR : D5 (OUTPUT)
で接続しています。Arduinoのデジタルピンなら別にどこでもいいです。
OE (Output Enable)ピンは今回制御に使わないので常にEnableとしてGNDに接続しています。
Arduino IDE
ShiftOut()を使う
Arduinoの制御関数の中に、ShiftOut()
関数というものがあります。
Arduinoリファレンス : https://www.arduino.cc/reference/jp/language/functions/advanced-io/shiftout/
Arduino 日本語リファレンス : http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=2369
ここを読めば大体わかりますね。
ShiftOut(dataPin, clockPin, bitOrder, value)
は引数としてdataPin, clockPin, bitOrder, valueの4つの値を持ちます。
dataPinはSERの接続ピン番号、clockPinはSRCLKの接続ピン番号、valueはシリアルデータ(通常は 1byte)です。
bitOrderは「MSBFIRST」または「LSBFIRST」を指定します。Most Significant Bit Firstは最上位ビットから送ること、Least Significant Bit Firstは最下位ビットから送ることを示します。つまりMSBにすればQAが最上位QHが最下位になりますし、LSBにすればQAが最下位QAが最上位になるということですね。
ShiftOut()関数ではSERとSRCLKの制御を行うので、ラッチ(RCLK)の制御とSRCLRの制御は自分で行う必要があるということですね。
コードの全体
/*
* 74HC595
* SER : 2
* OE : GND
* RCLK : 3
* SRCLK : 4
* SRCLR : 5
*/
int const SER = 2;
int const RCLK = 3;
int const SRCLK = 4;
int const SRCLR = 5;
void setup() {
pinMode(SER, OUTPUT);
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
pinMode(SRCLR, OUTPUT);
//初期化
digitalWrite(SRCLR, LOW);
digitalWrite(SRCLR, HIGH);
}
void loop() {
//光らせるLEDの選択
int i = B0000 0001;
//初期化
digitalWrite(SRCLR, LOW);
digitalWrite(SRCLR, HIGH);
//シリパラ変換
digitalWrite(RCLK, LOW);
shiftOut(SER, SRCLK, LSBFIRST, i);
digitalWrite(RCLK, HIGH);
delay(250);
}
実際のコードです。変数の設定とpinMode()
の設定に関しては割愛。
//初期化
digitalWrite(SRCLR, LOW);
digitalWrite(SRCLR, HIGH);
SRCLRをLowにすることで74HC595の出力を初期化しています。電源投入時などは74HC595の出力は安定していないのでとりあえずsetup()
内で一回初期化します。
//シリパラ変換
digitalWrite(RCLK, LOW);
shiftOut(SER, SRCLK, LSBFIRST, i);
digitalWrite(RCLK, HIGH);
シリアルパラレル変換と出力です。
- SRCLRをLowにして出力を初期化
SRCLRをHighに戻す - SERとSRCLKを使ってシリアルデータをパラレルに変換
- RCLKをHighにして74HC595の出力ピンからパラレルデータを出力
RCLKをLowに戻す
の2と3をやってるだけですね。
shiftOut()
のvalue値である i
を好きな値に変えることで、光らせたいLEDを変えることができます。今回はLSBFIRST
でi = 1
なのでQHの出力だけがHighになっているわけですね。
コードの全体(その2)
/*
* 74HC595
* SER : 2
* OE : GND
* RCLK : 3
* SRCLK : 4
* SRCLR : 5
*/
int const SER = 2;
int const RCLK = 3;
int const SRCLK = 4;
int const SRCLR = 5;
void setup() {
pinMode(SER, OUTPUT);
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
pinMode(SRCLR, OUTPUT);
digitalWrite(SRCLR, LOW);
digitalWrite(SRCLR, HIGH);
}
void loop() {
for (int j = 0; j < 8; j++) {
digitalWrite(RCLK, LOW);
shiftOut(SER, SRCLK, LSBFIRST, 1<<j);
digitalWrite(RCLK, HIGH);
delay(250);
}
}
なのでsiftOut()のvalue値を変えてやればLEDの光らせ方も変えることができます。
ついでにsetup()
内などでSRCLRで初期化をしていますが、SRCLRの接続ピンをVcc (5V)につないで、シフトレジスタにB0000 0000
を送ってやればほぼ同等のことができるのでArduinoで使用するGPIOピンを減らしたい時はSRCLRを使わないという手もありますね。
まとめ
今回はシフトレジスタ 74HC595を利用してArduinoの出力ピンを増やしました。
参考
しなぷすのハード製作記 「74HC595」の解説 : https://synapse.kyoto/glossary/glossary.php?word=74HC595
Arduinoでシフトレジスタ(SN74HC595)を使用して8個のLEDをチカチカさせる : https://stupiddog.jp/note/archives/1152#i-7
しなぷすのハード製作記 「シフトレジスタ」の解説 :
https://synapse.kyoto/glossary/glossary.php?word=シフトレジスタ