7seg+NANO(2) シフトレジスタ
7seg+NANO(1)でNANOからのコントロールを試みたが、ケタ数が3ケタのときはチラついたり暗くなったりした。そこで今度はシフトレジスタU74HC595Aを使ってみた。
0 シフトレジスタ
流れは以下の通り
① $${\overline{\text{SRCLR}}}$$ → LOW(初期化)→HIGH(戻す)
または、$${\overline{\text{SRCLR}}}$$を5Vに繋いでおく
② SERとSRCLKを使ってシリアルデータをパラレルに変換
③ RCLK → HIGH($${Q_A ~ Q_B}$$から出力)→ LOW(戻す)
1 予行演習(LED8個)
ピンの割り当て
SER = 8、RCLK = 9、SRCLK = 10、(SRCLR = 11)
SRCLK はNANOではなく5Vに繋いでも問題なかった。
/* NANO_shift_register_02.ino
シフトレジスタでLEDを制御する ①
https://www.msyoukai.com/robot/arduino_011/#l13
Arduino NANO serial port is COM3 for hp_PC.
1・ ・VIN 3,11 is interfered by tone().
0・ ・GND A6,A7 is analog only.
Reset・ ・Reset
GND・ ・5V
2・ ・A7
3・ ・A6
4・ ・19/A5
5・ ・18/A4
6・ ・17/A3
7・ ・16/A2
74HC595_SER <-- 8・ ・15/A1
74HC595_RCLK <-- 9・ ・14/A0
74HC595_SRCLK <--10・ ・AREF
74HC595_SRCLR <--11・ ・3.3V
12・ USB ・13
U74HC595A
LED_b <-- Qb/1・ 〇 ・16/VCC ---> 5V
LED_c <-- Qc/2・ ・15/Qa ----> LED_a
LED_d <-- Qd/3・ ・14/SER ---> NANO_8
LED_e <-- Qe/4・ ・13/OE ----> GND
LED_f <-- Qf/5・ ・12/RCLK --> NANO_9
LED_g <-- Qg/6・ ・11/SRCLK -> NANO_10
LED_h <-- Qh/7・ ・10/SRCLR -> 5V
GND <- GND/8・ ・9/Qh'
*/
int const SER = 8; // ピンの割り当て
int const RCLK = 9;
int const SRCLK = 10;
//int const SRCLR = 11; // SRCLRは5Vに繋いでもよい
void setup() {
pinMode(SER, OUTPUT); // 出力設定
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
// pinMode(SRCLR, OUTPUT);
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
}
byte data[8] = {
B10000000,
B01000000,
B00100000,
B00010000,
B00001000,
B00000100,
B00000010,
B00000001,
};
void loop() {
for (int i = 0; i < 8; i++) {
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
digitalWrite(RCLK, LOW); //シリパラ変換
shiftOut(SER, SRCLK, LSBFIRST, data[i]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
delay(100);
}
}
2 予行演習(LED16個、カスケード接続)
次にシフトレジスタを2個カスケード接続してLED18個の制御を試みた。
接続はSERの経路は直列、RCLKとSRCLKは並列にする。
NANO_8 => (1)SER、(1)Qh' => (2)SER
NANO_9 => (1)RCLK & (2)RCLK
NANO_10 => (1)SRCLK & (2)SRCLK
/* NANO_shift_register_03.ino
シフトレジスタ (74HC595) のカスケード接続
Arduino NANO serial port is COM3 for hp_PC.
1・ ・VIN 3,11 is interfered by tone().
0・ ・GND A6,A7 is analog only.
Reset・ ・Reset
GND・ ・5V
2・ ・A7
3・ ・A6
4・ ・19/A5
5・ ・18/A4
6・ ・17/A3
7・ ・16/A2
74HC595_SER <-- 8・ ・15/A1
74HC595_RCLK <-- 9・ ・14/A0
74HC595_SRCLK <--10・ ・AREF
74HC595_SRCLR <--11・ ・3.3V
12・ USB ・13
U74HC595A(1)
LED_b <-- Qb/1・ 〇 ・16/VCC <--- 5V
LED_c <-- Qc/2・ ・15/Qa ----> LED_a
LED_d <-- Qd/3・ ・14/SER <--- NANO_8
LED_e <-- Qe/4・ ・13/OE ----> GND
LED_f <-- Qf/5・ ・12/RCLK <-- NANO_9 & (2)12/RCLK
LED_g <-- Qg/6・ ・11/SRCLK <- NANO_10 & (2)11/SRCLK
LED_h <-- Qh/7・ ・10/SRCLR <- 5V
GND <- GND/8・ ・9/Qh' ----> (2)14/SER
U74HC595A(2)
LED_b2 <-- Qb/1・ 〇 ・16/VCC <--- 5V
LED_c2 <-- Qc/2・ ・15/Qa ----> LED_a2
LED_d2 <-- Qd/3・ ・14/SER <--- (1)9/Qh'
LED_e2 <-- Qe/4・ ・13/OE ----> GND
LED_f2 <-- Qf/5・ ・12/RCLK <-- NANO_9 & (1)12/RCLK
LED_g2 <-- Qg/6・ ・11/SRCLK <- NANO_10 & (2)11/SRCLK
LED_h2 <-- Qh/7・ ・10/SRCLR <- 5V
GND <- GND/8・ ・9/Qh'
*/
int const SER = 8; // ピンの割り当て
int const RCLK = 9;
int const SRCLK = 10;
//int const SRCLR = 11; // SRCLRは5Vに繋いでもよい
void setup() {
pinMode(SER, OUTPUT); // 出力設定
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
// pinMode(SRCLR, OUTPUT);
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
}
byte data_1[16] = {
B10000000, B01000000, B00100000, B00010000,
B00001000, B00000100, B00000010, B00000001,
B00000000, B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000, B00000000,
};
byte data_2[16] = {
B00000000, B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000, B00000000,
B10000000, B01000000, B00100000, B00010000,
B00001000, B00000100, B00000010, B00000001,
};
void loop() {
for (int i = 0; i < 16; i++) {
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
digitalWrite(RCLK, LOW); //シリパラ変換
shiftOut(SER, SRCLK, LSBFIRST, data_2[i]);
shiftOut(SER, SRCLK, LSBFIRST, data_1[i]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
delay(100);
}
}
3 予行演習(LED16個、シフトレジスタ1個)
配線は以下の通り
Qa~Qd:LEDの-側をLOW
Qe~Qh:LEDの+側をHIGH にしてLEDを点灯させる
データの例
/* NANO_shift_register_04.ino(1個で16LED)
Arduino NANO serial port is COM3 for hp_PC.
1・ ・VIN 3,11 is interfered by tone().
0・ ・GND A6,A7 is analog only.
Reset・ ・Reset
GND・ ・5V
2・ ・A7
3・ ・A6
4・ ・19/A5
5・ ・18/A4
6・ ・17/A3
7・ ・16/A2
74HC595_SER <-- 8・ ・15/A1
74HC595_RCLK <-- 9・ ・14/A0
74HC595_SRCLK <--10・ ・AREF
(74HC595_SRCLR <--)11・ ・3.3V
12・ USB ・13
U74HC595A
LED-_3,7,11,5 <-- Qb/1・ 〇 ・16/VCC ---> 5V
LED-_2,6,10,14 <-- Qc/2・ ・15/Qa ----> LED-_4,8,12,16
LED-_1,5,9,10 <-- Qd/3・ ・14/SER ---> NANO_8
LED+_1,2,3,4 <-- Qe/4・ ・13/OE ----> GND
LED+5,6,7,8 <-- Qf/5・ ・12/RCLK --> NANO_9
LED+_9,10,11,12 <-- Qg/6・ ・11/SRCLK -> NANO_10
LED+_13,14,15,16 <-- Qh/7・ ・10/SRCLR -> 5V
GND <- GND/8・ ・9/Qh'
*/
int const SER = 8; // ピンの割り当て
int const RCLK = 9;
int const SRCLK = 10;
//int const SRCLR = 11; // SRCLRは5Vに繋いでもよい
void setup() {
pinMode(SER, OUTPUT); // 出力設定
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
// pinMode(SRCLR, OUTPUT);
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
}
byte data[16] = {
B11101000, B11011000, B10111000, B01111000,
B11100100, B11010100, B10110100, B01110100,
B11100010, B11010010, B10110010, B01110010,
B11100001, B11010001, B10110001, B01110001,
};
void loop() {
for (int i = 0; i < 16; i++) {
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
digitalWrite(RCLK, LOW); //シリパラ変換
shiftOut(SER, SRCLK, LSBFIRST, data[i]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
delay(100);
}
}
これでシフトレジスタの大体の仕様はわかった。
いよいよ7セグでやってみる。
4 やっと本番4ケタ7セグ(シフトレジスタ1個)
デジットのワゴンで買った4ケタの12ピンの7セグを使用。(TOF-3407HS-B と表記されている) 通電して調べた各ピンの割当てと配線を以下に示す。
/* NANO_shift_register_05.ino(4ケタ7セグ)
シフトレジスタで4ケタ7セグを制御する
Arduino NANO serial port is COM3 for hp_PC.
1・ ・VIN 3,11 is interfered by tone().
0・ ・GND A6,A7 is analog only.
Reset・ ・Reset
GND・ ・5V
2・ ・A7
3・ ・A6
4・ ・19/A5
5・ ・18/A4
6・ ・17/A3
7・ ・16/A2
74HC595_SER <-- 8・ ・15/A1
74HC595_RCLK <-- 9・ ・14/A0
74HC595_SRCLK <--10・ ・AREF
74HC595_SRCLR <--11・ ・3.3V
12・ USB ・13
U74HC595A
b <-- Qb/1・ 〇 ・16/VCC ---> 5V
c <-- Qc/2・ ・15/Qa ----> a
d <-- Qd/3・ ・14/SER ---> NANO_8
e <-- Qe/4・ ・13/OE ----> GND
f <-- Qf/5・ ・12/RCLK --> NANO_9
g <-- Qg/6・ ・11/SRCLK -> NANO_10
DP <-- Qh/7・ ・10/SRCLR -> 5V
GND <- GND/8・ ・9/Qh'
TOF-3407HS-B
1/e・ --> Qe
2/dig1000・<-- NANO_7
3/dig100・<-- NANO_6
4/d・--> Qd
5/g・--> Qg
6/dig10・<-- NANO_5
7/b・--> Qb
8/a・--> Qa
9/f・--> Qf
10/dig1・<-- NANO_4
11/DP・-->Qh
12/c・--> Qc
*/
#include <MsTimer2.h>
int const dig_1 = 4; // ピンの割り当て
int const dig_10 = 5;
int const dig_100 = 6;
int const dig_1000 = 7;
int const SER = 8; // ピンの割り当て
int const RCLK = 9;
int const SRCLK = 10;
//int const SRCLR = 11; // SRCLRは5Vに繋いでもよい
int num = 0; // 表示する数
int old_num;
int t = 10; // スキャンする時間(usec) //10usecでチラつかないが、暗くて見えない
int t2 = 0;
void setup() {
Serial.begin(9600);
pinMode(dig_1, OUTPUT); // 出力設定
pinMode(dig_10, OUTPUT);
pinMode(dig_100, OUTPUT);
pinMode(dig_1000, OUTPUT);
pinMode(SER, OUTPUT); // 出力設定
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
// pinMode(SRCLR, OUTPUT);
// digitalWrite(SRCLR, LOW); //初期化
// digitalWrite(SRCLR, HIGH);
// disp_num(1234);
MsTimer2::set(500, count_up); // 500msごとにオンオフ
MsTimer2::start();
}
void count_up() {
num++;
}
byte data[10] = {
B00000011,
B10011111,
B00100101,
B00001101,
B10011001,
B01001001,
B01000001,
B00011111,
B00000001,
B00001001,
};
void disp_num(int i) {
int d_1000, d_100, d_10, d_1;
d_1000 = i / 1000;
d_100 = (i - 1000 * d_1000) / 100;
d_10 = (i - 1000 * d_1000 - 100 * d_100) / 10;
d_1 = i - 1000 * d_1000 - 100 * d_100 - 10 * d_10;
Serial.print("i= "); Serial.println(i);
Serial.print("d_1000= "); Serial.println(d_1000);
Serial.print("d_100= "); Serial.println(d_100);
Serial.print("d_10= "); Serial.println(d_10);
Serial.print("d_1= "); Serial.println(d_1);
digitalWrite(RCLK, LOW); //シリパラ変換 // 千位
shiftOut(SER, SRCLK, LSBFIRST, data[d_1000]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
digitalWrite(dig_1000, HIGH);
delayMicroseconds(t);
digitalWrite(dig_1000, LOW);
delayMicroseconds(t2);
digitalWrite(RCLK, LOW); //シリパラ変換 // 百位
shiftOut(SER, SRCLK, LSBFIRST, data[d_100]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
digitalWrite(dig_100, HIGH);
delayMicroseconds(t);
digitalWrite(dig_100, LOW);
delayMicroseconds(t2);
digitalWrite(RCLK, LOW); //シリパラ変換 // 十位
shiftOut(SER, SRCLK, LSBFIRST, data[d_10]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
digitalWrite(dig_10, HIGH);
delayMicroseconds(t);
digitalWrite(dig_10, LOW);
delayMicroseconds(t2);
digitalWrite(RCLK, LOW); //シリパラ変換 // 一位
shiftOut(SER, SRCLK, LSBFIRST, data[d_1]);
// shiftOut(SER, SRCLK, MSBFIRST, data[i]); // データの向きが逆になる
digitalWrite(RCLK, HIGH);
digitalWrite(dig_1, HIGH);
delayMicroseconds(t);
digitalWrite(dig_1, LOW);
delayMicroseconds(t2);
}
void loop() {
// for (int i = 0; i < 1000; i++) {
disp_num(num);
Serial.println(num);
// delay(1000);
}
結果は、7segLEDのまとめでも書いた通り各ケタの点滅をチラつかなくなるまで(10μsec)速くすると表示が暗くて見えない。
これを解決する方法として
・コモンの抵抗値を下げる → ケタ数が多いとNANOの最大出力を超えるかも
・トランジスタで増幅する
が考えられる。
まずコモンの抵抗値を1kΩから330Ωにしてみた。しかし少し明るくなっただけでチラつかないのは10μsecだった。
各セグメントに流れる電流は抵抗が1kohmのとき
(5-1.8)V/1kohm=3.2×10^{-3}=3.2mA
330Ωのときは(5-1.8)V/330ohm=9.7×10^{-3}=9.7mA
である。0を表示するとき6つのセグメントに電流が流れるのでアノードから3.2×6=19.2mA、9.7×6=58.2mAの電流を供給することになり、NANOのmax20mAに近いか超えてしまう。シフトレジスタを触ったらアチチだった。これ以上セグメントの抵抗値を下げることは難しい。
おわりに
結果をまとめる。シフトレジスタはNANOと3本の線だけで情報のやり取りをおこなうことができる優れものである。複数のシフトレジスタをカスケード接続することで大量のON・OFFを制御することができる。しかし、電流値はNANOと同様max20mA程度である。これはLED単体を順にチラつかせるなしでは問題はないが、ダイナミック点灯でケタ数の大きい7セグを制御するときには暗くて使いものにならない。これはシフトレジスタを使わない場合でも同様である。→ 7seg+NANO(1)
下のようにセグメントの前後にトランジスタを置くことが望ましいと思われる。上流(アノード)側に2SA1015(PNP型)、下流側に2SC1815(NPN型)のトランジスタを置く方法が考えられる。そのうち試したい。