フォト
2018年10月
  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      
無料ブログはココログ

« ATtiny13AでI2C接続キャラクタLCDを利用する(4) | トップページ | Aliexpressで USBTinyISPの小型版を購入 »

2018年4月24日 (火)

シフトレジスタ 74HC595の考察

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

Snapshot000003

「これじゃぁ、アカン、ちゃんと仕様と機能をちゃんと理解しよう」と思い、
調査しまとめることにしました。


まずは仕様の再確認

ピンレイアウト

Photo
メーカー毎に微妙にピン名称が異なります。
MC74HC595Aが分かり易い名称なので、データシートからピンレイアウトを
拝借し、修正しました。


ブロック図

Photo

内部的には、シフトレジスタストレージレジスタの構成になっています。

変化するシフトレジスタの8ビットパラレル出力をストレージレレジスタが
ラッチにて取り込んで、パラレル出力の状態を保持&出力します。

ストレージレジスタQAQHは3ステート(HIGHLOW、ハイインピーダンス)です。
SQHは2ステート(HIGHLOW)であるに注意)

Arduino Unoを使った実験

ブレッドボード上の8個のLEDを74HC595を使って制御します。

Dscn7854

接続は、74HC595のパラレル出力QAQHSQHにLEDを接続します。
各LEDには電流調整用に330Ωの抵抗を入れてGNDに接続しています。
各LEDはQAQHSQHの出力がHIGHの場合点灯し、LOWの場合に消灯します。

OUTPUT ENABLESERIAL DATA INPUTRESETSHIFT CLOCK, LATCH CLOCK
制御用の入力端子は、ArduinoのD10D11D2D13D3に接続します。

Photo_2

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 CLOCKLATCH 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);  
      }

        74HC595LATCH CLOCKに対して、LOWHIGHを行うことで、
        シフトレジスタの値をラッチしてストレージレジスタに取り込みます。

    (5)ストレージレジスタの出力有効
        strage_enable()関数を呼び出して、ストレージレジスタのパラレル出力QAQHSQH
        を有効にします。

        strage_enable()関数は次のように定義しています。

      // ストレージレジスタの出力有効
      void strage_enable() {
        digitalWrite(OUT_ENABLE, LOW);
      }

       74HC595OUTPUT ENABLELOWに設定することにより、
       出力を有効にしています。
       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)74HC595SHIFT CLOCKLOWにした状態にする
        (2)74HC595SERIAL OUTにセットしたい値をセットする
        (3)74HC595SHIFT CLOCKHIGHにして、SERIAL OUTの状態をラッチして
           1ビットをシフトレジスタにシフトインして取り込む。

    次にstrage_update()関数にてシフトレジスタの値をストレージレジスタにセットします。
    このタイミングでLEDの表示が更新されます。


LEDのPWMを使った明るさの制御

74HC595OUTPUT ENABLEPWMで制御することで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を連結先の74HC595SERIAL DATA INPUTに接続)して
8ビット、16ビット、24ビットと桁数を増やすことが出来る仕様なのですが、
QHSQHが同じ値なので、
  「1個目の8ビット目と2個目の1ビット目が同じ値になってしまうのでは?」
と非常に疑問を感じます。

シフトレジスタ部の内部ロジック構造を見てみることにします。
シフトレジスタ部はDフリップ・フロップの連結構造です。

    Photo_3

(ロジック図はMC74HC595Aからの引用です)

74HC595内部の個々のDフリップ・フロップの連結と
連結する2個目の74HC595のDフリップ・フロップへの連結は
よく考えたら、差異はなくまったく同じになりますね。

下記の図は1個目の74HC595のシフトレジスタ部内のSRHと、2個目の74HC595
シフトレジスタ部内のSRAを接続したイメージです。

Dff_2

SERIAL CLOCKの立上りのタイミングでSERIAL DATA INPUTから読み込むデータを
D0、D2、D3...とすると、SQHSQAの状態は次のような感じにまります。
(時間軸は左が過去)

SQHがD5をラッチするタイミングでSQAのDにはD4が入力されているため、取り込むデータの
値は当然D4になります。

Photo_2

うぁ、良く考えたら当たり前で、こんな図を描いて考える必要もなかった。
  「Dフリップ・フロップ の連結で受け取るデータは前段のDフリップ・フロップの
   1クロック遅れたデータを受け取る」

ってことです。

まあ、これで疑問が解けたので良しとします。

« ATtiny13AでI2C接続キャラクタLCDを利用する(4) | トップページ | Aliexpressで USBTinyISPの小型版を購入 »

arduino」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/571408/66627347

この記事へのトラックバック一覧です: シフトレジスタ 74HC595の考察:

« ATtiny13AでI2C接続キャラクタLCDを利用する(4) | トップページ | Aliexpressで USBTinyISPの小型版を購入 »