概要
第7回目です。前回は、Arduino(アルディーノ)のアナログ入力機能について「計測量を電圧変化として出力するセンサ」と組み合わせて使う方法を紹介しました。
今回は、その続きとして計測量を「電気抵抗変化として出力するセンサ」とアナログ入力機能を組み合わせて使う方法を勉強します。このタイプのセンサには、次のような製品があります。
- 光(明るさ)を計測するフォトレジスタ(CdSセル)
- CdSセル/光センサー(5φ) @ 共立エレショップ(約90円)
- 回転角を計測するポテンショメータ(可変抵抗、ボリューム)
- ローレット軸タイプ 炭素皮膜可変抵抗 Aカーブ 10kΩ @ 共立エレショップ(約90円)
- 直線変位を計測する リニアポテンショメータ(スライドボリューム)
- 2連スライドボリューム Aカーブ @ 共立エレショップ(約95円)
- 2軸ジョイスティックモジュール @ 秋月電子(約850円)
- ガスを検出するガスセンサ
- アルコールセンサ @ スイッチサイエンス(約750円)
- 水位(水面の高さ)を計測する水位センサ
- 水位センサ @ スイッチサイエンス(約5,900円)
- 土中に含まれる水分を計測する水分センサ
- 水分センサ @ スイッチサイエンス(約650円)
これらのセンサを利用すれば、アイデア次第で便利で有用な装置を自作できることが分かると思います。上記のセンサーうち、**赤文字のもの**は、TinkerCad Circuits の回路シミュレータで利用可能です。
光センサ(フォトレジスタ、CdSセル)
TinkerCad Circuits では、CdSセル(硫化カドミウムセル)タイプの光センサが利用できます。このセンサは、光の強さに応じて電気抵抗が大きく変化する素子で「光が当たると抵抗値が下がる」という特性があります。夕方から夜にかけて自動点灯する街路灯などに使われています。1個50円から150円程度で購入することができます。
実際に確認してみましょう。TinkerCad Circuits では「フォトレジスタ」という名前で部品登録されているので、これを配置して、マルチメータ(モードは「抵抗(Resistor)」に設定)と接続して、明るさによって抵抗値が変化すること を確認していきましょう。
- TinkerCad Circuits にアクセス&ログインして「新しい回路」を新規作成します。
- コンポーネントパネルから「フォトレジスタ」と「マルチメータ」をフィールドに配置します。
- マルチメータでは「電圧値」「電流値」「抵抗値」を計測することができます。マルチメータをクリックして、計測モードを「抵抗」に切り替えます。
- フォトレジスタとマルチメータを接続します。フォトレジスタに極性はありません(プラスとマイナスをどちらの足(端子)に接続しても問題ありません)。
- シミュレーションを開始して、フォトレジスタをクリックして光の強さを変えてみます。それに応じて、抵抗値が連続的に変化することを確認します。
シミュレーションにおいては「最も暗いときに $180\mathrm{k}\Omega$」「最も明るいときに $506\Omega$ 」のように抵抗値が大きく変化することが確認できます。無論、実際のセンサは、製品により抵抗値の変化範囲は変わります。また、同じ型番の製品でも個体差があります。
以上のことから、CdSセルは 明るさで抵抗値が変化する可変抵抗 として扱うことができます。
- CdSセルの原理(なぜ、光があたると抵抗値が下がるのか?)に興味がある人は「
cdsセル 原理
」などでググってみてください。
抵抗値 → 電圧 の 変換
マルチメータでは、直接的に抵抗値を測定することができました。しかし、Arduino では 直接的に抵抗値を測定する機能がありません。そこで、抵抗値を電圧に変換して、それをアナログ入力ポートから analogRead(...)
で読み取り、間接的に抵抗値を計測します。
抵抗値を電圧に変換するために、CdSセルと固定抵抗 $\mathrm{R1}$ と組み合わせて次のように分圧回路を構成します。
上記のように回路を構成すれば、**暗いとき**にCdSセルの抵抗は $180\mathrm{k}\Omega$ と大きくなるので、アナログ入力ポートの入力電圧 $V_{\mathrm{in}}$ は、次式より約 $5\mathrm{V}$ となります。
$$ V_{\mathrm{in}}=\frac{180k}{1k+180k}\times 5 \fallingdotseq 5,[\mathrm{V}]$$
**明るいとき**は、CdSセルの抵抗が $506\Omega$ と小さくなるので、アナログ入力ポートの入力電圧 $V_{\mathrm{in}}$ は、次式より約 $1.68\mathrm{V}$ となります。
$$ V_{\mathrm{in}}=\frac{506}{1k+506}\times 5 \fallingdotseq 1.68,[\mathrm{V}]$$
ここでは、$\mathrm{R1}$ に $1\mathrm{k}\Omega$ を使用しましたが、$10\mathrm{k}\Omega$ や $100\mathrm{k}\Omega$ を使っても構いません。$\mathrm{R1}$ に大きな抵抗を使うほど、電圧が変化する範囲が大きくなります。
前回の復習になりますが、アナログ入力 analogRead(...)
では、ポートに印加される電圧範囲 $0$~$5\mathrm{V}$ を「$0$~$1023$ までの $1024$ 段階」で読み取ることができました。例えば、$1.68\mathrm{V}$ が印加されている場合、プログラムのなかでは、次のように $344$ という値(整数値)が取得されます。
$$ x = \frac{1.68}{5.00}\times 1023 = 344$$
プログラムをテキスト(≠ブロック)で記述
CdSセル と Arduino を組み合わせて「暗くなったらLEDが自動点灯する回路」を作成してみます。ただし、今回は、ロジックをテキスト(コード)で書くことに挑戦します。
まずは、次のように回路を構成します。Arduinoの左側では、CdSセルと抵抗を使って分圧回路を構成しています。また、右側では LED点灯回路を構成しています(LEDの極性に注意してください)。
コードエディタを開いて、モードを「テキスト」に切り替えます。
切り替える際に「ブロック エディタを終了しますか? 現在開かれているすべてのブロックは失われます。テキスト エディタ内のコードは維持され、編集できるようになります。
」が表示されるので「続行」を選択します。
サンプルとして記述されている「Lチカ」のプログラム
テキストモードに切り替えると、初期状態では、次のようにビルトインLEDの点滅のためのプログラムが書かれています。これは、Arduino言語というプログラミング言語によるプログラムですが、基本的には C言語 と同じと思って(ほぼ)問題ありません。
記述のルール(大文字小文字を区別する、文の終わりにはセミコロン ;
、全角文字を使わないなど(特に**全角空白の混入に注意**))も同じです。
void setup()
{
pinMode(13, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH);
delay(1000); // Wait for 1000 millisecond(s)
digitalWrite(13, LOW);
delay(1000); // Wait for 1000 millisecond(s)
}
Arduinoのプログラムは、基本的に setup(){...}
と loop(){...}
という2つの関数から構成されます(※ main(){...}
が見当たらないという点はC言語との違いですね)。
これらの2つの関数の使い方(使い分け)ですが、
-
setup(){...}
のなかには「電源投入後の**初回だけ**にやって欲しい処理」を書いてきます。 -
loop(){...}
のなかには「setup(){...}
の実行後に、電源が切れるまで(繰り返し)ずっと続けて欲しい処理」を書きます。
TinkerCad Circuitsでは、直接的には見ることができませんが、裏側には次のようなプログラムがあって、はじめの1回だけ「setup関数」を呼び出して、その後は、無限ループのなかで繰り返し「loop関数」が呼び出されている、と考えてください。
main() {
setup(); // 最初に setup() を実行
while(1){ // while(1) で 無限ループ
loop(); // 無限ループのなかで loop() を繰り返し実行
}
}
さて、「暗くなったときにLEDを自動点灯させるプログラム」を書いていく前に、この「ビルトインLEDの点滅プログラム」について、読み解いていきたいと思います。
ビルトインLEDのLチカにおけるsetup関数
まずは、「setup関数」を見てください。この関数には「ピン(ポート)のモード切り替え(入力モードで使用するか、出力モードで使用するか)」や「変数の初期化」など、初回だけ実行したい処理を記述します。
void setup()
{
pinMode(13, OUTPUT);
}
ビルトインLEDのLチカプログラムには、pinMode(13, OUTPUT)
という文が記述されていますが、これは「デジタル 13 番ポートを、OUTPUT(出力)モードとして使います!」という指示を与えています。
ここで、なぜ「13」なのかというと、ビルトインLED(=Arduinoのボード上に実装されているオレンジ色のLED)は、ボードの内部で デジタル13番ポートと接続されているためです。
-
中級者向け補足:回路系に興味がある人は ArduinoUNOの回路図を見てみましょう。Arduinoの本体である ATmega8 というCPUの
(SCK)PB5
という端子と13番ポートの間にLED点灯回路が存在していることが分かると思います。
このように、「setup関数」のなかには、使用予定のポート(ピン)を「どのようなモードとして使用するか」の設定を書きます(設定は最初に1度だけすればよいので、その理由から「loop関数」ではなく「setup関数」に記述します。
ビルトインLEDのLチカにおけるloop関数
次に「loop関数」を読み解いていきます。
void loop()
{
digitalWrite(13, HIGH);
delay(1000); // Wait for 1000 millisecond(s)
digitalWrite(13, LOW);
delay(1000); // Wait for 1000 millisecond(s)
}
最初の digitalWrite(13, HIGH)
は「デジタル13番ポート出力を HIGH に切り替える」という指示になります。出力が HIGH ということは、$5\mathrm{V}$ が出力されるので、LED が点灯状態になります。
つづいての delay(1000)
は「1000ms(1000ミリ秒=1秒)だけ、次の命令に進まずに待機」という指示になります。
次の digitalWrite(13, LOW)
は「デジタル13番ポート出力を LOW に切り替える」という指示になります。出力が LOW ということは、$0\mathrm{V}$ が出力されるので、LED が消灯状態になります。
つづいての delay(1000)
では、1秒待機します。
さて、「loop関数」の最後まで到達すると、自動的に「loop関数」が再度呼び出されて、文が先頭から順に実行されます。これは、電源が断たれるまで永遠に繰り返されます(これまでに C言語 で作成してきたような PCプログラムとは違って「終わり」はありません)。
setup関数 と loop関数 をあわせた全体の流れ
ビルトインLEDのLチカプログラムの全体の流れは、次のようになります。
-
pinMode(13, OUTPUT);
@ setup関数 -
digitalWrite(13, HIGH);
@ loop関数(1回目) -
delay(1000);
@ loop関数(1回目) -
digitalWrite(13, LOW);
@ loop関数(1回目) -
delay(1000);
@ loop関数(1回目) -
digitalWrite(13, HIGH);
@ loop関数(**2**回目) -
delay(1000);
@ loop関数(**2**回目) -
digitalWrite(13, LOW);
@ loop関数(**2**回目) -
delay(1000);
@ loop関数(**2**回目) -
digitalWrite(13, HIGH);
@ loop関数(**3**回目) -
delay(1000);
@ loop関数(**3**回目) - (つづく・・・)
暗くなったらLEDが自動点灯するプログラムに書き換え
ここからは「暗くなったときにLEDを自動点灯させるプログラム」に書き替えていきます。もう一度、回路を示してきます。
steup関数
setup関数のなかには、使用するポート(ピン)を「どのようなモードとして使用するか」の設定を書きます。回路から分かるように、使用するのは「(LEDを接続する)デジタル7番ポート」と「(CdSセルを接続する)アナログ0番ポート」の2つです。
※ 回路では「5V」と「GND」の端子も使用していますが、固定出力なのでプログラムによる設定は不要です。
setup関数には、次のように記述していきます。
- デジタル 7 番ポートには、LEDを接続してデジタル**出力**として使用したいので、それをArduinoに設定するために
pinMode(7, OUTPUT);
を記述します。OUTPUTは大文字です。
- もし、デジタル**入力**として使う場合は INPUT とします。
- アナログ 0 番ポートには、分圧回路を接続してアナログ電圧を入力したいので、
pinMode(A0, INPUT);
を記述します。注意:単に0
と記述するとデジタル0番ポートの意味になってしまうので、A0
と記述してください。
まとめると、次のようになります。
void setup()
{
pinMode(7, OUTPUT);
pinMode(A0, INPUT);
}
-
中級者向け補足:アナログ0番から5番ポートは、デジタル入出力としても利用できます。デジタル出力として使用するときは
pinMode(A0, OUTPUT)
としてdigitalWrite(A0, HIGH)
のように使います。また、デジタル入力として使用するときはpinMode(A0, INPUT)
としてdigitalRead(A0)
のように使います。 -
中級者向け補足:
A0
は内部的には、バイト型の値14
となります。裏側で(コンパイル時に読み込まれるpins_arduino.h
というヘッダファイルのなかで)、#define PIN_A0 (14)
、static const uint8_t A0 = PIN_A0;
のように定義されています。- Arduino IDE をインストールしているPCでは、
C:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard\pins_arduino.h
を参照してください。
- Arduino IDE をインストールしているPCでは、
loop関数
次のように記述します。
void loop()
{
int a = analogRead(A0);
if ( 500 < a ) {
digitalWrite(7, HIGH);
} else {
digitalWrite(7, LOW);
}
delay(100);
}
はじめに、int型の変数 a
を宣言して、analogRead(A0)
で読み取った値をそこに格納しています。変数 a
には、0 ~ 1023 の範囲の整数値が格納されます。
次に if
で分岐を構成しています。500 < a
ならば(環境が暗くCdSセルの抵抗が大きくA0ポートの入力電圧が大きいなら)、digitalWrite(7, HIGH);
でデジタル7番ポートに接続したLEDを**点灯**させます。
また、500 < a
が成立しないなら(=環境が明るいなら)digitalWrite(7, LOW);
でLEDを**消灯**させます。
シミュレータの負荷を小さくするために 100ミリ秒だけ待機します(実機の場合は不要です)。
シミュレーションの実行
プログラム全体は次のようになります。これをコードエディタにコピペして、シミュレーションを実行してみて下さい。
- 作成例はこちら(TinkerCadに移動します)。
void setup()
{
pinMode(7, OUTPUT);
pinMode(A0, INPUT);
}
void loop()
{
int a = analogRead(A0);
if ( 500 < a ) {
digitalWrite(7, HIGH);
} else {
digitalWrite(7, LOW);
}
delay(100);
}
プログラムには、いわゆる別解が、ほぼ無限に存在します。上記のプログラムも、様々な書き替えができます。たとえば「loop関数」では、変数を省略して次のようにすることもできます。
void loop()
{
if ( 500 < analogRead(A0) ) {
digitalWrite(7, HIGH);
} else {
digitalWrite(7, LOW);
}
delay(100);
}
ポテンショメータの接続方法
ポテンショメータ(日本語環境では「電位差計」の名称)では、角度を計測することができます。回路は次のように構成します。ポテンショメータ単体で分圧回路を構成して、Arduino のアナログ入力に接続することができます。
- 回路例はこちら(TinkerCadに移動します)。
-
analogRead()
で読み取った値をシリアルモニタ出力しています。
-
シミュレーションではなく実際に回路を構築する際、いきなり光センサーを接続するのではなく、その代わりに半固定抵抗(ポテンショメータ)を接続して回路の動作を確認するといった用途でも使用します。
ガスセンサの接続方法
TinkerCad Circuits の回路シミュレータで利用できるガスセンサは「MQ-2」という製品になります。詳細については「MQ-2 gas sensor datasheet
」などをキーワードにググってください。
端子が6個あり、次のように接続します。シミュレーションを実行して、煙(ガス)をセンサに近づけるとマルチメータの表示がかわることが確認でききると思います。
- 作成例はこちら(TinkerCadに移動します)。
- 作成例はこちら(TinkerCadに移動します)。
演習16:自動点灯する街路灯
周囲が暗くなると自動的に点灯する街路灯をつくっていきます。ただし、上記とは違って、ここではLEDではなく電球を使用します。また、自動点灯モードと常時点灯モードをスライドスイッチを使って切り替えられるようにしていきます。
Step.1 電球とLEDの違い
- 電球は、LEDとは違い極性はありません。
- 電球は消費電力が大きいため(=たくさんの電流を流すため)Arduinoに直接接続してはいけません。
- TinkerCad Circuits で用意される電球は、$5\mathrm{V}$ 印加時に 約 $100\mathrm{mA}$ の電流が流れます。
- Arduinoのデジタル入出力ポートの電流の**絶対最大定格**は、1ポートあたり$40\mathrm{mA}$ です。絶対最大定格を超える電流を流そうとするとArduinoが壊れます !
- Arduinoを使って電球を点灯させるためには、外部電源 と トランジスタ が必要になります。
トランジスタの「デジタルスイッチ」としての仕組みは、とても簡単です(図内の「抵抗+LED」を「電球」に置き替えてください)。ベース抵抗の設計などは実験実習の時間に習います。
次のように回路を構成して「デジタル4番ポートを HIGH(高) にすると電球が点灯」「LOW(低) にすると電球が消灯」を実際に確認してください。**トランジスタのピンアサイン(ピン配置)に注意**してください。
点灯を確認できたら、次に「外部電源のGND と ArduinoのGNDを接続しないと、ベースに電圧を印加しても電球が「点灯しない」こと」も体験してください(図内の赤矢印の配線を切ってみてください)。GNDの共通化忘れは、初心者のハマりポイントです。
- 解答例はこちら(TinkerCadに移動します)。
Step.2 フォトレジスタの追加
フォトレジスタ(CdSセル)を追加して、暗くなると電球が自動点灯する回路&ロジックに拡張してください。まずは、ブロックによるロジック構成でOKです。
- 解答例はこちら(TinkerCadに移動します)。
Step.3 スライドスイッチによるモード切替
上記の回路に、スライドスイッチを追加して「自動点灯モード(暗くなると点灯)」と「常時点灯モード」切り替えられるようにしてみてください。
- 解答例はこちら(TinkerCadに移動します)。
- 3Hの学生さんは、最低でも 15分 は自分で粘ってから解答例を見るようにしてください。数分で諦めるのは早過ぎです。また、解答例をみた後も、必ず自分で手を動かして回路&ロジックを構成してみましょう。
Step.4 ブロックとコードの対応確認
コードエディタのモードを「ブロック + テキスト」に変更し、ブロックで構成したプログラムと、プログラムコード(テキスト)で記述したプログラムがどのように対応しているのか確認してみましょう。
EX演習3:自由作品A
ここまでに勉強した要素を組み合わせて、自由に回路&ロジックを作成してみましょう。