LoginSignup
0
0

シフトレジスタ(U74HC595AG)をつかって、大量のLEDを制御しよう(ShiftOut関数不使用)

Last updated at Posted at 2023-06-04

初めに

アクセスしていただきありがとうございます。
こちらの記事はシフトレジスタをarduinoで制御するプログラムとそれに関する情報を記載したものです。

シフトレジスタとは

シフトレジスタは少量のデータを保存するICです。
D-FFを直列につなげて作られており、8bitのデータを保存できます。

シフトレジスタのメリット

マイコンの代名詞ともいえるarduinoには18本のピンがあり、このピンを使って信号を送受信することができる。
18ピンというと多いように感じますが、8×8ドットマトリクスなどの電子部品を使用したり、多数のセンサーを搭載するとなると、18ピンでは足りない場合があります。
そんなときに使うのが、シフトレジスタです。
出力を増やすか入力を増やすかは、シフトレジスタの種類によって異なり、
今記事では出力を増やす方法について書いてあります。

配線と役割(8個の制御)

配線図とピンの役割を示した画像を載せます。
Untitled Sketch 2_ブレッドボード (1).png
U74HC595AG (2).png

プログラム(8個の制御)

どのようなプログラムを書くかは皆さんの自由ですが、ここでは理解の助けになるようなプログラムを書きます。
複数のプログラムを書きます、Arduino IDEに書いてくださいね。

最初に書かなきゃいけないプログラム.INO
#define SER		(2)
#define RCLK	(3)
#define SRCLK	(4)
 
void setup() {
  pinMode( SER,  OUTPUT );
  pinMode( RCLK, OUTPUT );
  pinMode( SRCLK, OUTPUT );
}
void initShiftRegister(){
  digitalWrite(RCLK, LOW);
  for(int i = 0; i < 8;i++){
    digitalWrite(SER, LOW);
//クロックパルスを立ち上げる
	digitalWrite(SRCLK, HIGH);
	digitalWrite(SRCLK, LOW);
//-----------------------------------------
  }
  digitalWrite(RCLK, HIGH);
}

これは最初に書くプログラムです、これを毎回書くのは行が増えてしまうので短縮のために、先に書きました。
initShiftRegister()は最初にLEDを全部消すための、関数です。今後説明するときがあるのでそれを読もう。

loop内のプログラム.INO
void loop() {
  initShiftRegister();
  for(;;){
    //データを送る前に呼び出す必要がある
    digitalWrite(RCLK, LOW);
    //送るデータ HIGH
    digitalWrite(SER, HIGH);
    //おまじないです考えるな
	digitalWrite(SRCLK, HIGH);
	digitalWrite(SRCLK, LOW);
    //----------------------
    //データを送った後に呼び出す必要がある
    digitalWrite(RCLK, HIGH);
    delay(500);
    for(int i = 0; i < 7;i++){
      digitalWrite(RCLK, LOW);
      //送るデータ LOW
      digitalWrite(SER, LOW);
			
	  digitalWrite(SRCLK, HIGH);
	  digitalWrite(SRCLK, LOW);
      digitalWrite(RCLK, HIGH);
      delay(500);
    }
  }
}

このプログラムをコンパイルして出力すると、出力1から出力8へシフトしていく動きになります。
これがその動画です。
イメージ
SERがHIGHだと出力1をHIGHにして、LOWだと出力1をLOWにする仕組みで、
SERを送るとその前のデータは出力1から出力2にシフトします、
このプログラムは最初にHIGHを出力した後7回LOWを出力しています。
例えば以下のようにSERにデータを出力したとします。
出力(SERを"H,H,L,L,H,H,L,L"の順に出力) //RCLKも出力の合間に入れてある。
LEDはこのように出力されます。
LED L, L, H, H, L, L, H, H
イメージ図
イメージ
わかってきましたかでは次にRCLKの役割をメインにプログラムを書きます。

配列で光る位置を指定するやり方.INO
void loop() {
  int Row = 0, Column = 0;
  int Array1[3][8] = {{1,1,1,0,1,1,1,0},
                     {1,1,0,1,1,1,0,0},
                     {1,1,1,1,1,0,0,0}};
  for(;;){
    initShiftRegister();
    Row++;
    if(Row == 3){
      Row = 0;
    }
    digitalWrite(RCLK, LOW);
    for(int Column = 0; Column < 8;Column++){
      if(Array1[Row][Column] == 1){
        digitalWrite(SER, HIGH);
      }
      else {
        digitalWrite(SER, LOW);
      }
			
		digitalWrite(SRCLK, HIGH);
	  digitalWrite(SRCLK, LOW);
    }
    digitalWrite(RCLK, HIGH);
    delay(1000);
  }
}

配列内に光る位置を指定するプログラムですが、RCLKの位置を見てください、
For分の外にあることでデータがすべてシフトレジスタに転送された後、出力されています。
これはinitShiftRegister()でも同じことをしています。
イメージはこのような感じです。
イメージ
(余談ですがここで使っているinitShiftRegisterはイニシャライズ関数として使っています、
しかしこのプログラムでは、何度もResetのために使っています。
この場合initShiftRegisterという名称は有効でなくResetShiftRegisterに変えるのが良いと思います。)

このプログラムは少し複雑で、2次配列を使うため2重の繰り返しを行っています。

シフトレジスタを複数個使うには?

さて、いままで書いてきた内容はすべてシフトレジスタを1つだけ使ったときのことでした。
しかしもっとたくさんpinを使いたいという強欲な方もいるでしょう。
実はシフトレジスタは複数個並べて使用することもできます
つまりピン3個で16個のLEDを使うこともできます。

配線図(16個の制御)

配線図です。
イメージ
見ると、SER(N)と書いてあったピンの役割のところがSERに接続されています。
それ以外は特に変わったことはないです。
今後は下のシフトレジスタがシフトレジスタ2上のシフトレジスタが1とします

プログラム(16個の制御)

これも特に変わったことはなく、入れられるデータが8個から16個に変わっただけです。
シフトレジスタ1の出力1から シフトレジスタ2の出力8までHIGHとLOWを繰り返しながらシフトするプログラムです

シフトしていく.INO
#define SER		(2)
#define RCLK	(3)
#define SRCLK	(4)
 
void setup() {
  pinMode( SER,  OUTPUT );
  pinMode( RCLK, OUTPUT );
  pinMode( SRCLK, OUTPUT );
}
void initShiftRegister(){
  digitalWrite(RCLK, LOW);
  for(int i = 0; i < 16;i++){
    digitalWrite(SER, LOW);
			
		digitalWrite(SRCLK, HIGH);
	  digitalWrite(SRCLK, LOW);
  }
  digitalWrite(RCLK, HIGH);
}
void loop() {
  initShiftRegister();
  for(;;){
    digitalWrite(RCLK, LOW);
    digitalWrite(SER, HIGH);

	digitalWrite(SRCLK, HIGH);
	digitalWrite(SRCLK, LOW);
    
    digitalWrite(RCLK, HIGH);
    delay(500);

    digitalWrite(RCLK, LOW);
    digitalWrite(SER, LOW);

	digitalWrite(SRCLK, HIGH);
	digitalWrite(SRCLK, LOW);

    digitalWrite(RCLK, HIGH);
    delay(500);
  }
}

見て頂くと、initShiftRegisterの条件文がi < 8 から i < 16に変わっています。
それ以外はいつも通りのプログラムですね。
動作動画です
イメージ
最後にまとめのプログラムとして、2次配列に光らせる位置を書いてそれを実行するプログラムです。

配列に光らせる位置を指定するプログラム
#define SER		(2)
#define RCLK	(3)
#define SRCLK	(4)
//シフトレジスタの個数(Number of shift registers)
#define NSR (2)
void setup() {
  pinMode( SER,  OUTPUT );
  pinMode( RCLK, OUTPUT );
  pinMode( SRCLK, OUTPUT );
}
//初期化の関数
void initShiftRegister(){
  digitalWrite(RCLK, LOW);
  for(int i = 0; i < NSR * 8;i++){
    digitalWrite(SER, LOW);
			
	digitalWrite(SRCLK, HIGH);
	digitalWrite(SRCLK, LOW);
  }
  digitalWrite(RCLK, HIGH);
}
//array : 光らせる位置の入れる2次配列
//Rows  : 2次配列の行数(縦のこと)
void SetLED(int array[][8], int Rows){
  digitalWrite(RCLK, LOW);
  for(int Row = 0; Row < Rows; Row++){
    for(int Column = 0; Column < 8; Column++){
      if(array[Row][Column] == 1){
        digitalWrite(SER, HIGH);
		digitalWrite(SRCLK, HIGH);
	    digitalWrite(SRCLK, LOW);
      }
      else {
        digitalWrite(SER, LOW);
		    digitalWrite(SRCLK, HIGH);
	      digitalWrite(SRCLK, LOW);
      }
    }
  }
  digitalWrite(RCLK, HIGH);
}

void loop() {
  initShiftRegister();
  //LEDの点灯パターン
  int LEDPattern1[2][8] = {{1,0,1,0,1,0,1,0},{0,1,0,1,0,1,0,1}};
  int LEDPattern2[2][8] = {{0,1,0,1,0,1,0,1},{1,0,1,0,1,0,1,0}};
  for(;;){
    SetLED(LEDPattern1, 2);
    delay(500);
    SetLED(LEDPattern2, 2);
    delay(500);
  }
}

SetLEDを使えば簡単に光らせる位置を変えることができます。

終わりに

シフトレジスタは便利なICですが、扱いが難しいです。
そしてほとんどのサイトがShiftOut関数を使用しています。
この関数は2進数を使った制御文を書かないといけないのですが、2進数って扱いずらいしイメージがわかないから、配列にして書きました。
プログラムのソースコードはgithubで公開されています。
以下のURLを飛んでください。
GithubのURL
2023/6/23 記事を書き換えました

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0