赤外線(IrRemote)
環境構築(ライブラリインストール・ライブラリインクルード)

#include <IRremote.h>
赤外線リモコンとデコードの仕組み
デコードされたデータについて説明します。
赤外線リモコンとデコードの仕組み
赤外線リモコンは、ボタンを押すと特定の赤外線信号を送信します。この信号は、一定のパターン(例えば、オンとオフの時間)で構成されています。このパターンはリモコンごとに異なり、リモコンのプロトコルに依存します。
Arduinoが赤外線リモコンの信号を受信すると、その信号を解釈し、ボタンに対応するユニークなデータ(コード)に変換します。このプロセスが「デコード」です。
decodedIRData
構造体
IRremote
ライブラリでは、受信した赤外線信号の情報を保持するために decodedIRData
という構造体(データのまとまり)が使われます。この構造体には、以下のようなさまざまな情報が含まれています。
decodedRawData
: リモコンから受信した信号の生データ(Raw Data)。これは、リモコンのボタンに対応するユニークな値です。この値が特定のボタンに対応しています。protocol
: 使用されているプロトコル(NEC、Sony、RC5など)を示します。リモコンの種類によってプロトコルが異なるため、この情報は信号を正しくデコードするために重要です。address
: リモコンやデバイスのアドレスを示します。一部のプロトコルでは、信号にアドレス情報が含まれており、それがこのフィールドに保存されます。command
: 実行されるコマンドを示します。例えば、ボリュームアップや電源オンなど、リモコンのボタンに対応する特定のアクションです。
デコードされたデータの具体的な使用例
例えば、NECプロトコルを使ったリモコンの場合、特定のボタンを押すとArduinoはその信号を受信し、decodedIRData.decodedRawData
に固有の16進数の値(例えば、0x20DF10EF
)を格納します。この値を使って、プログラムがどのボタンが押されたかを判断し、それに応じた動作を実行します。
デコードされたデータを利用する際の手順
- 受信とデコード: リモコンから信号を受信し、
IRremote
ライブラリが信号をデコードします。 - シリアルモニタで確認: デコードされたデータは、シリアルモニタに出力して確認することができます。これにより、どのボタンがどの値を持っているかを特定できます。
IrReceiver.printIRResultShort(&Serial);
このコードを使うと、シリアルモニタに受信した信号の詳細が表示されます。 - 条件文で利用: デコードされた値を使って、特定のアクションを実行する条件を設定します。
if (IrReceiver.decodedIRData.decodedRawData == 0x20DF10EF) { // LEDを点灯させる }
注意点
- 異なるリモコン: 異なるリモコンやプロトコルでは異なる値が生成されますので、自分のリモコンのボタンに対応するデータを確認する必要があります。
- 再利用:
decodedRawData
の値を利用して、異なるボタンに対して異なるアクションを割り当てることができます。
これでデコードされたデータの仕組みについて理解が深まったと思いますが、他に質問があればどうぞ!
赤外線受信用のピン設定(IrReceiver.begin)
IrReceiver.begin
は、赤外線受信モジュールを初期化するための関数です。この関数を使うと、赤外線リモコンの信号を受信するための設定が行われます。以下は、IrReceiver.begin
の引数についての詳細です。
IrReceiver.begin
の引数
IrReceiver.begin
は、通常次のように呼び出します。
IrReceiver.begin(pin, enableLEDFeedback, enableAutomaticTolerance);
1. pin
(必須)
- 説明: 赤外線受信モジュールが接続されているマイクロコントローラのデジタルピン番号を指定します。
- 例:
IrReceiver.begin(2);
の場合、デジタルピン2に赤外線受信モジュールが接続されていることを意味します。
2. enableLEDFeedback
(オプション, デフォルト: false
)
- 説明:
true
に設定すると、赤外線信号を受信した際にLEDが点灯します。通常、デバッグや動作確認のために使います。 - 例:
IrReceiver.begin(2, true);
とすると、信号を受信するときにLEDが点灯します。
3. enableAutomaticTolerance
(オプション, デフォルト: false
)
- 説明:
true
に設定すると、受信信号のタイミングの許容範囲が自動的に調整されます。これにより、異なるリモコンや環境条件に対して信号の受信精度が向上します。 - 例:
IrReceiver.begin(2, true, true);
とすると、LEDが点灯し、かつ自動許容範囲調整が有効になります。
まとめ
IrReceiver.begin
の引数は、最低限、赤外線受信モジュールの接続ピン番号を指定する必要があります。また、LEDフィードバックや自動許容範囲調整といった追加機能も使用可能です。これらのオプションは、特定の用途やデバッグ時に役立ちます。
赤外線信号をデコードして構造体に格納し、戻り値を返す(IrReceiver.decode)
IrReceiver.decode()
は、赤外線リモコンから送信された信号をデコードするための関数です。この関数は、IRrecv
ライブラリやIRremote
ライブラリを使用している場合に、受信した赤外線信号を読み取ってその内容を解析します。
IrReceiver.decode()
の概要
- 目的: 赤外線信号を受信し、それを意味のあるデータ(リモコンのボタン押下情報など)に変換します。
- 戻り値:
true
またはfalse
を返します。true
: 赤外線信号が正常にデコードされた場合。false
: 信号がまだ受信されていない、またはデコードできない場合。
使い方
基本的な使い方は以下のようになります。
#include <IRremote.h>
void setup() {
Serial.begin(9600); // シリアル通信の初期化
IrReceiver.begin(2); // 赤外線受信モジュールの初期化(デジタルピン2に接続)
}
void loop() {
if (IrReceiver.decode()) { // 赤外線信号を受信してデコードできた場合
Serial.println(IrReceiver.decodedIRData.command); // 受信したデータを表示
IrReceiver.resume(); // 次の信号を受信するために準備
}
}
IrReceiver.decode()
の詳細
- デコード結果の格納:
IrReceiver.decode()
がtrue
を返すと、デコードされたデータがIrReceiver.decodedIRData
構造体に格納されます。この構造体には、リモコンのプロトコル、アドレス、コマンド、RAWデータなどの詳細情報が含まれています。 IrReceiver.resume()
の使用: デコード後に次の信号を受信する準備をするために、IrReceiver.resume()
を呼び出す必要があります。この関数を呼ばないと、次の信号を受信できません。
主要な構造体フィールド
IrReceiver.decodedIRData
には以下のようなフィールドが含まれています:
command
: リモコンのボタンが送信するコマンド値。address
: 送信元アドレス(デバイスIDなど)。protocol
: 使用されているプロトコル(NEC、SONY、RC5など)。rawData
: デコード前の生データ(RAWデータ)。
まとめ
IrReceiver.decode()
は、赤外線リモコンから送信された信号を受信して解析するための関数です。- デコードされたデータは
IrReceiver.decodedIRData
に保存され、リモコンのボタン操作やデバイスのアドレスなどを取得できます。 - 次の信号を受信するには、
IrReceiver.resume()
を使って受信モジュールをリセットする必要があります。
これにより、リモコンのボタン操作を正確に検知し、様々な操作を実行することができます。
赤外線信号の受信をリセットする(IrReceiver.resume())
IrReceiver.resume()
は、赤外線リモコンからの信号を再び受信できるようにするための関数です。この関数は、赤外線信号を処理した後に次の信号を受信する準備をするために呼び出します。
IrReceiver.resume()
の役割
IrReceiver.decode()
を使って赤外線信号を受信してデコードすると、その信号は一度処理されるため、新しい信号が受信されるまでモジュールは次の信号を待機する状態になります。この状態を解除して、再び赤外線信号を受け付けるようにするのが IrReceiver.resume()
の役割です。
使い方
典型的な使い方は次のようになります。
#include <IRremote.h>
void setup() {
Serial.begin(9600); // シリアル通信を初期化
IrReceiver.begin(2); // 赤外線受信モジュールをデジタルピン2で初期化
}
void loop() {
if (IrReceiver.decode()) { // 赤外線信号を受信してデコードに成功した場合
Serial.println(IrReceiver.decodedIRData.command); // デコード結果を表示
IrReceiver.resume(); // 次の信号を受信できるようにリセット
}
}
IrReceiver.resume()
の必要性
- 信号処理後のリセット:
IrReceiver.decode()
がtrue
を返すと、その信号は一度処理され、次の信号を受信する前にIrReceiver.resume()
を呼び出して受信モジュールをリセットする必要があります。
- 新しい信号の受信:
IrReceiver.resume()
を呼び出すと、新しい信号の受信が可能になります。これにより、複数の信号を連続して受信・処理することができます。
まとめ
IrReceiver.resume()
は、赤外線信号を受信した後、再び新しい信号を受信できるようにするために使用されます。- この関数を使うことで、連続的に赤外線信号を受信し、それぞれを適切に処理することが可能になります。
IrReceiver.decode()
で信号を処理した後は、必ずIrReceiver.resume()
を呼び出して、次の信号を受信する準備をする必要があります。
これにより、赤外線リモコンを使用したデバイス制御をスムーズに行うことができます。
IrReceiver.decodeで格納されたデータを使用する(IrReceiver.decodedIRData
)
IrReceiver.decodedIRData
は、赤外線リモコンから受信した信号を解析した結果を格納するための構造体です。この構造体のフィールドには、リモコン信号に関するさまざまな情報が含まれています。以下は、IrReceiver.decodedIRData
の主要なフィールドとその詳細についての説明です。
IrReceiver.decodedIRData
の主要フィールド
command
- 説明: リモコンのボタン操作によって送信されたコマンド値が格納されます。リモコンの各ボタンは異なるコマンド値を持っています。
- 用途: このフィールドを利用して、特定のボタンが押されたかどうかを判定します。
- 例: 電源ボタンが押されたときに特定の処理を行う。
if (IrReceiver.decodedIRData.command == 0x10) { // 0x10に対応するボタンが押された場合の処理 }
address
- 説明: リモコンが送信したデバイスのアドレス(識別子)です。複数のデバイスを区別するために使用されます。
- 用途: 同じプロトコルを使用する複数のデバイスがある場合に、それらを区別するために使用します。
- 例: 特定のアドレスを持つリモコンからの信号を検知する。
protocol
- 説明: 信号が使用している赤外線プロトコルを示します(例: NEC、SONY、RC5など)。
- 用途: 使用しているプロトコルに応じてデータの処理方法を変更するために使用します。
- 例: NECプロトコルの場合の特定の処理を実装する。
if (IrReceiver.decodedIRData.protocol == NEC) { // NECプロトコルの信号を処理 }
flags
- 説明: 特定の状態やフラグを示します。例えば、リピートコードが送信されたかどうかなどが含まれます。
- 用途: リモコンの長押しやリピートコードを検知する際に使用します。
- 例: リモコンの長押しが行われている場合に特定の動作を行う。
rawDataPtr
- 説明: デコード前の生の赤外線信号データが格納されているポインタです。生データを直接扱いたい場合に使用します。
- 用途: 標準的なプロトコルに適合しない信号やカスタムプロトコルの解析に使用されます。
decodedRawData
- 説明: デコードされた生の赤外線信号データが格納されます。このフィールドには、信号のRAWデータが含まれます。
- 用途: リモコンの信号を解析して、特定の情報を取得したい場合に使用します。
numberOfBits
- 説明: 受信した赤外線信号のビット数を示します。信号が何ビットで構成されているかを知るために使用します。
- 用途: プロトコルごとのビット長を検証したり、信号の完全性を確認するために使用します。
extra
- 説明: プロトコル固有の追加情報や拡張データが格納されます。特定のプロトコルでのみ使用されることがあります。
decodedRawData
- 説明: 生の赤外線データ(RAWデータ)をデコードした結果を保持します。このデータを使ってより詳細な解析を行うことができます。
まとめ
IrReceiver.decodedIRData
は、赤外線リモコンの信号を解析した結果を保持する構造体で、その中のフィールドを活用することで、受信した信号に応じた動作をプログラムで実装できます。- 主要なフィールドには、コマンド、アドレス、プロトコル、フラグ、RAWデータなどが含まれ、各フィールドは異なる用途に利用できます。
この構造体を利用することで、リモコンのボタン操作に基づく制御を実現することができます。
RTC(rtcライブラリ)
環境構築(ライブラリインストール・ライブラリインクルード)
#include <RtcDS1302.h>
3線式でSPI通信を行う設定
ThreeWire myWire(4, 5, 2);
は、Arduinoのプログラムで3線SPI(Serial Peripheral Interface)を使用するためのオブジェクトの作成を示すコードです。このコードの詳細について説明します。
ThreeWire
クラスについて
ThreeWire
は、3線式のSPI通信をサポートするためのクラスです。この通信方式は、通常のSPI通信よりも少ないピン(3本のワイヤ)を使用してデータの送受信を行います。一般的に、SPI通信では4本の線を使いますが、このThreeWire
ライブラリを使うと、必要な信号線を3本に減らすことができます。
通常、SPI通信には以下の4本の信号線が必要です:
- MOSI (Master Out Slave In) – マスターからスレーブへデータを送る。
- MISO (Master In Slave Out) – スレーブからマスターへデータを送る。
- SCK (Serial Clock) – クロック信号を同期させる。
- SS (Slave Select) – スレーブデバイスを選択する信号。
ThreeWire
クラスを使うと、これらの信号のうち1つを省略し、3本の信号線で通信を行います。
ThreeWire myWire(4, 5, 2);
の詳細
ThreeWire
クラス: 3本のワイヤを使用するSPI通信を管理するクラス。myWire
オブジェクト: このオブジェクトは、通信に使うピンを指定して、実際に通信を管理するためのインスタンスです。
引数の意味:
ThreeWire myWire(4, 5, 2);
この場合、3本の信号線に以下のピンが割り当てられています。
- ピン 4: これは データ(MOSIもしくはMISOとして使用される)を送受信するピンです。
- ピン 5: これは クロック(SCK)信号を生成するピンです。
- ピン 2: これは スレーブセレクト(SS) ピンで、どのスレーブデバイスと通信するかを選択するために使用されます。
ThreeWire
の用途
3線式SPIは、ピン数を節約したい場合や、制約のあるデバイスでの通信が必要な場合に便利です。このクラスを使って、Arduinoと周辺デバイス(例えばセンサーやLCDディスプレイ)との間で効率的に通信ができます。
例
以下に、ThreeWire
を使ったサンプルコードを示します。
#include <ThreeWire.h>
#include <LiquidCrystal_SR3W.h> // 3線式でLCDを使う場合
// ピンの設定
ThreeWire myWire(4, 5, 2); // データピン、クロックピン、スレーブセレクトピン
LiquidCrystal_SR3W lcd(myWire, 16, 2); // 3線SPIでLCDを制御
void setup() {
lcd.begin(16, 2); // 16x2 LCDの初期化
lcd.print("Hello, World!"); // LCDにメッセージを表示
}
void loop() {
// メインループでは特に何もしない
}
この例では、ThreeWire myWire(4, 5, 2);
を使って3線式でLCDディスプレイを制御しています。myWire
オブジェクトが、データ転送とクロック信号、スレーブセレクト信号の管理を行い、LiquidCrystal_SR3W
ライブラリを使ってLCDにテキストを表示しています。
まとめ
ThreeWire
クラス: 3本の信号線を使用したSPI通信を実現するためのクラス。myWire
オブジェクト: 具体的な通信を制御するためにインスタンス化されるオブジェクト。- 引数: それぞれデータ、クロック、スレーブセレクト信号用のピン番号を指定する。
このように、ThreeWire myWire(4, 5, 2);
を使うことで、少ないピンで効率的にSPI通信を行うことができます。
RtcDS1302<ThreeWire> Rtc(myWire);
は、Arduinoでリアルタイムクロック(RTC)モジュールのDS1302を、3線式SPI通信で制御するためのオブジェクトを作成するコードです。
このコードの各部分について詳しく説明します。
RtcDS1302<ThreeWire>
について
RtcDS1302
は、DS1302リアルタイムクロック(RTC)モジュールを制御するためのクラスです。DS1302は時刻や日付を保持し、電源が切れてもバッテリーバックアップによりデータを保持する機能を持っています。
RTCモジュールは通常、SPIやI2Cなどの通信プロトコルを介して制御されますが、この場合、3線式SPI通信を使用しています。
ThreeWire
について
ThreeWire
クラスは、3線式のSPI通信プロトコルを実装するクラスです。前述のように、通常のSPI通信は4本の線を使いますが、この場合はデータ、クロック、スレーブセレクトの3本の信号線を使います。
ArduinoとRTCの間でSPI通信を3線式で行う場合、ThreeWire
クラスを使って、データ転送を行います。
RtcDS1302<ThreeWire> Rtc(myWire);
の詳細
この部分では、RTCモジュールの制御オブジェクト Rtc
を作成しています。このオブジェクトは、myWire
オブジェクトを使用して、3線式通信によってDS1302モジュールを制御します。
コードの構造
RtcDS1302<ThreeWire> Rtc(myWire);
RtcDS1302<ThreeWire>
:- これは、DS1302リアルタイムクロック(RTC)モジュールを操作するためのクラスで、
ThreeWire
オブジェクトを使った通信をサポートしています。テンプレートの形でThreeWire
クラスが使われており、RTCと3線式通信を結び付けています。
- これは、DS1302リアルタイムクロック(RTC)モジュールを操作するためのクラスで、
Rtc
:Rtc
は、RTCモジュールを制御するためのオブジェクト名です。このオブジェクトを通じて、DS1302モジュールに対する時刻の設定や読み取りを行います。
myWire
:- これは前述の
ThreeWire
オブジェクトで、3線式SPI通信を管理します。myWire
は3つのピン(データピン、クロックピン、スレーブセレクトピン)にマッピングされており、RTCモジュールとの通信に使用されます。
- これは前述の
例: RTCモジュールを使ったサンプルコード
次に、RtcDS1302<ThreeWire>
と ThreeWire
を使って、DS1302 RTCモジュールから時刻を読み取るサンプルコードを示します。
#include <ThreeWire.h>
#include <RtcDS1302.h>
// 3線式通信のピン設定
ThreeWire myWire(4, 5, 2); // データピン、クロックピン、スレーブセレクトピン
RtcDS1302<ThreeWire> Rtc(myWire); // RTCオブジェクトの作成
void setup() {
Serial.begin(9600); // シリアル通信の初期化
Rtc.Begin(); // RTCの初期化
// 時刻を設定(初回のみ必要)
// RtcDateTime dt(2023, 9, 8, 12, 30, 0); // YYYY, MM, DD, HH, MM, SS
// Rtc.SetDateTime(dt); // 時刻の設定
if (!Rtc.IsDateTimeValid()) {
Serial.println("RTCの時刻が無効です!");
}
}
void loop() {
RtcDateTime now = Rtc.GetDateTime(); // 現在時刻の取得
// 時刻の表示
Serial.print(now.Year());
Serial.print('/');
Serial.print(now.Month());
Serial.print('/');
Serial.print(now.Day());
Serial.print(" ");
Serial.print(now.Hour());
Serial.print(':');
Serial.print(now.Minute());
Serial.print(':');
Serial.println(now.Second());
delay(1000); // 1秒ごとに更新
}
主要な部分の説明
ThreeWire myWire(4, 5, 2);
ThreeWire
オブジェクトを作成し、3線式通信のためのピン(データピン4、クロックピン5、スレーブセレクトピン2)を設定します。
RtcDS1302<ThreeWire> Rtc(myWire);
RtcDS1302
クラスのオブジェクトRtc
を作成し、3線式通信でRTCモジュールを制御します。
Rtc.Begin();
- RTCモジュールの初期化を行います。
- 時刻設定
RtcDateTime dt(2023, 9, 8, 12, 30, 0);
のように時刻を設定します(初回のみ実行すればよい)。Rtc.SetDateTime(dt);
でRTCに時刻を設定します。
- 時刻取得
Rtc.GetDateTime();
でRTCから現在の時刻を取得し、シリアルモニタに出力します。
まとめ
RtcDS1302<ThreeWire> Rtc(myWire);
は、3線式SPI通信を利用して、DS1302リアルタイムクロック(RTC)モジュールを制御するためのコードです。これにより、DS1302モジュールから時刻や日付を読み取ったり、設定したりすることができます。myWire
オブジェクトは、データ、クロック、スレーブセレクトの3本のピンを指定して、RTCとの通信を管理します。
RTCの通信初期化と動作開始(Rtc.Begin)
Rtc.Begin()
は、ArduinoでDS1302リアルタイムクロック(RTC)モジュールを使用する際に、RTCの初期化を行うためのメソッドです。このメソッドは、主に次のことを行います。
- RTCモジュールとの通信の確立: DS1302チップが正しく動作しているかを確認し、ArduinoとRTCモジュール間の通信を開始します。
- 初期設定の適用: 必要に応じて、RTCモジュールの内部レジスタを初期化し、時刻や設定が適切に読み書きできる状態にします。
通常、スケッチ内の setup()
関数で呼び出し、RTCモジュールの使用準備を整えます。
RTCが保持している日時データが正しいかどうかを確認(Rtc.IsDateTimeValid)
Rtc.IsDateTimeValid()
は、リアルタイムクロック(RTC)モジュールが保持している日時データが有効かどうかを確認するためのメソッドです。このメソッドは、RTCが動作しているときに電源が落ちたり、初期化されていない場合など、日時データが正確でない可能性がある場合に役立ちます。
主な機能:
- データの一貫性チェック: 内部の日時データが正常であるかを確認します。
- 初期化の確認: RTCが正しく初期化されているかどうかも判断します。
もし false
を返した場合、日時データが信頼できないため、スケッチ内で適切な対処(例: 日時の再設定)を行う必要があります。
RTCに新しい日時を設定(Rtc.SetDateTime)
Rtc.SetDateTime()
は、DS1302リアルタイムクロック(RTC)モジュールに新しい日時データを設定するためのメソッドです。このメソッドを使うことで、RTCモジュールに現在の日時を設定できます。
使い方:
Rtc.SetDateTime(RtcDateTime(2024, 8, 31, 12, 34, 56));
この例では、RTCに2024年8月31日12時34分56秒という日時を設定しています。
主要な用途:
- RTCが初期化されたときや、電源が切れた後に日時を再設定する際に使用します。
RctDateTime
オブジェクトを使って、設定する日時を簡単に指定できます。
RtcDateTime(__DATE__, __TIME__)
は、Arduinoスケッチ内でリアルタイムクロック(RTC)モジュールの日時を設定するために使用されるコンストラクタ呼び出しです。この部分について詳しく説明します。
1. 基本的な構造
Rtc.SetDateTime(RtcDateTime(__DATE__, __TIME__));
この行は、RTCモジュールに現在の日時を設定しています。具体的には、__DATE__
と __TIME__
という2つのプリプロセッサマクロを使用して、コンパイル時の日時情報をRTCにセットしています。
2. 各要素の詳細
a. RtcDateTime
クラス
- 概要:
RtcDateTime
は、RTCモジュール(この場合はDS1302)とのやり取りに使用される日時データを保持するクラスです。このクラスは、年、月、日、時、分、秒などの日時情報を管理します。 - 用途: RTCモジュールに日時を設定したり、RTCから日時を取得したりする際に使用します。
b. __DATE__
と __TIME__
マクロ
__DATE__
:- 内容: ソースコードがコンパイルされた日付を表す文字列リテラルです。
- 形式:
"Mmm dd yyyy"
(例:"Aug 31 2024"
)
__TIME__
:- 内容: ソースコードがコンパイルされた時刻を表す文字列リテラルです。
- 形式:
"hh:mm:ss"
(例:"14:23:45"
)
これらのマクロは、コンパイル時に自動的に現在の日時に置き換えられます。つまり、スケッチをコンパイルした瞬間の日時情報が格納されます。
3. RtcDateTime(__DATE__, __TIME__)
の動作
RtcDateTime
クラスのコンストラクタは、__DATE__
と __TIME__
の文字列を解析して、RTCモジュールに設定可能な日時データ形式に変換します。具体的な処理は以下の通りです:
- 文字列の解析:
__DATE__
の形式"Mmm dd yyyy"
を解析して、月、日、年を取得します。__TIME__
の形式"hh:mm:ss"
を解析して、時、分、秒を取得します。
- 数値への変換:
- 取得した文字列を整数値(数値)に変換します。例えば、
"Aug"
は月の数字(8)に変換されます。
- 取得した文字列を整数値(数値)に変換します。例えば、
RtcDateTime
オブジェクトの生成:- 解析および変換された数値を使用して、
RtcDateTime
オブジェクトを生成します。このオブジェクトは、RTCモジュールに設定可能な形式で日時情報を保持します。
- 解析および変換された数値を使用して、
4. 実際のコードでの使用例
以下は、RtcDateTime(__DATE__, __TIME__)
がどのように使用されるかの具体例です。
#include <RtcDS1302.h>
ThreeWire myWire(4, 5, 2); // DAD, CLK, RST
RtcDS1302<ThreeWire> Rtc(myWire);
void setup() {
Serial.begin(9600);
Rtc.Begin();
if (!Rtc.IsDateTimeValid()) {
Serial.println("RTC lost confidence in the DateTime!");
// コンパイル時の日時をRTCに設定
Rtc.SetDateTime(RtcDateTime(__DATE__, __TIME__));
}
// 他の初期化コード...
}
void loop() {
// RTCから日時を取得して処理
}
この例では、RTCモジュールが有効な日時情報を保持していない場合(例: RTCの電源が切れた後に再起動した場合)、スケッチがコンパイルされた日時情報をRTCに設定します。これにより、RTCが最新の日時情報を持つようになります。
5. 注意点
- コンパイル時の日時:
__DATE__
と__TIME__
はスケッチがコンパイルされた瞬間の日時情報を提供します。スケッチがアップロードされるたびに、この日時が更新されます。- 実行時のリアルタイムの日時ではないため、RTCモジュール自体が正確な時刻を保持している場合は、通常この設定は一度だけ行われます。
- RTCの精度:
- RTCモジュールはバッテリーで動作し、電源が切れても日時を保持します。しかし、長期間使用するとRTCの精度が低下することがあります。その場合、
RtcDateTime(__DATE__, __TIME__)
を使用して再設定することが有効です。
- RTCモジュールはバッテリーで動作し、電源が切れても日時を保持します。しかし、長期間使用するとRTCの精度が低下することがあります。その場合、
- タイムゾーンの考慮:
__TIME__
はコンパイルされたマシンのローカルタイムを反映します。異なるタイムゾーンでコンパイルすると、RTCに設定される時刻も異なる可能性があるため、必要に応じて調整が必要です。
- 日付と時刻のフォーマット:
RtcDateTime
クラスが受け入れるフォーマットに正しく変換されるよう、__DATE__
と__TIME__
の形式が適切であることを確認してください。
6. まとめ
RtcDateTime(__DATE__, __TIME__)
は、Arduinoスケッチがコンパイルされた日時をRTCモジュールに設定する便利な方法です。これにより、RTCが無効な日時情報を保持している場合に、自動的にコンパイル時の日時でリセットすることができます。ただし、実行時の正確な日時を保持するためには、RTCモジュール自体が正常に動作し、適切な電源が供給されていることが前提となります。
RTCへの書き込みが可能かを確認(Rtc.GetIsWriteProtected)
Rtc.GetIsWriteProtected()
は、リアルタイムクロック(RTC)モジュールが書き込み保護されているかどうかを確認するためのメソッドです。
主な用途:
- 書き込み保護の状態確認: RTCモジュールが書き込み保護されていると、日時データの更新や他の設定ができなくなります。このメソッドは、RTCがその状態にあるかどうかを確認します。
使用例:
if (Rtc.GetIsWriteProtected()) {
Serial.println("RTC is write protected, disabling write protection.");
Rtc.SetIsWriteProtected(false);
}
このコードでは、RTCが書き込み保護されている場合、その保護を解除します。これにより、RTCの設定が可能になります。
RTCへの書き込み保護を有効・解除(Rtc.SetIsWriteProtected)
Rtc.SetIsWriteProtected(bool)
は、DS1302リアルタイムクロック(RTC)モジュールの書き込み保護を設定するメソッドです。このメソッドを使うことで、RTCへのデータの書き込みを防ぐことができます。
使い方:
Rtc.SetIsWriteProtected(true);
とすると、RTCは書き込み保護され、データの変更ができなくなります。Rtc.SetIsWriteProtected(false);
とすると、書き込み保護が解除され、データの変更が可能になります。
例:
// 書き込み保護を有効化
Rtc.SetIsWriteProtected(true);
// 書き込み保護を解除
Rtc.SetIsWriteProtected(false);
この機能は、RTCのデータが誤って変更されるのを防ぐために利用されます。
RTCが動作しているかを確認(Rtc.GetIsRunning)
Rtc.GetIsRunning()
は、DS1302リアルタイムクロック(RTC)モジュールが現在動作しているかどうかを確認するためのメソッドです。
主な用途:
- RTCの状態確認: このメソッドを使って、RTCが正しく動作中か(カウントを進めているか)をチェックできます。
- RTCが停止している場合は、日時のカウントが停止している可能性があるため、
Rtc.SetIsRunning(true)
で再開させることができます。
使用例:
if (!Rtc.GetIsRunning()) {
Serial.println("RTC was not actively running, starting now");
Rtc.SetIsRunning(true);
}
このコードは、RTCが停止している場合に、その動作を再開させます。
RTCの動作を開始・停止(Rtc.SetIsRunning)
Rtc.SetIsRunning(bool)
は、DS1302リアルタイムクロック(RTC)モジュールの動作を開始または停止するためのメソッドです。このメソッドを使用することで、RTCのカウントを開始したり、一時的に停止させたりすることができます。
使用方法:
Rtc.SetIsRunning(true);
:RTCを動作状態にし、時間のカウントを開始します。Rtc.SetIsRunning(false);
:RTCの動作を停止させ、時間のカウントを止めます。
例:
Rtc.SetIsRunning(true); // RTCを動作させる
Rtc.SetIsRunning(false); // RTCを停止させる
主な用途:
- RTCが初めて設定されたときに動作を開始させたり、特定の条件下でRTCの動作を一時的に停止する際に使用されます。
このメソッドは、RTCの時間計測を制御するために重要です。
RTCから現在の日時データを取得する(Rtc.GetDateTime())
Rtc.GetDateTime()
は、DS1302リアルタイムクロック(RTC)モジュールから現在の日時データを取得するためのメソッドです。このメソッドを呼び出すと、RtcDateTime
オブジェクトが返され、そのオブジェクトには年、月、日、時、分、秒といった日時情報が含まれています。
使用例:
RtcDateTime now = Rtc.GetDateTime();
Serial.print("Current time: ");
Serial.print(now.Hour());
Serial.print(":");
Serial.print(now.Minute());
Serial.print(":");
Serial.println(now.Second());
主な用途:
- 現在の日時を取得して、他の処理に利用する。
- システム時間の表示や、特定の時間に基づいたイベントのトリガーなどに使用します。
void printDateTime(const RtcDateTime& dt)
void printDateTime(const RtcDateTime& dt)
関数は、RTCモジュール(リアルタイムクロック)から取得した日時情報を表示するために使用される関数です。この関数の詳細について説明します。
関数の概要
- 関数名:
printDateTime
- 戻り値:
void
(なし) - 引数:
const RtcDateTime& dt
引数の説明
const RtcDateTime& dt
は、RTCモジュールから取得した日時情報を含むオブジェクトです。
const
: 引数が関数内で変更されないことを示します。RtcDateTime&
:RtcDateTime
クラスのオブジェクトへの参照です。dt
: 引数の名前で、日時(DateTime)を表しています。
関数の動作
この関数は通常、以下のような処理を行います:
- 年、月、日、時、分、秒の情報を
dt
オブジェクトから取得します。 - 取得した情報をフォーマットして表示します。
実装例
以下は、この関数の一般的な実装例です:
void printDateTime(const RtcDateTime& dt)
{
char datestring[20];
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),
dt.Day(),
dt.Year(),
dt.Hour(),
dt.Minute(),
dt.Second() );
Serial.print(datestring);
}
この実装では、日付と時刻を”MM/DD/YYYY HH:MM:SS”形式で表示しています。
使用例
この関数は通常、RTCモジュールから現在の日時を取得した後に呼び出されます:
RtcDS3231<TwoWire> Rtc(Wire);
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
この関数を使用することで、RTCモジュールから取得した日時情報を簡単に表示できます。
液晶ディスプレイ(LCD)
環境構築(ライブラリインクルード)
#include <LiquidCrystal.h>
LCDディスプレイの初期設定(LiquidCrystal lcd())
LiquidCrystal lcd();
は、Arduino で LCD ディスプレイを制御するための LiquidCrystal
クラスのコンストラクタです。このコンストラクタを使って、Arduino のどのピンが LCD に接続されているかを指定し、LCD の初期設定を行います。
基本構文
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
または、オプションとして読み書きピン(rw
)を指定する場合の構文は次の通りです:
LiquidCrystal lcd(rs, rw, en, d4, d5, d6, d7);
パラメータ
rs
(Register Select): LCDのレジスタ選択ピン。データ送信とコマンド送信の切り替えに使用されます。rw
(Read/Write): 読み取り/書き込みの切り替えピン。通常、書き込みモードで使われるため、rw
ピンを使わずにグランドに接続して使用することが多いです。オプションです。en
(Enable): データの読み取り/書き込みのタイミングを制御するためのピン。LCDに命令を送る際に使います。d4
,d5
,d6
,d7
: 4ビットモードでデータを送るために使用されるピン。LCDに接続されるArduinoのデジタルピンです。
構文例
- 基本的な接続(4ビットモード)
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
これは、LCDに接続されたピンを指定しています。次のように解釈します:rs
ピンは Arduino のデジタルピン 7 に接続en
ピンは Arduino のデジタルピン 8 に接続d4
,d5
,d6
,d7
ピンはそれぞれ Arduino のデジタルピン 9、10、11、12 に接続
rw
ピンを指定する場合LiquidCrystal lcd(7, 6, 8, 9, 10, 11, 12);
この例では、rw
ピンとして Arduino のデジタルピン 6 を指定していますが、通常このピンはグランド(GND)に接続され、write-only
モードで使用されることが多いです。この場合、ピン数が限られている場合はrw
ピンを省略しても動作します。
例
フルコード例
次に、典型的な Arduino プロジェクトでの LiquidCrystal lcd()
の使い方の例を示します:
#include <LiquidCrystal.h>
// LCDに接続するピンの定義
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12;
// LiquidCrystalオブジェクトを作成し、ピンを指定
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// LCDの行数と列数を指定(ここでは16列×2行のLCD)
lcd.begin(16, 2);
// LCDにメッセージを表示
lcd.print("Hello, World!");
}
void loop() {
// ループ内での特別な処理はない
}
コンストラクタの機能
LiquidCrystal lcd();
は、LCDの制御に必要なピン設定を行い、LCDディスプレイを制御するための準備を行うためのメソッドです。このメソッドを使って、接続するピンをArduinoに伝え、LCDとの通信ができるようにします。
4ビットモードについて
LCDディスプレイは一般的に8ビットモードと4ビットモードのどちらかで制御できますが、4ビットモードが一般的です。理由は、少ないピン数でLCDを制御できるためです。8ビットモードでは8本のデータ線を使うのに対し、4ビットモードではデータ線を4本だけ使用します。
4ビットモードでは、1回のデータ送信に2回の操作が必要になりますが、ピン数を減らせるため、小型のプロジェクトでよく使用されます。
よくある誤解
LiquidCrystal lcd();
は LCD自体の設定を行うものではなく、ArduinoとLCDディスプレイをつなぐピンを指定するためのものです。- これを呼び出しただけではLCDには何も表示されません。実際に動作させるには、
lcd.begin()
でLCDのサイズ(行数と列数)を設定し、lcd.print()
で表示を行います。
まとめ
LiquidCrystal lcd();
は、Arduino が LCD を制御するために必要なピン接続を定義するためのコンストラクタです。- 接続されるピンは、デジタルピンで、
rs
,en
,d4
〜d7
などを指定します。 - 一般的には 4ビットモード が使用され、データの送受信に必要なピン数を少なく抑えられます。
これを使うことで、LCDを柔軟に制御し、文字や数値を表示するアプリケーションを作ることができます。
LCDディスプレイの初期化(lcd.begin)
lcd.begin(16, 2);
は、ArduinoのLiquidCrystal
ライブラリを使用してLCDディスプレイを初期化するための関数です。この関数を使用することで、LCDの動作を設定し、指定した行数と文字数の表示領域を確保します。
詳細な説明:
lcd
:lcd
はLiquidCrystal
クラスのインスタンスであり、このオブジェクトを通じてLCDディスプレイを操作します。例えば、テキストの表示やカーソルの位置指定など、LCDの制御はこのlcd
オブジェクトを使って行います。begin(16, 2)
: この関数は、LCDディスプレイの表示形式(サイズ)を設定します。引数として2つの値を指定します。16
: LCDの横方向の文字数を指定しています。ここでは16文字となっており、1行あたり最大16文字を表示できるLCDを意味します。2
: LCDの行数を指定しています。この例では2行のLCDを想定しています。
lcd.begin(16, 2);
では、16文字×2行のLCDディスプレイを使うことを意味しています。よく使われる一般的なLCDは、この形式を採用しています(例: 1602 LCDモジュール)。
実行時の役割:
この関数が実行されると、LCDの初期化が行われ、指定されたサイズでLCDが動作する準備が整います。例えば、カーソルの初期位置が左上(1行目、1文字目)に設定され、以降のlcd.print()
などの関数で表示される文字が、設定された16文字×2行の領域に表示されます。
関連する他の機能:
lcd.setCursor(x, y);
:カーソルの位置を指定する(x
は横方向の文字位置、y
は行数)。lcd.clear();
:LCDの表示をすべて消去する。lcd.print("文字列");
:LCDに文字列を表示する。
まとめ:
lcd.begin(16, 2);
は、LCDディスプレイの表示サイズを「16文字×2行」に設定するための関数です。LCDが正しく初期化され、以後のテキスト表示が期待通りに行われるようにします。この初期化を行わないと、LCDは正しく動作しない可能性があります。
LCDディスプレイにテキストや数値を表示する(lcd.print)
lcd.print()
は、Arduino の LiquidCrystal
ライブラリにおけるメソッドで、LCDディスプレイにテキストや数値を表示するために使われます。このメソッドを使うことで、指定した文字列や数値をLCDに簡単に出力できます。
基本構文
lcd.print(value);
value
は、表示したい文字列や数値などのデータです。value
にはテキスト、整数、浮動小数点数、さらには他の型も指定できます。
使用例
- 文字列を表示する例
lcd.print("Hello, World!");
このコードは、LCDディスプレイにHello, World!
という文字列を表示します。 - 数値を表示する例
int number = 123; lcd.print(number);
このコードは、整数123
をLCDディスプレイに表示します。 - 浮動小数点数を表示する例
float decimalNumber = 3.14159; lcd.print(decimalNumber);
このコードは、LCDに3.14159
という浮動小数点数を表示します。デフォルトでは、小数点以下の桁数は制限されませんが、後述するフォーマットを使うことで制御できます。
表示形式とフォーマットの調整
lcd.print()
で数値を表示するとき、フォーマットを調整することもできます。
1. 整数(基数指定)
数値を異なる基数(進数)で表示することができます。DEC
(10進数)、HEX
(16進数)、OCT
(8進数)、BIN
(2進数)などが使えます。
int number = 255;
lcd.print(number, DEC); // 255(10進数)
lcd.print(number, HEX); // FF(16進数)
lcd.print(number, OCT); // 377(8進数)
lcd.print(number, BIN); // 11111111(2進数)
2. 浮動小数点数(小数点以下の桁数指定)
浮動小数点数を表示するとき、桁数を指定できます。
float pi = 3.14159;
lcd.print(pi, 2); // 小数点以下2桁まで表示: 3.14
カーソル位置と lcd.print()
lcd.print()
で表示する文字列は、現在のカーソル位置に表示されます。LCDディスプレイのカーソルは通常左上(0, 0)にありますが、lcd.setCursor()
関数を使って表示位置を変更できます。
カーソル位置を変更する例
lcd.setCursor(0, 1); // 2行目の最初の位置にカーソルを移動
lcd.print("2nd Line");
このコードは、LCDの2行目(行番号は0から始まるので実際には行1)に 2nd Line
と表示します。
クリアと上書き
LCDの表示は、lcd.print()
を使って更新されますが、以前に表示された文字列はクリアされない限り残り続けます。画面をクリアする場合は、lcd.clear()
を使います。
lcd.clear(); // 画面をクリアする
lcd.print("New Text");
lcd.print()
の特徴まとめ:
- 文字列や数値の表示:
lcd.print()
は文字列、整数、浮動小数点数などをLCDに表示できます。 - 表示フォーマットの調整: 基数や小数点以下の桁数を指定して表示できます。
- カーソル位置の変更:
lcd.setCursor()
と併用して、特定の位置に文字列を表示できます。
これらの機能により、lcd.print()
はLCDにデータを表示するための主要なメソッドとして、さまざまな状況で使用されます。
LCDディスプレイにテキストや数値を表示する(lcd.write)
Arduinoのlcd.write()関数は、LCD(液晶ディスプレイ)に文字を表示するための重要な機能です。以下にlcd.write()の詳細を説明します。
基本的な使い方
lcd.write()関数は、LCDに1文字ずつ表示するために使用されます。主に以下の2つの方法で使用できます:
- ASCII文字コードを使用する方法
- 文字リテラルを直接指定する方法
例えば:
lcd.write(65); // 'A'を表示
lcd.write('B'); // 'B'を表示
特徴と利点
多言語対応: lcd.write()の大きな利点は、英数字以外の文字も表示できることです。例えば、カタカナや特殊記号を表示する際に使用できます[1][4]。
16進数表記: 文字を16進数で指定することも可能です。例えば:
lcd.write(0b10110001); // 'ア'(カタカナのア)を表示
応用例
lcd.write()は、カスタム文字の作成と表示にも使用できます。例えば、棒人間のような簡単なアイコンを作成し、LCDに表示することができます[1]。
print()との違い
lcd.print()関数が主に英数字の表示に使用されるのに対し、lcd.write()は以下の場合に特に有用です:
- カタカナや特殊文字の表示
- カスタム文字の表示
- バイナリデータの直接表示
注意点
- lcd.write()は1文字ずつ表示するため、複数の文字を表示する場合はループ処理が必要になることがあります。
- 文字コードはLCDの種類によって異なる場合があるため、使用するLCDの仕様を確認することが重要です。
lcd.write()関数を使いこなすことで、Arduinoプロジェクトでより柔軟で多様な文字表示が可能になります。
lcd.write()とlcd.print()の主な違いは以下の通りです:
データの扱い方
lcd.write()
- バイトデータを直接LCDに書き込みます[1][4]。
- 文字コードや特殊文字を1バイトずつ表示するのに適しています。
lcd.print()
- 様々なデータ型(整数、浮動小数点数、文字列など)を自動的に文字列に変換してから表示します[1][2]。
- 数値や文字列を簡単に表示できます。
表示の挙動
lcd.write()
- LCDの端に達しても自動的に改行しません[3]。
- 1文字ずつ制御したい場合に適しています。
lcd.print()
- LCDの端に達すると自動的に改行します[3]。
- 連続したテキスト表示に便利です。
使用例
lcd.write()
lcd.write(65); // 'A'を表示
lcd.write('B'); // 'B'を表示
lcd.write(0b10110001); // カタカナの'ア'を表示
lcd.print()
int value = 42;
lcd.print("The answer is: ");
lcd.print(value);
特殊な用途
lcd.write()
- カスタム文字やグラフィックスの表示に使用できます。
- 多言語文字(カタカナなど)の表示に適しています[1]。
lcd.print()
- フォーマット指定付きの出力(printf風)が可能です[2]。
- 数値を10進数、16進数、2進数などで表示できます。
lcd.write()はより低レベルな制御が可能で、lcd.print()はより高レベルで使いやすい関数といえます。用途に応じて適切な方を選択することが重要です。
LCDディスプレイのカーソル位置を設定する(lcd.setCursor)
lcd.setCursor()
は、Arduino の LiquidCrystal
ライブラリにおけるメソッドで、LCDディスプレイ上のカーソル位置を設定するために使用されます。このメソッドを使うことで、次に表示されるテキストやデータがどの位置から始まるかを指定することができます。
基本構文
lcd.setCursor(column, row);
column
: 横方向の位置(列番号)。LCDの左から何番目の位置にカーソルを置くかを指定します。0が最初の列(最も左)に対応します。row
: 縦方向の位置(行番号)。LCDの上から何番目の行にカーソルを置くかを指定します。0が最初の行(最上部)に対応します。
具体例
1. カーソルを指定位置に移動して文字列を表示する
lcd.setCursor(0, 1); // 1行目の最初の位置にカーソルを移動
lcd.print("Hello");
このコードでは、LCDの2行目の最初の位置にカーソルを移動し、そこに「Hello」という文字列を表示します。行番号は0
から始まるので、setCursor(0, 1)
は2行目の一番左の位置を指しています。
2. 特定の位置にデータを表示
lcd.setCursor(5, 0); // 1行目の6番目の位置にカーソルを移動
lcd.print("Data");
この例では、1行目の6番目(列番号が0から始まるため、5番目の位置)にカーソルを移動し、「Data」という文字列を表示します。
典型的なLCDディスプレイのサイズとカーソル位置
一般的なLCDディスプレイのサイズは次のようなものがあります:
- 16×2 LCD: 16文字×2行
- 20×4 LCD: 20文字×4行
16×2 LCDの場合の行と列:
- 行番号は
0
(1行目)と1
(2行目)の2つ。 - 列番号は
0
から15
までの16個。
20×4 LCDの場合の行と列:
- 行番号は
0
(1行目)から3
(4行目)までの4つ。 - 列番号は
0
から19
までの20個。
実際の例:16×2 LCDにおけるsetCursor
lcd.setCursor(0, 0); // 1行目の最初の位置
lcd.print("Hello,"); // 1行目に "Hello," を表示
lcd.setCursor(0, 1); // 2行目の最初の位置
lcd.print("World!"); // 2行目に "World!" を表示
この例では、16×2のLCDディスプレイに「Hello,」を1行目に、「World!」を2行目に表示しています。
応用例:カーソルを使った動的な表示
lcd.setCursor()
を使うと、特定の位置で文字やセンサーデータを表示できます。
センサーデータの表示例
int temperature = 25;
lcd.setCursor(0, 0); // 1行目にタイトルを表示
lcd.print("Temp:");
lcd.setCursor(6, 0); // 1行目の特定位置に温度データを表示
lcd.print(temperature);
lcd.print(" C");
このコードでは、LCDの1行目に「Temp: 25 C」という表示がされます。lcd.setCursor()
を使って、データの表示場所を調整しています。
lcd.setCursor()
のまとめ
- 指定した位置にカーソルを移動し、次に
lcd.print()
で表示される文字列やデータの表示開始位置を制御するための関数です。 - 行(row)と列(column)のインデックスを指定し、表示する位置を柔軟に設定できます。
- 0から始まるインデックスを使い、LCDディスプレイの1行目、1列目は
setCursor(0, 0)
となります。 - 動的なデータ(センサーデータや可変情報)を特定の位置に表示する際に非常に便利です。
この関数を使うことで、複数行・複数列にわたるLCDディスプレイでデータを自由に配置できます。
LCDディスプレイをクリアする(lcd.clear)
lcd.clear()
は、Arduino の LiquidCrystal
ライブラリにおけるメソッドで、LCDディスプレイ全体をクリア(消去)するために使用されます。呼び出すと、LCDに表示されているすべての文字やデータが消去され、カーソルの位置も最初の位置(左上:(0, 0)
)にリセットされます。
基本構文
lcd.clear();
この1行でLCDの全表示が消去されます。LCDがクリアされた後、カーソル位置が (0, 0)
に移動するので、その後に文字列や数値を新たに表示するときは、LCDの最初の位置から始まります。
lcd.clear()
の使いどころ
lcd.clear()
は、LCDディスプレイの内容を消して、新しいデータやメッセージを表示したい場合に使用します。例えば、動的に変化するセンサーデータやユーザー入力をリアルタイムで表示するアプリケーションで、古いデータを消して新しいデータを表示したいときに使います。
使用例
1. 簡単なクリア操作の例
lcd.print("Hello, World!"); // LCDに「Hello, World!」を表示
delay(2000); // 2秒待つ
lcd.clear(); // LCDをクリア
このコードでは、まず「Hello, World!」をLCDに表示し、2秒待った後に lcd.clear()
を使って画面をクリアします。
2. データを更新して表示する例
リアルタイムで変化するセンサーデータをLCDに表示する場合、lcd.clear()
を使って前のデータを消去してから新しいデータを表示します。
void loop() {
int sensorValue = analogRead(A0); // センサーデータの読み取り
lcd.clear(); // LCDをクリア
lcd.setCursor(0, 0); // カーソルを左上に設定
lcd.print("Sensor Value: "); // ラベルを表示
lcd.setCursor(0, 1); // 2行目の最初に移動
lcd.print(sensorValue); // センサーデータを表示
delay(1000); // 1秒待機して再度データを更新
}
この例では、センサーから取得したデータをLCDに1秒ごとに更新して表示しています。lcd.clear()
を使って毎回画面をクリアし、新しいデータを表示しています。
注意点
- ちらつきの発生:
lcd.clear()
は、画面全体を一瞬で消去するため、頻繁に使うとLCDの表示がちらつくことがあります。ちらつきを抑えるために、あまり頻繁に呼び出さない方が良い場合があります。 - 上書きによる代替方法: もし毎回画面全体をクリアする必要がない場合、既存の内容に部分的に上書きすることでちらつきを防ぐことができます。例えば、固定文字列の上に可変データ(数値など)だけを表示する場合、クリアせずに
lcd.setCursor()
でその場所に移動し、必要な部分だけを更新する方法もあります。
ちらつきを防ぐ代替案
lcd.setCursor(0, 1); // 2行目にカーソルを移動
lcd.print(" "); // スペースで上書きして前の文字を消去
lcd.setCursor(0, 1); // 再度カーソルを移動して新しいデータを表示
lcd.print(sensorValue);
この方法では、クリアする代わりに、数値の部分だけを上書きすることでちらつきを減らすことができます。
まとめ
lcd.clear()
は、LCDディスプレイの内容を一括して消去し、次の新しいデータを表示する準備をするための便利なメソッドです。しかし、頻繁に使用するとちらつきが発生する可能性があるため、必要に応じて適切に使用することが重要です。
画面内のテキストやデータを1文字左右へ移動する(lcd.scrollDisplayLeft)(lcd.scrollDisplayRight)
lcd.scrollDisplayLeft()
は、Arduino の LiquidCrystal
ライブラリにおけるメソッドで、LCDディスプレイ上の表示内容を左にスクロールさせるために使用します。この関数を使うと、画面内のテキストやデータを一文字ずつ左へ移動させることができます。これは、表示内容がディスプレイの幅を超える場合などに、動的な表示を演出する際に非常に便利です。
基本構文
lcd.scrollDisplayLeft();
このコマンドを実行すると、LCDの画面全体が一文字分左にスクロールします。カーソルの位置は変更されません。
使いどころ
- 長い文字列の表示: 16文字×2行のLCDでは、長い文字列はすべて表示しきれません。そこで、スクロール機能を使って、見えない部分を動的に表示することができます。
- アニメーション効果: スクロールさせることで、テキストが流れるように見えるため、ユーザーに動きを感じさせることができます。
使用例
1. 基本的なスクロールの例
#include <LiquidCrystal.h>
// LCDに接続されるピンの設定
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2); // 16文字×2行のLCDを初期化
lcd.print("Hello, World!"); // メッセージを表示
delay(2000); // 2秒間表示
}
void loop() {
lcd.scrollDisplayLeft(); // 表示内容を左にスクロール
delay(500); // 0.5秒ごとにスクロール
}
このコードでは、「Hello, World!」というメッセージがLCDに表示され、500ミリ秒ごとに一文字ずつ左にスクロールします。スクロールさせると、テキストの一部が画面外に移動し、左から新しい部分が表示されるようになります。
2. 長いテキストをスクロールする例
#include <LiquidCrystal.h>
const int rs = 7, en = 8, d4 = 9, d5 = 10, d6 = 11, d7 = 12;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2);
lcd.print("This is a long message that scrolls");
delay(2000);
}
void loop() {
lcd.scrollDisplayLeft(); // 画面を左にスクロール
delay(300); // 0.3秒ごとにスクロール
}
ここでは、"This is a long message that scrolls"
という長い文字列を表示しますが、LCDに表示できるのは最初の16文字までです。この場合、lcd.scrollDisplayLeft()
を使うことで、文字列全体が少しずつ左にスクロールされ、隠れていた部分が表示されていきます。
動作の詳細
- スクロール動作:
lcd.scrollDisplayLeft()
を呼び出すたびに、LCDの内容が1文字分左に移動します。もし右端に表示されている文字が画面外に出た場合、それは表示されなくなり、左から新しい文字が表示されるようになります。 - カーソルの位置:
lcd.scrollDisplayLeft()
は カーソルの位置には影響を与えません。カーソルはそのままの位置に残りますが、表示されるテキストが動きます。 - スクロール速度の調整: スクロールの速度は、
delay()
関数を使って調整します。例えば、delay(100)
に設定すると高速でスクロールし、delay(1000)
に設定すると1秒に1回スクロールします。
応用例: スクロールを止める
時々スクロールを止め、しばらく表示を固定することも可能です。例えば、数秒間表示を停止し、その後再びスクロールを続けることができます。
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
void setup() {
lcd.begin(16, 2);
lcd.print("Scrolling Text");
delay(2000);
}
void loop() {
for (int i = 0; i < 10; i++) { // 10回左にスクロール
lcd.scrollDisplayLeft();
delay(300);
}
delay(2000); // 2秒間スクロールを止める
}
このコードでは、10回スクロールした後、2秒間スクロールを止めて表示を固定します。その後、またスクロールを再開します。
注意点
- 表示内容のリセット: スクロール操作を行うと、表示されている内容が徐々に左に移動して画面外に消えていきますが、新しいデータを表示させるためにスクロールをリセットしたい場合は、
lcd.clear()
を使用してディスプレイをクリアし、再度データを表示させることができます。 - スクロール方向:
lcd.scrollDisplayLeft()
で表示内容を左にスクロールしますが、逆に右にスクロールするメソッドとしてlcd.scrollDisplayRight()
もあります。
まとめ
lcd.scrollDisplayLeft()
は、LCD上の表示内容を左にスクロールさせるためのメソッドです。- 主に、長い文字列を順次表示したり、アニメーション的な効果を出したりする際に使用されます。
delay()
関数を使ってスクロール速度を調整できます。- スクロールはカーソル位置には影響しないため、テキストをスクロールさせながら特定の位置に新しいデータを表示することも可能です。
この関数を使うと、LCDに動的な表示効果を加えることができ、視覚的な演出や情報表示に役立ちます。
サーボモータ(Servo)
環境構築(ライブラリインクルード)
#include <Servo.h>
サーボモータに接続するピンを指定する(servoMotor.attach)
servoMotor.attach
は、Arduino IDEで使用される Servo
ライブラリのメソッドで、サーボモーターを特定のピンに接続するために使用します。このメソッドを呼び出すことで、指定したピンからサーボモーターを制御できるようになります。
以下の構文で使用されます:
servoMotor.attach(pin);
パラメータ:
- pin: サーボモーターの制御信号が接続されているArduinoのデジタルピン番号を指定します。
例:
#include <Servo.h>
Servo servoMotor; // サーボモーターのインスタンスを作成
void setup() {
servoMotor.attach(9); // サーボモーターをデジタルピン9に接続
}
void loop() {
servoMotor.write(90); // サーボモーターを90度に回転させる
delay(1000); // 1秒待機
}
servoMotor.attach()
メソッドの詳細:
- ピンの設定:
attach
メソッドを使用すると、指定したピンでPWM信号が生成され、サーボモーターの角度を制御できます。 - PWM信号の発生: ArduinoはPWM(パルス幅変調)を使用してサーボに角度の指示を送ります。サーボは受け取った信号の幅に基づいて角度を変えます。
- 複数のサーボを制御可能: Arduinoは複数のサーボを同時に制御できます。各サーボには個別のインスタンスとピンを使用します。
オプションのパラメータ
attach
メソッドは、ピン番号以外にもオプションで次のように最小・最大パルス幅を指定できます:
servoMotor.attach(pin, minPulse, maxPulse);
- minPulse: 最小パルス幅 (デフォルトは544マイクロ秒)
- maxPulse: 最大パルス幅 (デフォルトは2400マイクロ秒)
これにより、カスタムのサーボの範囲を設定できます。
質問があれば、ぜひどうぞ!
サーボモータの角度を動かす(servoMotor.write)
servoMotor.write
は、Arduinoでサーボモーターを制御するための Servo
ライブラリのメソッドで、サーボモーターを特定の角度に動かすために使用されます。このメソッドは、指定した角度の位置にサーボモーターを移動させます。
基本構文:
servoMotor.write(angle);
パラメータ:
- angle: サーボモーターの角度を0度から180度の範囲で指定します。0度は最小位置、180度は最大位置を表します。
例:
#include <Servo.h>
Servo servoMotor;
void setup() {
servoMotor.attach(9); // サーボモーターをデジタルピン9に接続
}
void loop() {
servoMotor.write(0); // サーボを0度に移動
delay(1000); // 1秒待機
servoMotor.write(90); // サーボを90度に移動
delay(1000); // 1秒待機
servoMotor.write(180); // サーボを180度に移動
delay(1000); // 1秒待機
}
servoMotor.write()
メソッドの詳細:
- 角度の指定:
write
メソッドに角度を指定すると、その角度にサーボモーターが回転します。0度は最小角度、180度は最大角度です。 - 非リニアな動作: 一部のサーボは、指定した角度通りに正確に動作しない場合があります(機械的な制約や個々のサーボの特性による)。そのため、サーボの反応は微調整が必要になることがあります。
- 範囲外の値:
0
~180
の範囲外の値を指定した場合、内部で自動的にこの範囲に丸められます。 - サーボの動作速度:
write
メソッドでは、速度は設定されず、サーボは可能な限り速く指定された位置に移動します。速度制御をしたい場合は、別途writeMicroseconds()
や、遅延(delay()
)を利用することで速度を調整できます。
オプション: マイクロ秒での制御
サーボの角度ではなく、PWM信号のパルス幅を直接指定してサーボを制御することも可能です。その場合は、writeMicroseconds()
メソッドを使用します。
例: writeMicroseconds()
servoMotor.writeMicroseconds(1500); // 中央位置に移動
1500
マイクロ秒は一般的にサーボの中間位置(90度)に対応します。
まとめ
write()
メソッドは、角度(0〜180度)でサーボを制御するのに使います。- 精密な制御が必要な場合は、
writeMicroseconds()
を使用してPWM信号のパルス幅を調整できます。
質問があれば、さらに詳しく説明しますよ!
フラッシュメモリを使用する(avr/pgmspace.h)
環境構築(ライブラリインクルード)
#include <avr/pgmspace.h>
フラッシュメモリにデータを保存する(PROGMEM)
PROGMEM
は、Arduinoや他のAVRマイコンで使用される特別なキーワードで、データをフラッシュメモリ(プログラムメモリ)に保存するために使います。通常、データはSRAM(データメモリ)に格納されますが、SRAMは非常に限られており(たとえば、Arduino Unoでは2KBしかありません)、メモリ不足の原因となることがあります。
PROGMEM
を使うことで、SRAMの代わりにフラッシュメモリ(プログラムメモリ)にデータを格納し、貴重なSRAMを節約できます。フラッシュメモリはArduino Unoで32KBあり、プログラムコードだけでなく、データも保存することができます。
1. PROGMEM
の基本的な使い方
PROGMEM
キーワードを使って変数や配列を宣言すると、それらはフラッシュメモリに保存されます。例えば、文字列や定数テーブルなど、大きなデータをSRAMに保存する代わりに、フラッシュメモリに格納して利用します。
PROGMEM
の構文
const dataType variableName[] PROGMEM = { values };
dataType
: データの型(例:char
,int
,uint16_t
,float
など)。variableName[]
: 変数または配列の名前。PROGMEM
: このキーワードを指定することで、データがフラッシュメモリに保存されます。
例1: 数値配列をフラッシュメモリに保存
#include <avr/pgmspace.h>
// 16ビット整数の配列をフラッシュメモリに格納
const uint16_t myData[] PROGMEM = {100, 200, 300, 400, 500};
void setup() {
Serial.begin(9600);
// フラッシュメモリから値を読み取る
for (int i = 0; i < 5; i++) {
uint16_t value = pgm_read_word(&(myData[i])); // 値を読み取る
Serial.println(value); // 読み取った値をシリアルモニタに表示
}
}
void loop() {
// 空のループ
}
2. PROGMEM
の使用例
例2: 文字列をフラッシュメモリに保存
Arduinoプログラムで多用される文字列(メッセージや長いテキストなど)は、SRAMを多く消費します。このようなデータをフラッシュメモリに格納してSRAMを節約できます。
#include <avr/pgmspace.h>
// フラッシュメモリに格納された文字列
const char message[] PROGMEM = "Hello, World!";
void setup() {
Serial.begin(9600);
// フラッシュメモリから文字列を1文字ずつ読み出して表示
for (int i = 0; i < strlen_P(message); i++) {
char c = pgm_read_byte(&(message[i])); // 1バイトずつ読み込む
Serial.print(c);
}
}
void loop() {
// 空のループ
}
strlen_P(message)
は、フラッシュメモリ内の文字列の長さを取得します。pgm_read_byte()
を使って、1バイトずつフラッシュメモリから読み込みます。
3. PROGMEM に関連する関数
フラッシュメモリに保存したデータにアクセスするためには、pgm_read_*
関数を使います。これは、データ型に応じて適切な読み出し方法を選択するために必要です。
pgm_read_byte()
: 8ビット(1バイト)のデータを読み込みます。pgm_read_word()
: 16ビット(2バイト)のデータを読み込みます。pgm_read_dword()
: 32ビット(4バイト)のデータを読み込みます。pgm_read_float()
: フラッシュメモリから浮動小数点数(float
)を読み込みます。
4. PROGMEM を使うメリットと注意点
メリット
- SRAMの節約: SRAMが非常に限られているマイコン(Arduino Unoなど)で、定数データや文字列をフラッシュメモリに保存することで、SRAMの使用量を大幅に減らせます。
- 大規模な定数データの格納: 例えば、センサーのキャリブレーションデータや、数学的ルックアップテーブルなどの大きなデータセットをフラッシュメモリに保存することで、SRAMを効率的に使えます。
注意点
- 書き換え不可:
PROGMEM
に保存されたデータは、フラッシュメモリに格納されるため、プログラムの実行中に書き換えることができません。定数としてのみ使用できます。 - アクセスが遅い: フラッシュメモリへのアクセスはSRAMよりも遅くなることがあるため、頻繁にアクセスするデータはSRAMに保存したほうがパフォーマンスが良くなる場合があります。
- 読み込みに特殊な関数が必要: フラッシュメモリからデータを取り出すためには、
pgm_read_byte()
やpgm_read_word()
などの特別な関数を使用する必要があります。通常のアクセスとは異なるため、プログラムの中でこれを考慮する必要があります。
5. よくある用途
- 文字列メッセージ: デバッグや表示用の長い文字列メッセージをフラッシュメモリに格納し、必要に応じて読み出す。
- ルックアップテーブル: 数学的関数の事前計算結果(例: サイン波や三角関数、センサーの補正値)をフラッシュメモリに格納し、必要なときにデータを効率的に読み出す。
- アイコンや画像データ: LEDマトリックスディスプレイや液晶ディスプレイに表示するパターンやアイコンなど、定期的に使われるデータをフラッシュメモリに格納。
6. PROGMEM を使った実用例
例3: フラッシュメモリに保存したアイコンデータを使う
次のコードは、LEDマトリックスディスプレイ用のアイコンデータを PROGMEM
に格納し、必要に応じて読み出す例です。
#include <avr/pgmspace.h>
// LEDマトリックス用のアイコンデータ
const uint8_t icon[] PROGMEM = {
0x3C, 0x42, 0xA9, 0x85, 0xA9, 0x91, 0x42, 0x3C // 笑顔アイコン
};
void setup() {
Serial.begin(9600);
// フラッシュメモリからアイコンデータを読み出し
for (int i = 0; i < 8; i++) {
uint8_t value = pgm_read_byte(&(icon[i]));
Serial.println(value, HEX); // アイコンデータを16進数で表示
}
}
void loop() {
// 空のループ
}
この例では、8×8のLEDマトリックスディスプレイで使用する「笑顔」のアイコンデータをフラッシュメモリに保存しています。このデータをフラッシュメモリから取り出し、シリアルモニタに表示しています。
まとめ
PROGMEM
は、ArduinoやAVRマイコンで、データをフラッシュメモリに保存するためのキーワードです。- SRAMの使用を節約し、特に大きな定数データを格納するのに役立ちます。
- フラッシュメモリに保存されたデータにアクセスするには、
pgm_read_*
関数を使う必要があります。 - ただし、データの書き換えができない、アクセス速度が遅いというデメリットもあるため、使用するデータや場面に応じて適切に使い分ける必要があります。
`
フラッシュメモリから16bitのデータを読み出す(pgm_read_word)
pgm_read_word()
は、ArduinoなどのAVRマイコンで、プログラムメモリ(フラッシュメモリ)から16ビット(2バイト)のデータを読み出すために使われる関数です。この関数は、<avr/pgmspace.h>
ヘッダーファイルの一部であり、定数データやルックアップテーブルなどをフラッシュメモリに保存しておき、動的にアクセスするために使用します。
1. 背景
Arduinoのマイコンには、SRAM(データメモリ)とフラッシュメモリ(プログラムメモリ)があり、通常の変数はSRAMに保存されます。しかし、SRAMは容量が非常に限られているため、大量のデータや変更のない定数データをSRAMに保存するとメモリ不足になることがあります。
この問題を回避するために、定数データはフラッシュメモリに保存し、pgm_read_*
系の関数を使って必要なときにフラッシュメモリから読み込むという方法がよく使われます。
pgm_read_word()
はそのうちの1つで、フラッシュメモリに保存された16ビット(2バイト)単位のデータを読み出します。
2. pgm_read_word()
の構文
uint16_t pgm_read_word(const void* address);
引数
address
: フラッシュメモリ上の読み出したいデータのアドレス(ポインタ)。
戻り値
uint16_t
型(16ビット、符号なし)のデータ。指定されたアドレスから読み込まれた16ビット(2バイト)の値が返されます。
3. pgm_read_word()
の使い方
例1: 定数配列からデータを読み込む
まず、フラッシュメモリに16ビットの定数配列を格納し、pgm_read_word()
でその値を読み出す例を紹介します。
#include <avr/pgmspace.h>
// 16ビットの定数データをフラッシュメモリに格納
const uint16_t myData[] PROGMEM = {1000, 2000, 3000, 4000};
void setup() {
Serial.begin(9600);
// フラッシュメモリから値を1つずつ読み出して表示
for (int i = 0; i < 4; i++) {
uint16_t value = pgm_read_word(&(myData[i]));
Serial.println(value);
}
}
void loop() {
// 空のループ
}
説明
PROGMEM
キーワードを使って、配列myData[]
をフラッシュメモリに格納しています。pgm_read_word(&(myData[i]))
でフラッシュメモリ上の配列から16ビットデータを読み出しています。- 読み出したデータを
Serial.println()
で表示しています。
4. 実際の用途
pgm_read_word()
は、主に次のような場合に使用されます。
- ルックアップテーブル: センサーデータの補正や、数学的関数の事前計算結果を格納しておく場合に便利です。フラッシュメモリに大きなテーブルを保存し、必要に応じてデータを読み出します。
- 大きな定数データ: 大きなデータセットをSRAMではなく、フラッシュメモリに格納してメモリの節約を図る際に使用します。
例2: ルックアップテーブルの使用例
#include <avr/pgmspace.h>
// サイン波の値をフラッシュメモリに格納
const uint16_t sineWaveTable[] PROGMEM = {
0, 707, 1000, 707, 0, -707, -1000, -707
};
void setup() {
Serial.begin(9600);
// テーブルから値を読み取って表示
for (int i = 0; i < 8; i++) {
uint16_t value = pgm_read_word(&(sineWaveTable[i]));
Serial.println(value);
}
}
void loop() {
// 空のループ
}
この例では、サイン波の値をフラッシュメモリに格納し、pgm_read_word()
を使って読み出しています。このようなルックアップテーブルを使用すると、演算を省略し、効率的に計算結果を使用することができます。
5. 他の pgm_read_*
関数との違い
AVRのフラッシュメモリからデータを読み取るためには、データの型に応じて異なる関数が用意されています。
pgm_read_byte()
: 8ビット(1バイト)データを読み出します。pgm_read_word()
: 16ビット(2バイト)データを読み出します(今回の説明)。pgm_read_dword()
: 32ビット(4バイト)データを読み出します。pgm_read_float()
: 浮動小数点数(float
)を読み出します。
各関数は、格納されたデータの型やサイズに応じて使い分ける必要があります。
6. オーバーフローや型の問題に注意
pgm_read_word()
は 16ビット(2バイト) のデータを読み取ります。読み込む対象が16ビットを超えるサイズの場合、データが正しく読み取れないか、オーバーフローの原因となる可能性があるため、格納するデータの型や読み出す関数を正しく選択する必要があります。
まとめ
pgm_read_word()
は、AVRマイコンのフラッシュメモリから16ビット(2バイト)のデータを読み込む関数です。- フラッシュメモリに格納された定数や配列を効率的に扱い、SRAMの使用を節約するのに役立ちます。
PROGMEM
キーワードと共に使用し、大きなデータセットや定数を扱う場合に便利です。- フラッシュメモリからデータを読み出す際には、データ型に応じた適切な関数を使用することが重要です。
これを利用することで、Arduinoのメモリ効率を最大化し、より大規模なプログラムやデータを扱うことができます。
温湿度センサー(DHT sensor)
環境構築(ライブラリインストール・ライブラリインクルード)

#include <DHT.h>
センサーのデータピントセンサータイプを設定
DHT dht();
は、Arduinoで温湿度センサー DHT シリーズ(DHT11やDHT22など)を使用するためのオブジェクトを宣言するコードです。具体的には、DHTライブラリを使用してセンサーを操作するための インスタンス(オブジェクト) を作成しています。
このコード自体は デフォルトコンストラクタ を呼び出す形式で、通常は後でピン番号とセンサーの種類を指定して、オブジェクトを初期化します。例えば以下のように記述します:
cpp
コードをコピーする
DHT dht(pin, type);
pin
: DHTセンサーが接続されているArduinoのピン番号。type
: センサーの種類(DHT11
やDHT22
など)。
例:
cpp
コードをコピーする
DHT dht(2, DHT11); // DHT11センサーをピン2に接続
その後、dht.begin()
でセンサーを初期化し、dht.readTemperature()
や dht.readHumidity()
でデータを取得します。
DHTセンサーを初期化し、使用可能な状態にする
dht.begin();
は、DHTセンサー(例えばDHT11やDHT22)を使用するための初期化処理を行うメソッドです。このコードを呼び出すことで、DHTセンサーを使用可能な状態にします。setup()
関数内で実行されることが多く、センサーからデータを読み取る前に必ず実行する必要があります。
機能:
- DHTセンサーのデータ送受信ピンやプロトコルの初期化を行います。
dht
オブジェクトを通して、温度や湿度データを取得する準備を整えます。
例:
void setup() {
Serial.begin(9600); // シリアル通信の初期化
dht.begin(); // DHTセンサーの初期化
}
この後、dht.readHumidity()
や dht.readTemperature()
などで、センサーから温度や湿度のデータを取得できます。
温度を読み取る(dht.readTemperature)
dht.readTemperature()
は、DHTセンサー(例:DHT11やDHT22)を使用して温度を読み取るメソッドです。この関数を呼び出すことで、センサーから取得した温度データを浮動小数点数(float
)として返します。デフォルトでは摂氏温度が取得されます。
使い方の例
float temperature = dht.readTemperature();
Serial.print("Temperature: ");
Serial.println(temperature);
この例では、温度が temperature
という変数に保存され、シリアルモニタに表示されます。
特徴
- 摂氏温度がデフォルトで取得されます。
- 華氏温度を取得するには、引数に
true
を渡します:float temperatureF = dht.readTemperature(true);
このように、DHTセンサーから簡単に温度データを取得し、計測に使用できます【1】。
🌐 Sources
- zenn.dev – 電子工作 その18(温湿度センサー:DHT11/DHT22の使い方)
- iot.keicode.com – DHT11 を用いた温度と湿度の計測
- stemship.com – Arduinoベースのセンサノード:Arduinoを使った温度センサ
湿度を読み取る(dht.readHumidity)
dht.readHumidity()
は、DHTセンサー(例:DHT11やDHT22)を使用して 湿度 を取得するメソッドです。この関数は、センサーから読み取った湿度を 浮動小数点数(float
) として返します。通常、相対湿度(%)が取得されます。
使い方の例
float humidity = dht.readHumidity();
Serial.print("Humidity: ");
Serial.println(humidity);
この例では、湿度が humidity
変数に格納され、シリアルモニタに表示されます。センサーからデータを正確に取得するためには、ループ内でデータを読み取る際、約2秒間隔を空ける必要があります。これはDHTセンサーの仕様で、新しいデータが更新されるまで時間がかかるためです【1】。