e-DIY
ディスプレイ

シフトレジスタ【74HC595】の使い方を解説

74HC595

今回はシフトレジスタIC:74HC595を使って7セグLEDに数字や文字を表示させてみたいと思います。

シフトレジスタの基本的な知識についてはこちらの記事をご覧ください。

74HC595の概要

74HC595は出力ラッチを持った8bitのシフトレジスタICです。

ICの端子配置図と内部の概略図はこのようになっています。

74HC595端子配置図

74HC595端子配置図

74HC595内部概略図

74HC595内部概略図

入力されたデータは8段のシフトレジスタに保存され、RCKによってストレージレジスタに転送されます。
ストレージレジスタの値は3ステートバッファによってQA~QHからパラレル出力されます。

各端子の機能をまとめます。

ピン番号 端子名 機能
1~7、15 QA~QH データ出力端子
8 GND GND端子
9 QH’ 別の74HC595のSI端子に接続してシフトレジスタの段数を増やす事ができる(カスケード接続)。
10 SCLR シフトレジスタクリア端子。LOWにすると全ビットがLOWにセットされる。
11 SCK クロック入力端子。立ち上がりエッジでデータがシフトレジスタにセットされる。
12 RCK ラッチ端子。立ち上がりエッジでシフトレジスタのデータがストレージレジスタへ転送される。
13 G 出力イネーブル端子。LOWで全出力をHi-Z状態にする。
14 SI シリアルデータ入力端子。
16 VCC 電源端子

シフトレジスタの使い方

それでは、ラズパイとシフトレジスタICを使って7セグディスプレイに数字を表示してみましょう。
7セグLEDについてはこちらの記事をご覧ください。

回路図

今回使った7セグLEDディスプレイはアノードコモンなので、シフトレジスタの出力はカソード側へ接続しています。
したがって、シフトレジスタの出力がLOWの時にLEDが点灯することになります。

ラズパイ回路図
ラズパイ配線図

Pythonコード

7セグディスプレイに数字のを表示させるプログラムです。

import RPi.GPIO as GPIO     # GPIO用のモジュール
import time                 # 時間制御用のモジュール

dataPin = 11   # GPIO 17(74HC595の14ピンと接続)
latchPin = 13  # GPIO 27(74HC595の12ピンと接続)
clockPin = 15  # GPIO 22(74HC595の11ピンと接続)

def setRegister(dPin,cPin,val):
  for i in range(0,8):
    GPIO.output(cPin,GPIO.LOW);         # クロックをLOWに
    GPIO.output(dPin,val&(0x01<<i))     # 最下位bitから順にデータを入力
    GPIO.output(cPin,GPIO.HIGH);        # クロックをHIGHに

GPIO.setmode(GPIO.BOARD)           # GPIOを物理ピン番号で指定
GPIO.setup(dataPin, GPIO.OUT)      # dataPinを出力モードに設定
GPIO.setup(latchPin, GPIO.OUT)     # latchPinを出力モードに設定
GPIO.setup(clockPin, GPIO.OUT)     # clockPinを出力モードに設定

GPIO.output(latchPin,GPIO.LOW)       # latchPinをLOWに
setRegister(dataPin,clockPin,0x25)   # valに16進数で引数を渡す
GPIO.output(latchPin,GPIO.HIGH)      # latchPinをHIGHに
GPIO.cleanup()

を表示するためには、7セグLEDの[A,B,D,E,G]を点灯させる、つまりLOWにする必要があります。
したがって、SIに入力するデータは00100101となります。
16進数にすると0x25です。

7セグLEDの点灯箇所

このプログラムの一番のポイントは下記の部分です。

def setRegister(dPin,cPin,val):
  for i in range(0,8):
    GPIO.output(cPin,GPIO.LOW);         # クロックをLOWに
    GPIO.output(dPin,val&(0x01<<i))     # 最下位bitから順にデータを入力
    GPIO.output(cPin,GPIO.HIGH);        # クロックをHIGHに

この関数はシフトレジスタにデータをセットするためのものです。

まずSCK(cPin)をLOWにします。

次にSI(dPin)にデータをセットします。
ビット演算子:<<は左シフトを示し、0x01、つまり0b00000001の最下位ビットをi個左にシフトします。

i=0の場合は、0個シフトなのでそのまま、i=1の場合は1個シフトするので0b00000010となります。
まとめると、次のようになります。

i シフト後の値
0 00000001
1 00000010
2 00000100
3 00001000
4 00010000
5 00100000
6 01000000
7 10000000

このシフトされた値とvalの&を取ります。
&演算子は各ビットの掛け算となるので、i=0の場合は、

0b00100101
0b00000001
0b00000001

となり、SI(dPin)に1(HIGH)が入力されます。

この後、SCK(cPin)がHIGHとなりシフトレジスタに1がセットされます。

i=1の場合は1つシフトされるので、

0b00100101
0b00000010
0b00000000

となり、0(LOW)がセットされることになります。

この動きをi=0~7まで繰り返すので、シフトレジスタには00100101がセットされることになります。

シフトレジスタにデータがセットされると、RCK(latchPin)をLOWからHIGHに切り替えるので、シフトレジスタの値はストレージレジスタへ転送され、パラレル出力が更新されます。

このプログラムを走らせるとが表示されることが確認できました。

74HC595で7セグLEDを表示

オシロでSCKSIの波形を確認するとこのようになっていて、想定通りの動きが確認できました。

シフトレジスタの動作波形

7セグLEDに0~Fを順番に表示させる

少しレベルアップさせて、7セグLEDに0~9、A~Fを順番に表示させてみます。
Pythonのコードは次のようにしました。

import RPi.GPIO as GPIO     #GPIO用のモジュール
import time                 #時間制御用のモジュール

LSBFIRST = 1  #数字は何でもよい
MSBFIRST = 2  #数字は何でもよい

dataPin = 11   #GPIO 17(74HC595の14ピンと接続)
latchPin = 13  #GPIO 27(74HC595の12ピンと接続)
clockPin = 15  #GPIO 22(74HC595の11ピンと接続)

#0~9、A~Fを表示させるための値(MSBFIRSTの場合)
num = [0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e]

def setup():
  GPIO.setmode(GPIO.BOARD)
  GPIO.setup(dataPin, GPIO.OUT)
  GPIO.setup(latchPin, GPIO.OUT)
  GPIO.setup(clockPin, GPIO.OUT)

def shiftOut(dPin,cPin,order,val):
  for i in range(0,8):
    GPIO.output(cPin,GPIO.LOW);
    if(order == LSBFIRST):
      GPIO.output(dPin,val&(0x01<<i))
    elif(order == MSBFIRST):
      GPIO.output(dPin,val&(0x80>>i))
    GPIO.output(cPin,GPIO.HIGH);

def loop():
  while True:
    for i in range(0,16):
      GPIO.output(latchPin,GPIO.LOW)              #RCKをLOWにする
      shiftOut(dataPin,clockPin,MSBFIRST,num[i])  #MSBFIRST、numに格納された配列を順に渡していく
      GPIO.output(latchPin,GPIO.HIGH)             #RCKをHIGHにする
      time.sleep(0.5)

def destroy():
  GPIO.output(latchPin,GPIO.LOW)             # latchPinをLOWに
  shiftOut(dataPin,clockPin,MSBFIRST,0xff)   # LEDを全オフ
  GPIO.output(latchPin,GPIO.HIGH)            # latchPinをHIGHに
  GPIO.cleanup()

if __name__ == '__main__':
  print ('Program is starting...' )
  setup()
  try:
    loop()
  except KeyboardInterrupt:
    destroy()

shiftOut関数を作る

下記の部分でshiftOut関数を定義しています。

def shiftOut(dPin,cPin,order,val):
  for i in range(0,8):
    GPIO.output(cPin,GPIO.LOW);
    if(order == LSBFIRST):
      GPIO.output(dPin,val&(0x01<<i))
    elif(order == MSBFIRST):
      GPIO.output(dPin,val&(0x80>>i))
    GPIO.output(cPin,GPIO.HIGH);

引数のorderLSBFIRSTMSBFIRSTかを指定します。

LSBとはLeast Significant Bitの略で、最下位ビットのことです。
0b10110000の場合なら一番右の0がLSBです。

MSBとはMost Significant Bitの略で、最上位ビットのことです。
0b10110000の場合なら一番左の1がMSBです。

LSBFIRSTは最下位ビットから順にセットしていくことを示し、MSBFIRSTは最上位ビットから順にセットしていくことを示します。

よって、orderにLSBFIRSTを指定した場合は、0x01のLSBからシフト演算子で左へシフトしてvalとの&を取るようになっています。

逆にMSBFIRSTを指定した場合は、0x01のMSBからシフト演算子で右へシフトしてvalとの&を取るようになっています。

今回はMSBFIRSTでセットしていきます。
MSBFIRSTを表示させる場合の動きは以下のようなイメージになります。

MSBFIRST

0~Fまでを表示させる

次のコードで0~9とA~Fまでの16文字を順番に表示させます。

def loop():
  while True:
    for i in range(0,16):
      GPIO.output(latchPin,GPIO.LOW)              #RCKをLOWにする
      shiftOut(dataPin,clockPin,MSBFIRST,num[i])  #MSBFIRST、numに格納された配列を順に渡していく
      GPIO.output(latchPin,GPIO.HIGH)             #RCKをHIGHにする
      time.sleep(0.5)

RCKをLOWにしてからshiftOut関数を実行し、numに格納している数字、文字を表示させます。

これを16回繰り返し、numに格納した配列を左から順番に表示していきます。
while True:なので無限ループとなっており、0~Fの表示をずっと繰り返します。

プログラム実行結果

狙い通り0~Fの表示を繰り返していることを確認できました。

関連キーワード

フリーワード検索