Arduinoプログラム解説:多機能センサー制御システム
このArduinoスケッチは、複数の入出力デバイスを統合的に制御するシステムです。主要な機能は、各種センサーからのデータ読み取り、そのデータに基づくアクチュエーター(LEDやブザー)の制御、そしてシリアル通信によるデバッグ情報の出力です。
プログラムの構成要素
1. プリプロセッサディレクティブと変数定義
#include <DHT.h>
#include <Adafruit_Sensor.h>
// ピン定義 (Pin Definitions)
#define DHTPIN 4
...
#define KEY_LED_B_PIN 13
// オブジェクトの作成 (Object Instantiation)
DHT dht(DHTPIN, DHTTYPE);
// グローバル変数 (Global Variables)
int prevPotValue = 0;
int prevButton1State = HIGH;
int prevButton2State = HIGH;
-
#include: 外部ライブラリ(DHT.h、Adafruit_Sensor.h)をインクルードしています。これにより、DHTセンサーの複雑なデータ取得処理を簡単に扱えます。 -
#define: 各コンポーネントを接続するピン番号に、わかりやすい名前を割り当てています。これにより、プログラムの可読性が向上し、ピンの変更も容易になります。 -
DHT dht(DHTPIN, DHTTYPE);: DHTセンサーライブラリのインスタンスを生成し、オブジェクト指向プログラミングの概念を適用しています。 -
グローバル変数:
prevPotValueやprevButton1Stateは、loop()関数が繰り返し実行されるたびに、前回の状態を記憶しておくために使用されます。これによって、イベントの「瞬間」を検出するロジック(例: ボタンが押された瞬間)を実装できます。
2. ブザーを鳴らす関数 (playTone)
void playTone(int pin, int frequency, int duration) {
long period = 1000000 / frequency;
long delayTime = period / 2;
for (long i = 0; i < (long)duration * 1000L / period; i++) {
digitalWrite(pin, HIGH);
delayMicroseconds(delayTime);
digitalWrite(pin, LOW);
delayMicroseconds(delayTime);
}
}
-
この関数は、ハードウェアタイマーを使用する標準の
tone()関数との競合を避けるために、ソフトウェアPWMの原理でブザーを制御します。 -
frequency(周波数)から周期(period)を計算し、digitalWrite()とdelayMicroseconds()を繰り返すことで、手動で矩形波を生成しています。これにより、11番ピンのPWM出力との干渉を防ぎます。
3. 初期設定 (setup)
void setup() {
Serial.begin(9600);
dht.begin();
pinMode(BUTTON1_PIN, INPUT_PULLUP);
...
Serial.println("DHT_Temp(C)\t...");
}
-
Serial.begin(9600);: PCとのシリアル通信を開始し、デバッグやデータロギングのために使用します。ボーレート(通信速度)は9600bpsに設定されています。 -
pinMode(..., INPUT_PULLUP);: ボタンのピンをINPUT_PULLUPモードで設定しています。これにより、外部にプルアップ抵抗を接続しなくても、ボタンが押されていないときにHIGHの状態を保てます。 -
pinMode(..., OUTPUT);: LEDやブザーなどのアクチュエーターをOUTPUTモードに設定しています。 -
ヘッダー行の出力: シリアルモニターでのデータ表示を整理するために、各データの列名を出力しています。
4. メインループ (loop)
void loop() {
// 1. センサーデータの読み取り
float h = dht.readHumidity();
float t_dht = dht.readTemperature();
...
// 2. VR(ポテンショメーター)の変更検出とブザー制御
if (abs(potValue - prevPotValue) > 5) {
playTone(BUZZER_PIN, 500, 50);
prevPotValue = potValue;
}
...
// 5. キー(ボタン)に連動してブザーとLEDを制御する
if (button1_state == LOW && prevButton1State == HIGH) {
playTone(BUZZER_PIN, 1000, 50);
}
...
}
-
loop()関数は、Arduinoの電源が入っている限り、無限に繰り返されます。 -
センサーデータ読み取り: DHTセンサー、LM35温度センサー、LDR(CdSセル)、ポテンショメーター、ボタンの状態を読み取ります。
analogRead()は0から1023の値を返します。 -
VRのブザー制御: ポテンショメーターの値が前回の値から5以上変化した場合に、
playTone()関数を呼び出してブザーを鳴らします。 -
LED輝度制御:
-
brightness = map(ldrValue, 50, 800, 255, 0);: LDR(光センサー)の読み取り値(50〜800)を、LEDの輝度(0〜255)に線形変換しています。これにより、周囲が暗くなるとLEDが明るくなるロジックを実装しています。 -
potValueの値に応じて、RGB LEDの赤、緑、青の値を計算し、analogWrite()でPWM出力を制御して色を調整します。
-
-
キーによるブザーとLED制御:
-
if (button1_state == LOW && prevButton1State == HIGH): これは、ボタンが**押された瞬間(立ち下がりエッジ)**を検出する標準的な方法です。この条件が満たされたときだけブザーを鳴らすことで、ボタンを押し続けたときに音が鳴り続けるのを防いでいます。
-
-
シリアル出力: 各センサーの読み取り値とボタンの状態をシリアルポートに出力し、PCでデータの監視ができるようにしています。
\t(タブ)で区切ることで、表形式での表示を可能にしています。
このプログラムは、複数のセンサーからのアナログ・デジタル入力を受け付け、それに応じて複数のアクチュエーターを制御する、基本的な組込みシステムの良い例となっています。特に、ハードウェアの制約をソフトウェアで回避するplayTone()関数は、問題解決の一つのアプローチとして注目に値します。
つづき さらに深堀します。
このプログラムについて、さらに詳しく見ていきましょう。前回は主要な構成とplayTone関数について解説しましたので、今回はloop関数内の各処理について深掘りします。
1. センサーデータの読み取りと処理
loop()関数の冒頭では、さまざまなセンサーから環境データを取得しています。
// 1. センサーデータの読み取り
float h = dht.readHumidity();
float t_dht = dht.readTemperature();
int lm35_adc_value = analogRead(LM35_PIN);
float t_lm35 = lm35_adc_value * (500.0 / 1024.0);
int ldrValue = analogRead(LDR_PIN);
int potValue = analogRead(POT_PIN);
int button1_state = digitalRead(BUTTON1_PIN);
int button2_state = digitalRead(BUTTON2_PIN);
-
dht.readHumidity()とdht.readTemperature():DHT11センサーからデジタルデータとして湿度と温度を直接読み取っています。DHT11ライブラリが、この複雑なデータ通信を裏側で処理してくれています。 -
analogRead():LM35、LDR、ポテンショメーター(VR)といったアナログセンサーから、0から1023までの電圧値(ADC値)を読み取っています。 -
t_lm35の計算:LM35はアナログセンサーなので、読み取ったADC値を実際の温度に変換する式が必要です。lm35_adc_value * (500.0 / 1024.0)という式は、5Vの電源で動作するLM35の特性(10mV/℃)に基づいています。ArduinoのanalogReadは5Vを1024段階で表現するため、500.0 / 1024.0は「1段階あたり約4.88mV」という換算係数になり、これにlm35_adc_valueをかけることで、摂氏温度に変換しています。
2. ポテンショメーターとRGB LEDの連動ロジック
この部分では、ポテンショメーター(VR)の回転とLDRの明るさに応じて、3色LEDの色と明るさを動的に制御しています。
// 3. CDS(LDR)の明るさに応じてLEDの輝度を調整
int brightness = map(ldrValue, 50, 800, 255, 0);
// 4. VRの値に応じてRGB LEDの色を調整
...
analogWrite(LED_R_PIN, map(redValue, 0, 255, 0, brightness));
-
map(ldrValue, 50, 800, 255, 0):map()関数は、ある範囲の値を別の範囲に線形変換する便利な機能です。ここでは、LDRが読み取る明るさの値(ldrValue)が50から800の範囲で、LEDの輝度(brightness)を255から0に変化させています。明るい場所(ldrValueが大きい)ではLEDを暗く、暗い場所(ldrValueが小さい)ではLEDを明るくするロジックです。 -
if-else if-else:ポテンショメーターの値(potValue)を3つの範囲に分割し、それぞれの範囲でRGBの各色の値をmap()関数を使って調整しています。これにより、ポテンショメーターを回すと、赤→緑→青へと滑らかに色が変化するグラデーションを実装しています。 -
analogWrite():最終的なRGBの各色の値に、LDRから得たbrightness値をさらにmap()関数で乗算し、analogWrite()によってPWM(パルス幅変調)出力を行っています。これにより、光の色と明るさの両方を同時に制御できるのです。
3. ボタンのイベント検出と制御
キー連動のブザーとLEDの制御は、単にボタンの状態を読み取るだけでなく、「ボタンが押された瞬間」を正確に捉える工夫がされています。
// 5. キー(ボタン)に連動してブザーとLEDを制御する
if (button1_state == LOW && prevButton1State == HIGH) {
playTone(BUZZER_PIN, 1000, 50);
}
// ...
// ボタンの状態を更新
prevButton1State = button1_state;
prevButton2State = button2_state;
-
button1_state == LOW && prevButton1State == HIGH:この条件式は、ボタンの状態がHIGH(押されていない)からLOW(押された)に変化した瞬間を検出しています。 -
prevButton1Stateという前回の状態を記憶する変数があるため、ボタンが押されっぱなしになっている間はブザーが連続して鳴るのを防ぎ、イベントを一度だけ発生させることができます。これは、チャタリング(物理的なボタンを押したときの微細なON/OFFの繰り返し)対策にも有効です。
4. シリアル通信によるデータの出力
プログラムの最後では、すべてのセンサーデータをPCのシリアルモニターに出力しています。
// 6. すべてのデータを1行で出力
if (isnan(h) || isnan(t_dht)) {
Serial.print("NaN\tNaN\t");
} else {
...
}
Serial.print(t_lm35);
Serial.print("\t");
...
Serial.println(button2_state == LOW ? "Pressed" : "Not Pressed");
delay(100);
-
isnan():DHTセンサーが正常に動作しない場合に返されるNaN(Not a Number)という特殊な値をチェックし、エラー処理を行っています。 -
Serial.print()とSerial.println():それぞれのデータの後に\t(タブ)を挿入することで、シリアルモニター上でデータがきれいに表形式で表示されるように整形しています。 -
delay(100):loop()関数が次の繰り返しに進む前に100ミリ秒待機しています。これにより、センサーのデータが過度に高速で更新されるのを防ぎ、シリアルモニターの表示を安定させています。
このように、このプログラムはセンサーからの入力、ロジックによる処理、アクチュエーターへの出力、そして外部への情報提供(シリアル通信)という、組込みシステムの基本要素をすべて網羅した、バランスの取れた構成になっています。