電子工作で、8ビットシフトレジスタ74HC595をよく使います。
しかし、仕様を完全に理解していないで、他ブログや自分の過去の利用を流用し、
その場しのぎで利用していました。

「これじゃぁ、アカン、ちゃんと仕様と機能をちゃんと理解しよう」と思い、
調査しまとめることにしました。
まずは仕様の再確認
ピンレイアウト

メーカー毎に微妙にピン名称が異なります。
MC74HC595Aが分かり易い名称なので、データシートからピンレイアウトを
拝借し、修正しました。
ブロック図
内部的には、シフトレジスタとストレージレジスタの構成になっています。
変化するシフトレジスタの8ビットパラレル出力を、ストレージレレジスタが
LATCH CLOCKのラッチのタイミングで取り込んで、パラレル出力の状態を保持&出力します。
ストレージレジスタのQA~QHは3ステート(HIGH、LOW、ハイインピーダンス)です。
(SQHは2ステート(HIGH、LOW)であるに注意)
Arduino Unoを使った実験
ブレッドボード上の8個のLEDを74HC595を使って制御します。

接続は、74HC595のパラレル出力QA~QH、SQHにLEDを接続します。
各LEDには電流調整用に330Ωの抵抗を入れてGNDに接続しています。
各LEDはQA~QH、SQHの出力がHIGHの場合点灯し、LOWの場合に消灯します。
OUTPUT ENABLE、SERIAL DATA INPUT、RESET、SHIFT CLOCK, LATCH CLOCKの
制御用の入力端子は、ArduinoのD10、D11、D2、D13、D3に接続します。
LEDの簡単な点灯制御
つぎの動画のように、8つLEDをチカチカさせる制御です。
スケッチ
// 利用ピンの定義
#define OUT_ENABLE 10
#define SERIAL_OUT 11
#define HC595_RESET 2
#define SHIFT_CLK 13
#define LATCH_CLK 3
// シフトレジスタへの8ビットデータのセット
void shift_dataOut(uint8_t data) {
for (uint8_t i=0; i < 8; i++) {
digitalWrite(SHIFT_CLK,LOW);
digitalWrite(SERIAL_OUT, (data & (0x80>>i)));
digitalWrite(SHIFT_CLK,HIGH);
}
}
// シフトレジスタのデータリセット
void shift_reset() {
digitalWrite(HC595_RESET,LOW);
digitalWrite(HC595_RESET,HIGH);
}
// シフトレジスタからストレージレジスタへのデータセット
void strage_update() {
digitalWrite(LATCH_CLK,LOW);
digitalWrite(LATCH_CLK,HIGH);
}
// ストレージレジスタの出力有効
void strage_enable() {
digitalWrite(OUT_ENABLE, LOW);
}
// ストレージレジスタの出力無効
void strage_disable() {
digitalWrite(OUT_ENABLE, HIGH);
}
void setup() {
// 利用ピンの初期化
pinMode(OUT_ENABLE, OUTPUT);
pinMode(SERIAL_OUT, OUTPUT);
pinMode(HC595_RESET,OUTPUT);
pinMode(SHIFT_CLK, OUTPUT);
pinMode(LATCH_CLK, OUTPUT);
// SHIFT CLOCK、LATCH CLOCKの設定
digitalWrite(SHIFT_CLK,LOW);
digitalWrite(LATCH_CLK,LOW);
shift_reset(); // シフトレジスタの値リセット
strage_update(); // シフトレジスタからストレージレジスタへの値セット
strage_enable(); // ストレージレジスタの出力有効
delay(2000);
}
void loop() {
shift_dataOut(0b10101010);
strage_update();
delay(500);
shift_dataOut(0b01010101);
strage_update();
delay(500);
}
スケッチの説明
①初期化 setup()
(1)利用ピンの初期化
74HC595の制御を行う5つのピンの出力設定を行っています。
(2)SHIFT CLOCK、LATCH CLOCKの設定
初期値としてLOWの設定を行います。
(3)シフトレジスタの値リセット
shift_reset()関数を呼び出してシフトレジスタの値のリセットを行います。
shift_reset()関数は次のように定義しています。
// シフトレジスタのデータリセット
void shift_reset() {
digitalWrite(HC595_RESET,LOW);
digitalWrite(HC595_RESET,HIGH);
}
74HC595のリセットピンのLOWを設定してリセットを行った後、HIGHに戻しています。
(4)ストレージレジスタへの値設定
strage_update()関数を呼び出して、シフトレジスタの値をストレージレジスタに設定
しています。
strage_update()関数は次のように定義しています。
// シフトレジスタからストレージレジスタへのデータセット
void strage_update() {
digitalWrite(LATCH_CLK,LOW);
digitalWrite(LATCH_CLK,HIGH);
}
74HC595のLATCH CLOCKに対して、LOW→HIGHを行うことで、
シフトレジスタの値をラッチしてストレージレジスタに取り込みます。
(5)ストレージレジスタの出力有効
strage_enable()関数を呼び出して、ストレージレジスタのパラレル出力QA~QH、SQH
を有効にします。
strage_enable()関数は次のように定義しています。
// ストレージレジスタの出力有効
void strage_enable() {
digitalWrite(OUT_ENABLE, LOW);
}
74HC595のOUTPUT ENABLEをLOWに設定することにより、
出力を有効にしています。
delay(2000)は、LEDの出力がリセットされていることを確認するために入れています。
Arduinoのリセットボタンを押した直後、2秒間8個のLEDが消灯していることが確認できます。
②LEDの点灯ループ loop()
8個のLEDに対して、2つのパターンの出力を0.5秒間隔で繰り返しています。
shift_dataOut()関数は8個のLEDの点灯パターンを設定しています。
shift_dataOut()関数は、シフトレジスタへの値の設定のみを行います。
この関数を実行しても、LEDの表示には影響しません。
shift_dataOut()関数は次のように定義しています。
// シフトレジスタへの8ビットデータのセット
void shift_dataOut(uint8_t data) {
for (uint8_t i=0; i < 8; i++) {
digitalWrite(SHIFT_CLK,LOW);
digitalWrite(SERIAL_OUT, (data & (0x80>>i)));
digitalWrite(SHIFT_CLK,HIGH);
}
}
8ビットの値をシフトレジスタにセットするために8回繰り返し処理を行っています。
1回毎の処理で1ビットの値をシフトレジスタにセットしています。
(1)74HC595のSHIFT CLOCKをLOWにした状態にする
(2)74HC595のSERIAL OUTにセットしたい値をセットする
(3)74HC595のSHIFT CLOCKをHIGHにして、SERIAL OUTの状態をラッチして
1ビットをシフトレジスタにシフトインして取り込む。
次にstrage_update()関数にてシフトレジスタの値をストレージレジスタにセットします。
このタイミングでLEDの表示が更新されます。
LEDのPWMを使った明るさの制御
74HC595のOUTPUT ENABLEをPWMで制御することでLEDの明るさを制御することが出来ます。
スケッチのloop()のdeley(500)を次のように修正して、PWMにて徐々に暗くなるように
修正してみます。
実行すると、「ぽわー、ぽわー」と暗くなってからパターンが切り替わります。
void loop() {
shift_dataOut(0b10101010);
strage_update();
for (int16_t i=0; i<256; i++) {
analogWrite(OUT_ENABLE,i);
delay(5);
}
shift_dataOut(0b01010101);
strage_update();
for (int16_t i=0; i<256; i++) {
analogWrite(OUT_ENABLE,i);
delay(5);
}
}
ちょっとした疑問
74HC595は連結(SQHを連結先の74HC595のSERIAL DATA INPUTに接続)して
8ビット、16ビット、24ビットと桁数を増やすことが出来る仕様なのですが、
QHとSQHが同じ値なので、
「1個目の8ビット目と2個目の1ビット目が同じ値になってしまうのでは?」
と非常に疑問を感じます。
シフトレジスタ部の内部ロジック構造を見てみることにします。
シフトレジスタ部はDフリップ・フロップの連結構造です。
(ロジック図はMC74HC595Aからの引用です)
74HC595内部の個々のDフリップ・フロップの連結と
1個目の最後のDフリップ・フロップと2個目の74HC595のDフリップ・フロップへの
連結(SRH ⇒ SRA)は、差異が無いはずです。
下記の図は1個目の74HC595のシフトレジスタ部内のSRHと、2個目の74HC595の
シフトレジスタ部内のSRAを接続したイメージです。
下図のタイミングチャートにおいて、
SERIAL CLOCKの立上り(太い線)でSERIAL DATA INPUTから読み込むデータを
D0、D1、D2...とすると、SQHとSQAの状態は次のような感じにまります。
(時間軸は左が過去)
SQHがD5をラッチするタイミングでSQAのDにはD4が入力されているため、取り込むデータの
値は当然D4になります。
うぁ、良く考えたら当たり前で、こんな図を描いて考える必要もなかった。
「Dフリップ・フロップ の連結で受け取るデータは前段のDフリップ・フロップの
1クロック遅れたデータを受け取る」
ってことです。
まあ、これで疑問が解けたので良しとします。
最近のコメント