====== 5-3 CdSセルで明るさ検知(analogRead) ====== デジタル入出力では、0(LOW)か1(HIGH)の2つの値を用い、0であれば0Vの入出力、1であれば5Vの入出力として操作しました。 今回扱うアナログ入力では、0V~5Vまでの電圧変化を"段階的"に読み取ることができます。    ===== CdSセルについて ===== {{:gimmickkouza:electronic_basic:5:5-14.png?300|}} 本項ではCdSセルを使用します。 CdSセルは、「フォトセル」「フォトレジスタ」とも呼ばれる素子です。 "CdS"は硫化カドミウムのことで、これにより光の量に応じて抵抗値が変化するのが特徴です。 光の量が多い(周囲が明るい)場合、抵抗値は下がり電気が流れやすくなります。 逆に光の量が少なく(周囲が暗く)なると、抵抗値が上がり電気が流れにくくなります。 **超ざっくり言うと光の明るさに反応するセンサです。**    ちなみにカドミウムはEUの法規制であるRoHS指令の規制対象となっています。 (日本国内では2024年6月現在はまだ使用OKです) CdSセルを使った制作物をEUの方が購入したり、購入者がEU外の方であったとしても転居や遠征でEUに持ち込まれるのはNGなので、**販売用の作品には絶対に使わないようにしましょう。** CdSセルの代わりに使える電子パーツには、フォトトランジスタやフォトダイオードなどがあります。 /*光の明るさに反応するセンサですとか言ったほうがわかりやすいですかね*/    ===== 5-3_analogRead ===== ==== アナログ入力の仕組み ==== 本項冒頭の記述に反するようですが、実はArduinoでは電圧の値を直接読み取ることはできません。    まず、電圧は便宜上「5V」のように書いてますが、実際は小数点以下の数値が無限に続く無理数です。 例えば乾電池の電圧は1本1.5Vと説明しましたが、厳密には1.5Vピッタリではありません。 1.52546738…Vかもしれないし1.4989786716…Vかもしれないです。 コンピュータでは無理数は扱えません。なので、何らかの変換をして有理数にする必要があります。 そこで登場するのがADC(アナログデジタルコンバータ)です。 **Arduinoが読み込み可能な電圧の幅は0V~5Vです。この幅を1023等分し、0Vが0、5Vが1023となるよう、0~1023までの数値を順に割り振ります。** (大半のArduinoは0~1023(10ビットの分解能)ですが、異なる数値幅で表現するマイコンもあります) アナログ入力で読み取った電圧は、ADCによってこの等分した数値の一番近い値に変換されます。 例えばアナログ入力ソケットに5Vの入力があった場合、そのソケットの5VはADCによって変換され、5Vに対応する数値「1023」がArduinoに読み込まれます。 0Vであれば「0」です。2.5Vであれば0~1023のちょうど中間なので「512」となります。 ADCの変換過程はこちらの解説記事の図が非常にわかりやすくてオススメです。     Arduino(アルディーノ)電子工作の基本⑦ アナログ入力で電圧を読み取る(Device Plus):  https://deviceplus.jp/arduino/arduino_f07/    さて先ほど申し上げた通り、電圧の値は小数点が無限に続く無理数です。 なので実際に入力される電圧は3.000977517…Vのような形です。 この数値は0~1023の帯域の中では、「614」が最も近い数値となり、これがArduinoに入力されます。 ちなみにArduinoに入力された0~1023の数値は、下記の式で電圧の値に直すこともできます。           電圧の最大値(Arduinoなら「5」V   電圧 = ―――――――――――――――――― × 入力された数値         ADCの分割数(Arduinoなら「1023」 例えばArduinoが「299」という数値を読み取ったとしましょう。 電圧の計算式は (5 / 1023) * 299 = 1.4613880742913 となり、大体1.46Vくらいの電圧が入力されたことがわかります。 /* * 入力された数値 → × 入力された数値のほうがわかりやすいかも…*/    ==== 配線図 ==== {{:gimmickkouza:electronic_basic:5:5-3-1.png?600|}}    そんなわけで配線図です。 CdSセルを使ってどんな感じで値が表示されるかを知りたいので、シンプルに繋ぎます。 CdSセルに極性はありませんので、どちらの脚が5V/GNDに来てもOKです。 抵抗は10kΩのものを挿してください。 ===使う部品リスト=== ^ 部品 ^ 個数 ^ | CdSセル | 1個 | | 抵抗器(10kΩ) | 1個 | /* 部品表欲しいです。見て何が何個必要かわからないので…*/    ==== サンプルコード解説 ==== サンプルコード5-3_analogRead.inoを開いてください。 /*CDSはCDSpinかcdsPinとかにしたほうがなんのピンか分かりやすくていいと思います*/ int CDSpin = A0; //変数CDSを作り"アナログ入力ソケット0番"を示す「A0」を代入 void setup() { Serial.begin(9600); } void loop() { int analog_val = 0; //CdSセルで読み取った値を入れる変数を宣言する analog_val = analogRead(CDSpin); //CdS(=A0)の値を読み取り変数analog_valに格納する //値は入力電圧をADCで変換した後の0~1023の数値が格納される Serial.print("只今の数値は:"); Serial.print(analog_val); Serial.println("です!"); delay(500); } 一点補足すると、アナログ入力では、デジタル入出力では必要だったpinModeの指定は不要です。 == 1行目 == int CDSpin = A0; //変数CDSを作り"アナログ入力ソケット0番"を示す「A0」を代入 電圧読み取り用のソケットを変数で指定します。アナログ0番なので「A0」です。 初っ端から大事件です。「intは整数型なのに文字入ってますやん???」と思っちゃいますよね。 もちろん大丈夫な理由はちゃんとあります。が、本筋から脱線してしまうのでTipsで後述します。 とりあえず、アナログ入力の場合はint型でもA0~A5という指定が可能です。 もちろんint CDSpin = 0; でも動作します。 (個人的にはアナログ入力にはA0~A5表記を使用する方が、後から読んだ時の分かりやすさと他のArduinoとの互換性の観点から便利かなと思います) == 4行目 == Serial.begin(9600); 今回はCdSセルで読み取った値をシリアルモニタに表示します。 シリアルモニタの初期化を忘れずに行っておきましょう。 == 8行目 == int analog_val = 0; //CdSセルで読み取った値を入れる変数を宣言する int型の変数analog_valを用意します。この変数にCdSで読み取った値を入れます。 == 9行目 == analog_val = analogRead(CDSpin); 本命のアナログ入力です。analogRead(CDSpin)でA0ソケット挿さったCdSの値を読み取り、これを先程用意した変数analog_valに入れます。 A0への入力電圧をADCで数値に変換する処理は自動で行われます。なので命令文は不要です。 analog_valには、変換後の0~1023の数値が格納されます。 == 13~15行目 == Serial.print("只今の数値は:"); Serial.print(analog_val); Serial.println("です!"); analog_valの値をシリアルモニタに表示します。 だいたい0.5秒おきぐらいにシリアルモニタに値が表示され続けると思います。 CdSセルの周囲を手で覆い隠す(=暗くする)と数値が上昇し、逆にCdSセルにケータイのライトなどを当ててやる(=明るくする)と数値が減少するかと思います。 ちなみに講師の環境(電気のついた夕方の部屋)では、平常時で200前後、手で覆って暗くすると(覆う程度にもよりますが)500~980くらい、ケータイのライトを当てると100未満の数値を示しました。       int型でなぜ文字列「A0」を入力できるのか、気になって夜しか眠れない方向けのコーナーです。 Arduinoには、実はスケッチのファイルとは別に"見えない設定ファイル"がたくさんあります。 それらのファイルでは、ArduinoやArduinoで使う関数の動作の設定がされています。 (このファイル群は見ようと思えば見ることはできます。しかし万一ファイルや、ファイルの中身を損なってしまうとArduinoの動作がおかしくなってしまうため、見方はここには記載しません)    このファイルの一つ、"アナログピンの設定ファイル"の内部には、「A0」という"定数"が設定されています。 "定数"は"変数"と同じように"型を指定し、値を収納して使える箱のようなもの"ですが、変数とは違い、中身を変えることができないという特徴があります。 そしてこの定数「A0」の中身には、「14」という数値が入るように設定されています。     \\定数A0です。ヨロシク!!// {{:gimmickkouza:electronic_basic:5:5-15.png?200|}}       intに「A0」を入力できる種明かしです。 int CDSpin = A0; は、変数「CDSpin」に定数「A0」(の中身の14を)代入するという形を取っています。 定数A0のデータ型はuint8_t型で、これは0~255の整数の値のみを扱える型です。 変数CDSpinのint型とは異なる型ですが、int型の範囲(R3では-32,768~32,767)の方が広く、uint8_t型の定数A0 の中身「14」にも対応しているため、これを格納することができます。 {{:gimmickkouza:electronic_basic:5:5-16.png?300|}}    そしてanalogRead関数の設定ファイルでは「まず最初に、引数で指定されたソケットの数値が14以上であれば、その数値から14を引く」という処理をすることが定められています。 それによりCDSpinの中身は「0」となり、無事アナログ0番ピンを指定する仕組みになっています。    Arduinoの裏側には動作を規定する設定ファイルがあることを頭の隅に置いておくと、いつか役に立つ時が来る…かもしれません。 (例えば? ウーン……SoftwareSerial増やしたくなった時とか(小声)) {{ :gimmickkouza:electronic_basic:5:5-17.png?400|}}