【Raspberry Pi Pico】7セグメントディスプレイをシフトレジスタ(74HC595)で表示してみよう【MicroPython、Arduino】

Raspberry Pi/電子工作
スポンサーリンク

こんにちは、あろっちです。

シフトレジスタ(74HC595)を使って7セグメントディスプレイを表示してみます。
マイコンはRaspberry Pi Picoを使います。

スポンサーリンク

シフトレジスタ(74HC595)とは?

74HC595は、少ないピンで複数の信号を制御できるICです。マイコンからのデータを1ビットずつ送信(シリアル)し、それをまとめて出力(パラレル)することで、7セグメントディスプレイやLEDを効率よく操作できます。

これにより、マイコンの出力ピンを節約しながら、7セグメントディスプレイの各セグメント(8ピン)をまとめて制御できるのが特徴です。今回は7セグメントディスプレイの制御を中心に解説しますが、74HC595はLEDの制御やその他のデジタル出力の拡張にも活用できます。

74HC595の操作手順

1. データ送信 → クロック信号送信

最初に、1ビットのデータをDS(データ入力)ピンに送信し、SH_CPピンにクロック信号を送ります。クロック信号が立ち上がると、そのビットがシフトレジスタに格納されます。この操作を1回目のデータ転送とし、次のビットに進みます。

2. 次のビット送信 → クロック信号送信

2番目のビットを送信し、再度クロック信号を送ります。この操作を繰り返し、計8回の「データ送信 → クロック信号送信」を行い、8ビットすべてがシフトレジスタに格納されます。

3. すべてのビットをセット

8ビットすべてがシフトレジスタに格納された後、ST_CPピンをHIGHにします。これにより、シフトレジスタ内のデータがパラレル出力(Q0〜Q7)に転送され、実際の出力が反映されます。

この操作で、7セグメントディスプレイやLEDなどを制御できます。

準備

使用するもの

  • Raspberry Pi Pico
  • 7セグメントディスプレイ (5161BS)
    手持ちのものがこれでした。アノードコモン型です
  • シフトレジスタ (74HC595)
    DIPタイプのものです。
  • ブレッドボード
  • ジャンパーワイヤー

配線について

配線図

7セグメントディスプレイの各ピンと74HC595の間は330Ωの抵抗を入れています。抵抗は220Ωでもよいと思います。(ご使用の7セグメントディスプレイのデータシートをご確認ください。)

5161BSの場合、データシートによると、Vfは1.8V、IF(max)は30mAです。この場合、オームの法則から50Ω以上の抵抗を入れればよいことになります。

$$ R = \frac{V_{\text{cc}} – V_f}{I} $$

$$ R = \frac{3.3V – 1.8V}{0.03A} = \frac{1.5V}{0.03A} = 50Ω $$

7セグメントディスプレイ (5161BS)

シフトレジスタ (74HC595)

配線の対応表

74HC5957セグRaspberry Pi Pico
Q0a
Q1b
Q2c
Q3d
Q4e
Q5f
Q6g
Q7dp
(decimal point…小数点)
com (VCC)3.3V
VCC3.3V
GNDGND
OE (Output Enable)
(LOWで有効)
GND
MR (クリア)
(LOWでクリア
HIGHでクリアを無効)
3.3V
DS28
ST_CP
(ラッチ)
27
SH_CP
(クロック)
26

グリフコード (0から9までの数字の表示パターン)

バイナリーコードの並び

最下位ビット (LSB) が a、最上位ビット (MSB) が dp
並び順: dp, g, f, e, d, c, b, a

表示対象のビットが1

数字バイナリーコードヘックスコード
0001111110x3f
1000001100x06
2010110110x5b
3010011110x4f
4011001100x66
5011011010x6d
6011111010x7d
7000001110x07
8011111110x7f
9011011110x6f

このパターンは、通常カソードコモン型7セグメントディスプレイ(5161ASなど)に対応しています。

今回使用する7セグメントディスプレイはアノードコモン型のため(アノードとカソードが逆)、上記で示したビットを反転してシフトレジスタに書き込みます

プログラム

7セグに0から9を順番に表示する

0から9を順番に7セグメントディスプレイに表示します。

MicroPython

import machine
import time

# Define the segment code for a common anode 7-segment display
SEGCODE = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f]

# Initialize the pins for the 74HC595 shift register
sdi = machine.Pin(28, machine.Pin.OUT)  # DS
rclk = machine.Pin(27, machine.Pin.OUT)  # STcp
srclk = machine.Pin(26, machine.Pin.OUT)  # SHcp

# Define the hc595_shift function to shift data into the 74HC595 shift register
def hc595_shift(dat):
    # Set the RCLK pin to low
    rclk.off()

    # Iterate through each bit (from 7 to 0)
    for bit in range(7, -1, -1):
        # Extract the current bit from the input data
        value = 1 & (dat >> bit)

        # Set the SRCLK pin to low
        srclk.off()

        # Set the value of the SDI pin
        sdi.value(value)

        # Clock the current bit into the shift register by setting the SRCLK pin to high
        srclk.on()

    # Latch the data into the storage register by setting the RCLK pin to high
    rclk.on()

# Continuously loop through the numbers 0 to 9 and display them on the 7-segment display
while True:
    for num in range(10):
        # 7セグがアノードコモンの場合、SEGCODEをビット反転する
        hc595_shift(~SEGCODE[num])  # Shift the segment code for the current number into the 74HC595
        # 7セグがカソードコモンの場合はSEGCODEをそのまま渡す
        # hc595_shift(SEGCODE[num])  # Shift the segment code for the current number into the 74HC595
        time.sleep_ms(500)  # Wait 500 milliseconds before displaying the next number

SEGCODEに0から9の表示パターンを16進数で定義しています。

hc595_shift関数は、シフトレジスタに表示パターンを書き込む関数です。

書き込む際に、SEGCODEのパターンに対してnotをとることでビット列を反転しています。この処理によりアノードコモン型の7セグメントディスプレイで正しく数字が表示されるようにしています。

カソードコモン型の7セグメントディスプレイを使用する場合は、SEGCODEのパターンをhc595_shift関数にそのまま渡せばOKです。(コメントアウトされているhc595_shiftのロジックを適用すれば動作します。)

Arduino

const int STcp = 27;  //ST_CP
const int SHcp = 26;  //SH_CP
const int DS = 28;    //DS

int datArray[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };

void setup() {
  //set pins to output
  pinMode(STcp, OUTPUT);
  pinMode(SHcp, OUTPUT);
  pinMode(DS, OUTPUT);
}

void loop() {
  for (int num = 0; num < 10; num++) {
    digitalWrite(STcp, LOW);  //ground ST_CP and hold low for as long as you are transmitting
    // shiftOut(DS, SHcp, MSBFIRST, datArray[num]);
    // 7セグがアノードコモンの場合はビットを反転する
    shiftOut(DS, SHcp, MSBFIRST, ~datArray[num]);
    digitalWrite(STcp, HIGH);  //pull the ST_CPST_CP to save the data
    delay(500);
  }
}

dataArrayに0から9の表示パターンを16進数で定義しています。

shiftOut関数を使って、シフトレジスタに表示パターンのビット列を書き込みます。

書き込む際に、dataArrayのパターンに対してnotをとることでビット列を反転させています。この処理によりアノードコモン型の7セグメントディスプレイで正しく数字が表示されるようにしています。

カソードコモン型の7セグメントディスプレイを使用する場合は、dataArrayのパターンをそのまま書き込めばOKです。(コメントアウトされているshiftOutのロジックを適用すれば動作します。)

数字(0から9)の表示にアニメーションを加える

応用編として、上記のプログラムにアニメーションを加えてみました。

MicroPython

import machine
import time

# Define the segment code for a common anode 7-segment display
SEGCODE = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F]

ANIMEPATTERN = [0x5F, 0x1E, 0x5C, 0x58, 0x50, 0x70, 0x21, 0x23]

# Initialize the pins for the 74HC595 shift register
sdi = machine.Pin(28, machine.Pin.OUT)  # DS
rclk = machine.Pin(27, machine.Pin.OUT)  # STcp
srclk = machine.Pin(26, machine.Pin.OUT)  # SHcp


# Define the hc595_shift function to shift data into the 74HC595 shift register
def hc595_shift(dat):
    # Set the RCLK pin to low
    rclk.off()

    # Iterate through each bit (from 7 to 0)
    for bit in range(7, -1, -1):
        # Extract the current bit from the input data
        value = 1 & (dat >> bit)

        # Set the SRCLK pin to low
        srclk.off()

        # Set the value of the SDI pin
        sdi.value(value)

        # Clock the current bit into the shift register by setting the SRCLK pin to high
        srclk.on()

    # Latch the data into the storage register by setting the RCLK pin to high
    rclk.on()


while True:
    for segcode in SEGCODE:
        for pattern in ANIMEPATTERN:
            # 7セグがアノードコモンの場合、SEGCODEをビット反転する
            hc595_shift(~pattern)
            # 7セグがカソードコモンの場合はそのまま渡す
            # hc595_shift(pattern)
            time.sleep_ms(50)
        hc595_shift(~segcode)
        # 7セグがカソードコモンの場合はそのまま渡す
        # hc595_shift(segcode)
        time.sleep(1)

    # 非表示
    hc595_shift(~0)
    # 7セグがカソードコモンの場合はそのまま渡す
    # hc595_shift(0)
    time.sleep(3)

数字のパターンを表示する前にアニメーションを表示するループを加えています。
アニメーションの表示パターンはANIMEPATTERN配列で定義しています。

Arduino

const int STcp = 27;  //ST_CP
const int SHcp = 26;  //SH_CP
const int DS = 28;    //DS

// 数字(0から9)のパターン
int datArray[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
// アニメーションパターン
int animePattern[] = { 0x5F, 0x1E, 0x5C, 0x58, 0x50, 0x70, 0x21, 0x23 };

// 74HC595のST_CPのLOW、HIGH処理(ラッチ)を加えた関数
void hc595_shift(int data) {
  digitalWrite(STcp, LOW);
  shiftOut(DS, SHcp, MSBFIRST, data);
  digitalWrite(STcp, HIGH);
}

void setup() {
  //set pins to output
  pinMode(STcp, OUTPUT);
  pinMode(SHcp, OUTPUT);
  pinMode(DS, OUTPUT);
}

void loop() {
  for (int num = 0; num < 10; num++) {
    for (int i = 0; i < sizeof(animePattern) / sizeof(animePattern[0]); i++) {
      // アニメーションのパターンを表示
      hc595_shift(~animePattern[i]);
      // 7セグがカソードコモンの場合はそのまま渡す
      // hc595_shift(animePattern[i]);
      delay(50);
    }

    // 数字のパターンを表示
    hc595_shift(~datArray[num]);
    // 7セグがカソードコモンの場合はそのまま渡す
    // hc595_shift(datArray[i]);
    delay(1000);
  }

  // 非表示
  hc595_shift(~0);
  // 7セグがカソードコモンの場合はそのまま渡す
  // hc595_shift(0);

  delay(3000);
}

数字のパターンを表示する前にアニメーションを表示するループを加えています。
アニメーションの表示パターンはanimePattern配列で定義しています。

7セグのaからdpを順番に点灯させて逆順に消灯させる

MicroPython

import machine
import time

# Initialize the pins for the 74HC595 shift register
sdi = machine.Pin(28, machine.Pin.OUT)  # DS
rclk = machine.Pin(27, machine.Pin.OUT)  # STcp
srclk = machine.Pin(26, machine.Pin.OUT)  # SHcp


# Define the hc595_shift function to shift data into the 74HC595 shift register
def hc595_shift(dat):
    # Set the RCLK pin to low
    rclk.off()

    # Iterate through each bit (from 7 to 0)
    for bit in range(7, -1, -1):
        # Extract the current bit from the input data
        value = 1 & (dat >> bit)

        # Set the SRCLK pin to low
        srclk.off()

        # Set the value of the SDI pin
        sdi.value(value)

        # Clock the current bit into the shift register by setting the SRCLK pin to high
        srclk.on()

    # Latch the data into the storage register by setting the RCLK pin to high
    rclk.on()


ledPattern = 0
hc595_shift(~ledPattern)
time.sleep_ms(500)

while True:
    for num in range(16):
        if num < 8:
            ledPattern = (ledPattern << 1) | 1
        else:
            ledPattern >>= 1
        # 7セグがアノードコモンの場合、ビット反転(not)する
        hc595_shift(~ledPattern)
        # 7セグがカソードコモンの場合はそのまま渡す
        # hc595_shift(ledPattern)
        time.sleep_ms(500)  # Wait 500 milliseconds before displaying the next number

このプログラムでは、アノードコモン型の7セグメントディスプレイで正しく表示するためのビット反転処理にnot(~ledPattern)を使っています。

Arduino

const int STcp = 27;  //ST_CP
const int SHcp = 26;  //SH_CP
const int DS = 28;    //DS

void setup() {
  //set pins to output
  pinMode(STcp, OUTPUT);
  pinMode(SHcp, OUTPUT);
  pinMode(DS, OUTPUT);

  // 7セグを非表示にする
  digitalWrite(STcp, LOW);
  shiftOut(DS, SHcp, MSBFIRST, ~0);
  digitalWrite(STcp, HIGH);
  delay(500);  // 非表示の状態を500ms作る
}

void loop() {
  static int i;
  uint8_t ledPattern = 0;

  // 7セグのaからdpまで順番に点灯させ、反対にdpからaまで順番に消灯させる
  for (i = 0; i < 8 * 2; i++) {
    if (i < 8) {
      ledPattern = (ledPattern << 1) | 1;
    } else {
      ledPattern >>= 1;
    }

    digitalWrite(STcp, LOW);
    shiftOut(DS, SHcp, MSBFIRST, ~ledPattern);
    digitalWrite(STcp, HIGH);
    delay(500);
  }
}

このプログラムでは、アノードコモン型の7セグメントディスプレイで正しく表示するためのビット反転処理にnot(~ledPattern)を使っています。

ビットシフトの解説

このプログラムのビットシフト処理は以下のようになっています。

ロジックの動作

0~7回目

ledPattern = (ledPattern << 1) | 1 により、右端(Q0)から 1 を入れながら左にシフトする

8~15回目

ledPattern >>= 1 により、左端(Q7)から 0 になりながら右にシフトしていく

ビットの遷移

回数Q7 (dp)Q6 (g)Q5 (f)Q4 (e)Q3 (d)Q2 (c)Q1 (b)Q0 (a)
000000001
100000011
200000111
300001111
400011111
500111111
601111111
711111111
801111111
900111111
1000011111
1100001111
1200000111
1300000011
1400000001
1500000000

【対応関係】  
Q7~Q0 → 74HC595の出力ピン
dp, g, f, e, d, c, b, a → 7セグメントディスプレイのセグメント

シフト演算と論理演算をうまく組み合わせることで、7セグ表示用のビットパターンを一つ一つ用意しなくても、簡単に表示できるようになります。これによって、コードがシンプルになり、管理もしやすくなります。

まとめ

今回は、Raspberry Pi Picoとアノードコモン型の7セグメントディスプレイ、シフトレジスタ(74HC595)を使って、0から9の数字を表示しました。

アノードコモン型の7セグメントディスプレイでは、表示パターンのビット列をカソードコモンとは逆にする必要があり、少し考え方のコツが要ります。
「ON/OFFの関係が反転する」 と意識すると分かりやすいかもしれません。

関連記事

当ブログのマイコン記事です。ぜひご覧ください。

この記事を書いた人
あろっち

元ITエンジニアです。

当ブログでは、興味があること、役に立ちそうなこと、気になったことを発信していきます。

記事についてのコメントや質問があれば、ぜひお寄せください。
また、ご依頼等は「お問い合わせ」よりお気軽にご連絡ください。

あろっちをフォローする
Raspberry Pi/電子工作IT
あろっちをフォローする

コメント

タイトルとURLをコピーしました