夏休みの宿題のつもりで、去年7月に購入したELEGOO Arduino用Mega2560スタータキットですが、結局、平成のうちにLessonを完了できることができませんでした。
現在、Lesson 23 まで完了。Lesson は 33 まであるので、あと10。せめて、購入から1年以内には完了したいところなので、ラストスパートがんばります!
Lesson 24 Eight LED with 74HC595
8つのLEDをコントロールしたい時、単純に考えれば、制御用にピンを8個使うことになります。まあ、それでもいいのですが、ピンの数には上限があるので、他にもつなげたいものがある時とか、LEDがもっと増えた時とか、これだと手詰まりになりますね。
ここでは、少ないピンでコントロールするために制御用のチップを使います。
「74HC595」シフトレジスタ、シリアルをパラレルに変換するコンバーターです。3つのピンへの入力で、8つの出力を制御できます。(今回のLED数にピッタリ!とのこと)
8個のピンを使って制御するよりも、制御できる速度は落ちてしまって、8個のピンを使った場合には1秒間に8,000,000回、今回の方法だと1秒間に500,000回の制御が可能。数字だと、結構差はありますが、それでも人間の認識速度に対しては十分な早さがあるので、問題ないとのことです。
Arduinoとの接続は3本+5V/GNDでシンプルですが、チップからの配線もあるのでそれなりにゴチャゴチャしますね。
Arduinoからの接続は、Clock / Data / Latch の3本。クロックタイミングに合わせて、データを1ビットずつ順に8ビット分送信。
ラッチをHIGHにすると、その時のシフトレジスタの状態がストレージレジスタにコピーされて固定される…ようです。
テストプログラムはこちら。
//www.elegoo.com //2016.12.9 int tDelay = 100; int latchPin = 11; // (11) ST_CP [RCK] on 74HC595 int clockPin = 9; // (9) SH_CP [SCK] on 74HC595 int dataPin = 12; // (12) DS [S1] on 74HC595 byte leds = 0; void updateShiftRegister() { digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, leds); digitalWrite(latchPin, HIGH); } void setup() { pinMode(latchPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); } void loop() { leds = 0; updateShiftRegister(); delay(tDelay); for (int i = 0; i < 8; i++) { bitSet(leds, i); updateShiftRegister(); delay(tDelay); } }
セットアップでは、latchPin / dataPin / clockPin それぞれのピンをOUTPUTに設定
ループでは、bitSet(leds, i) で、データをセットして updateShiftRegister() で、LED状態を更新しています。
bitSet(x, n)
n: セットしたいビットの指定,一番右である最下位ビット(LSB)が0
https://www.arduino.cc/reference/jp/language/functions/bits-and-bytes/bitset/
leds 変数のビットを最下位ビットから順にセットしていきます。
00000000 00000001 00000011 00000111
こんな感じですね。8個セット終わったら、leds = 0 に戻して何回も繰り返し。
updateShiftRegisterでは、まず latchPin をLOWにしておいて、shiftOut(dataPin, clockPin, LSBFIRST, leds) でleds のデータを設定します。
shiftOut(dataPin, clockPin, bitOrder, value)
https://www.arduino.cc/reference/jp/language/functions/advanced-io/shiftout/
shiftOut の動作を完全に理解できてないのですが、bitOrderに設定した側のビットから、clockPin でクロックを送りつつ、1ビットずつdataPinに送信してくれる、…ってことでいいのかな。bitOrderは、MSBFIRST (最上位ビット側から) または LSBFIRST(最下位ビット側から)が設定できます。
shiftOutでデータを送信した後、latchPin をHIGHにすると、外部出力用のストレージレジスタにデータが反映されて、LED状態が変化します。
ということで、実行!
ELEGOO Lesson 24 pic.twitter.com/fSSPFOktce
— Nochi (@shikarunochi) 2019年5月2日
Lesson 25 The Serial Monitor
シリアルモニタです。これまでも普通に使ってきてたので、いまさらではありますが。
Serial.begin(9600);
で、9600bps でシリアル接続起動。PC側のシリアルモニタの通信速度を合わせるのを忘れずに。
Arduinoの種類によって、PCからシリアル接続したときに、自動的にリセットされるものとそうでないものがあるみたいですね。(Arduino MEGA 2560は自動的にリセットされる。)
今回のプログラムでは、シリアルモニタからの入力でLEDの状態を変化させる仕掛けになっています。
シリアル入力があった場合、 Serial.available() が true になり、
char ch = Serial.read();
でデータを入力バッファから読むことができます。同時に、入力バッファから読み込んだデータを消去します。
Lesson 26 Photocell
フォトセルです。
M5Stackの光通信やったときにも、使わせてもらいました。
M5Stack:光通信
http://shikarunochi.matrix.jp/?p=2629
明るさによって抵抗値の変わる部品です。だいたい、50kΩ(暗いところ)~500Ω(明るいところ)で
変化します。
今回は、Lesson 24 のLED表示と組み合わせて、周囲の明るさによってLEDの状態を変化させます。
1kΩの抵抗と図のように接続することで、明るさに応じてA0の値が変化します。
値はアナログで取得。
int reading = analogRead(lightPin);
ここでは、フォトセル1kΩの時を一番暗い状態として、値を設定します。
アナログ入力は0~1023の値をとるので、フォトセルの抵抗値がちょうど 1kΩになったときに、半分の1023 / 2になります。なので、それを9つのエリア(LED 0個~8個)に分割して、1023 / 2 / 9 ≒ 57。
入力値57増えるごとに、光るLED一つ増やします。ということで、光らせるLEDの数を、
int numLEDSLit = reading / 57;
で計算。
leds = 0; // no LEDs lit to start for (int i = 0; i < numLEDSLit; i++) { leds = leds + (1 << i); // sets the i'th bit }
numLEDSLitの数だけ、下からビットを立てていきます。
後は Lesson 24 と同じく updateShiftRegister(); で LEDの状態を更新。
実行!部屋の明かりを暗くしてみると、それに応じて光るLEDの数が変化します。
ELEGOO Lesson 26 pic.twitter.com/YXiJhoCglE
— Nochi (@shikarunochi) 2019年5月2日