初めに
アクセスしていただきありがとうございます。
こちらの記事はシフトレジスタをarduinoで制御するプログラムとそれに関する情報を記載したものです。
シフトレジスタとは
シフトレジスタは少量のデータを保存するICです。
D-FFを直列につなげて作られており、8bitのデータを保存できます。
シフトレジスタのメリット
マイコンの代名詞ともいえるarduinoには18本のピンがあり、このピンを使って信号を送受信することができる。
18ピンというと多いように感じますが、8×8ドットマトリクスなどの電子部品を使用したり、多数のセンサーを搭載するとなると、18ピンでは足りない場合があります。
そんなときに使うのが、シフトレジスタです。
出力を増やすか入力を増やすかは、シフトレジスタの種類によって異なり、
今記事では出力を増やす方法について書いてあります。
配線と役割(8個の制御)
プログラム(8個の制御)
どのようなプログラムを書くかは皆さんの自由ですが、ここでは理解の助けになるようなプログラムを書きます。
複数のプログラムを書きます、Arduino IDEに書いてくださいね。
#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を全部消すための、関数です。今後説明するときがあるのでそれを読もう。
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の役割をメインにプログラムを書きます。
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を繰り返しながらシフトするプログラムです
#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 記事を書き換えました