🚥

Arduinoで早押しボタンを作る 【その8 シフトレジスタ】

2022/12/26に公開

はじめに

目標

  • 少ない配線で複数のLEDを制御する

というのも実際に筐体に入れようかなという段階になって、配線を考えていたらArduinoのデジタル入出力ピンが足りなそうなことに気が付きました

今回接続したいのは「早押しボタン」8個、「音声出力」1個、「電源表示のLED」1個、「正誤判定ボタン」各1個です
これを合計すると20となり、今回使用しているAE-ATMEGA328-MINIのデジタル入出力はカタログスペック上では20ピンあることになっているので問題なさそうです(ギリギリだけど)
しかし実際にはD0, D1ピンはプログラムの書き込み等に必要なRX, TXとして確保されていたり、SCKピンでは割り込みが想定通りに動作しなかったりと、事実上利用できないピンが存在します
これらを考慮すると

  • デバイスの制約で利用できないピン 2(D0, D1)
  • 早押しボタン以外の機能で使いたいピン
    正誤判定 2
    音声出力 1
    電源表示 1
  • 早押しボタンで使いたいピン
    (ボタン1 + LED1) * 8 = 16

となり、合計は22
足りません

D0, D1は無理に使おうと思えば使えないこともないのですがあまりやりたくないです
ボタンを2つ減らして6つにすれば足りますが、なんとなく気持ち悪いので8の方がいいです
空いているピンがない(=これ以上機能の拡張性がない)という状態も嫌なので、
少ない制御ピンで複数のLEDを制御する方法を考える必要があります

ここで登場するのがシフトレジスタIC(74HC595)です
結論だけ先に述べておくと、3つのピンで8個以上のLEDを制御することが可能となります

方法

シフトレジスタについては多くの解説記事が存在し、特に今回採用した74HC595も代表的なシフトレジスタICでArduinoの工作でもよく用いられるためたくさんの記事があります。詳細な解説はそれらの記事に譲りたいと思います
たとえばこの辺りを参考にさせてもらいました
https://iot.keicode.com/arduino/arduino-shift-register-sn74hc595.php
https://www.arduino.cc/en/Tutorial/Foundations/ShiftOut

8つものLEDを制御するので自ずと配線もプログラムも見づらくなります
したがって今回はこれまでの早押し回路、プログラムに直接機能を追加するのではなく、
単体の回路とプログラムでの動作確認について書いていきたいと思います

回路図


配線図
実際にはLEDのカソードを直接グランドに接続していますが、配線図上では部品が重なって見づらくなってしまうのでふしぎなグランド配線になっています

プログラム

ソースコード

// 74HC595の制御に使うピンを設定する
#define SER_74HC595 12   // Data pin of 74HC595
#define RCLK_74HC595 11  // Latch pin of 74HC595
#define SRCLK_74HC595 13 // Clock pin of 74HC595

/*
   setup() - this function runs once when you turn your Arduino on
   We initialize the serial connection with the computer
*/
void setup()
{
  // 74HC595用のピンはOUTPUTとして設定する
  pinMode(SER_74HC595, OUTPUT);
  pinMode(RCLK_74HC595, OUTPUT);
  pinMode(SRCLK_74HC595, OUTPUT);
}

/*
   loop() - this function runs over and over again
*/
void loop()
{
  // すべてのLEDを消灯する
  clearLed();
  delay(500);
  // Q7→Q6→………→Q0の順でLEDが点灯する
  for (int i = 0; i < 8; i++) // Turn all the LEDs ON one by one.
  {
    turnOnLed(i);
    delay(500);
  }
}

// すべてのLEDを消灯する
void clearLed(){  
  byte led = 0; 
  updateShiftRegister(led);
}

// n番目のLEDだけを点灯する
void turnOnLed(int n){
    byte led = 1 << n;
    updateShiftRegister(led);  
}

// 74HC595に制御信号を出力する
void updateShiftRegister(byte reg)
{
  digitalWrite(RCLK_74HC595, LOW);
  shiftOut(SER_74HC595, SRCLK_74HC595, LSBFIRST, reg);
  digitalWrite(RCLK_74HC595, HIGH);
}

たとえばbyte ledを関数の外でグローバルに持っておいて、turnOnLed(int n)の中身をled |= 1 << nに変えると、現在点灯しているLEDにプラスしてn番目のLEDを追加で点灯させたりもできます
●●●●●●●●→●●●●●●●○→●●●●●●○○…という動作になります
そしてもちろんbyte led = 0b00110011などと設定すれば●●○○●●○○のように任意の組み合わせでLEDを点灯することができます

結果

サンプルプログラムを実行することでLEDが順に点灯する様子を確認できました
また、この応用で8個のLEDを任意の組み合わせで点灯することができることがわかりました

まとめ

74HC595の活用によってArduinoのピンを3つ使うだけで8個のLEDが制御できるようになりました
これによりピンを5ピンも節約することができ、

  • デバイスの制約で利用できないピン 2(D0, D1)
  • 早押しボタン以外の機能で使いたいピン
    正誤判定 2
    音声出力 1
    電源表示 1
  • 早押しボタンで使いたいピン
    (ボタン1 + LED1) * 8 = 16
    ボタン1 * 8 = 8
  • 74HC595の制御ピン 3

となり、合計は17
無事3ピンの余裕ができました

空いたピンは今後何らかの機能を追加するときにも使えますし、
その分早押しボタンを増やすこともできます
やっとの思いで8個制御できるようになったのになにを言ってんだって感じですが、74HC595のカスケード接続を利用するとArduinoのピンは3つのままでさらにLEDを増やすことが可能です
くわしくはこちらを参照してください
https://iot.keicode.com/arduino/arduino-shift-register-sn74hc595-cascading.php

このあたりの拡張性もいいなーと思って今回はシフトレジスタを追加しました

Discussion