Arduino 入門
番外編 21
【pulseIn関数 まとめ】
こんにちは管理人のomoroyaです。
arduino 入門 番外編はarduinoの基本的なことを解説している記事です。
本記事は、Arduinoで使用するpulseIn関数についてです。
入門編、番外編では、超音波センサの距離測定に使用した関数。
まあ、まあ使う関数かなということで備忘録のためまとめます。
pulseIn関数はパルス幅を測定する関数です。
pinに入力されるパルス幅を測定できます。
パルスはHighでもLowでもどちらでも測定可能。
HighとLowのパルス幅を測定できることから、それほど速くない周波数なら周期の測定もこの関数で可能。
Arduinoの公式HPでは「経験上、10マイクロ秒から3分」との記述があります。
あるサイトで精度を検証されていましたが、1%程度は誤差がある。
パルス幅に関しては、100us以上であれば精度よく測定可能ということでした。
※100us以下は急激に測定精度が悪化
周波数で考えると~5KHz程度が限界(duty:50%)と考えておくのがよいようです。
ファンクションジェネレータが手元にあれば精度検証ができるのですが、手元になく。。。
当然、Arduinoよりも精度の高いパルスジェネレータでないと意味がありません。
用意ができたら、精度の検証を管理人もやってみたいと思います。
どんなときに使うのか?
入門編では超音波センサで使用しました。
使い道としては、一番わかりやすい使い道となります。
管理人はプログラマーの専門家というわけではありません。
気が向いたときにテキストを開き、ネットを調べ自己学習。
管理人にとってはブログ記事が自己学習のノートです。
書くことによって頭の中が整理できる。
arduino自身のこと、スケッチ(コード、プログラム)を少しづつ理解して行きましょう。
いやいや、arduinoを早速始めたいんだ!というかたは下記の入門編からお読みください。
Arduino入門編の解説にて使用しているArduinoは互換品です。
互換品とは言え、Arduinoはオープンソースであり複製して販売するのもライセンス的に問題なし。
そのため互換品の品質も悪くなく、それでいて値段は安いです。
正規品本体の値段程度で豊富な部品が多数ついています。
正規品(Arduino UNO R3)の本体単品がほしい方はこちらとなります。
Arduino入門編2では「Arduino UNO R4 Minima」「Arduino UNO R4 WIFI」にて遊ぶため今のところは正規品を使用。(まだ互換品が・・・ほぼない)
pulseIn関数 基本解説
まずは基本的なことを復習。
繰り返しになりますが、「パルス幅を測定する」ための関数です。
余談ですが・・・
pulseIn関数の時間測定は「micros()」で測定しています。
公式に記載のあるpulseIn関数の「経験上、10マイクロ秒から3分」との記載。
これで納得できるわけです。
公式リファレンスはこちら
https://www.arduino.cc/reference/en/language/functions/advanced-io/pulsein/
コマンド | 説明 |
---|---|
pulseIn(pin, value, timeout) | pinに入力されたパルス幅の読み取り pin: パルスを入力するピンの番号 value: 測定するパルスの種類(HIGH / LOW) timeout: タイムアウトまでの時間 ・省略可 ・単位:マイクロ秒 ・デフォルト:1秒 (unsigned long) 例 パルスがHighになっている期間を取得する。 pulseIn(pin,HIGH); |
pulseIn関数 サンプルスケッチ
シリアルモニタに測定したパルス幅を表示するスケッチとなります。
analogWrite関数を利用すれば、簡単にパルスを生成できますのでこちらを利用。
スケッチに通信用の関数を使いますので念のため説明をのせておきます。
関数 | 説明 |
---|---|
Serial.begin(speed) | シリアル通信のデータ転送レートをbpsを指定します。 bpsはビット/秒。 speed:転送レート 転送レートは下記が指定可能です。 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 戻り値:なし |
Serial.available() | シリアルポートにデータがあるかどうかの確認をする。 戻り値:シリアルバッファにあるデータのバイト数 |
Serial.read() | 受信データの読み込み。 戻り値: 読み込み可能なデータの最初の1バイトを返す。 -1の場合はデータなし。 |
Serial.print(data,format) | ASCIIテキストでシリアルポートにデータを出力する。 data:出力する値 format:基数または有効桁数(BIN,DEC・・・など) 戻り値:送信したバイト数 |
Serial.println(data,format) | データの末尾に改行を入れて送信。 Serial.print()と同じフォーマットが使えます。 |
流れとしては以下。
- analogWrite関数でPWMを出力
- pulseIn関数でパルス幅を測定
- 値は、シリアルモニタで確認
Dutyは数値で入力し、途中で簡単に変えられるようにしておきました。
//番外編 21 pulseIn関数 //pulseIn関数をシリアルモニタで理解するサンプルスケッチ //https://omoroya.com/ const int pin_pwm = 3; //PWM出力ピン const int pin_pul = 11; //パルス幅測定ピン int val_duty = 50; //初期値のDuty設定 int val_pwm; //duty計算用の変数 int val_hpul, val_lpul; //H,Lパルス幅格納変数 float val_frq; //周波数格納変数 void setup() { pinMode(pin_pwm, OUTPUT); //PMW設定ピンをOUTPUT指定 pinMode(pin_pul, INPUT); //パルス幅測定ピンをINPUT指定 Serial.begin(9600); //シリアル通信のデータ転送レート設定しポート開放 Serial.println("set Duty = 50%"); //デフォルト表示 } void loop() { if (Serial.available() > 0 ) //受信したデータが存在した場合以下を実行 { val_duty = Serial.parseInt(); //文字列データを数値に変換 Serial.print("set Duty = "); //表示 Serial.print(val_duty , DEC); //セットしたdutyを表示 Serial.println("%"); //表示 } val_pwm = 255*val_duty/100; //dutyからPWM値計算 analogWrite(pin_pwm, val_pwm); //PWM出力 val_hpul = pulseIn(pin_pul, HIGH); //Hパルス幅測定 val_lpul = pulseIn(pin_pul, LOW); //Lパルス幅測定 val_frq = 1 / (val_hpul*1e-6 + val_lpul*1e-6); //周波数計算 Serial.print(val_hpul); //Hパルス表示 Serial.print("us / "); //単位表示 Serial.print(val_lpul); //Lパルス表示 Serial.print("us / "); //単位表示 Serial.print(val_frq); //周波数表示 Serial.println("Hz"); //単位表示 delay(1000); //表示時間調整 }
pulseIn関数 サンプルスケッチ 実行結果
まずは、Aruduinoへスケッチを書き込んでください。
書き込み後、3番ピンと11番ピンを接続。
「ツール」 ⇒ 「シリアルモニタ」 を開きます。
Dutyのデフォルトは50%にしてあります。
あとは、「1 ~ 99」で好きな数値を入力して変化を確認してください。
下図がシリアルモニタの実行結果。
シリアルモニタは「改行なし」を選択してください。
改行なしを選択しないと改行も入力値として認識してしまいます。
50% → 25% → 75% → 1% → 99%と変えた結果。
3番ピンを使用した場合のPWM周波数は「490Hz」。
測定結果も約490Hzとなっており、周波数が測定できていることがわかります。
また、入力したDutyに応じて、H、Lのパルス幅も変わっていることが確認できます。
シリアルモニタの結果からpulseIn関数でパルス幅を測定できていることがわかります。
まとめ
「Arduino 入門 番外編 21 【pulseIn関数 まとめ】」
何気なしに使っている関数。
あらためて、Arduinoを使って関数を一つ一つ理解するのも学習にはもってこい。
まずは、基本を理解して応用してみましょう。
次回の「番外編 22」は【IOピン ポート・レジスタ まとめ】です。
最後に
疑問点、質問などありましたら気軽にコメントください。
この電子部品の解説をしてほしい!などなどなんでもOKです。
リンク切れ、間違いなどあればコメントいただけると助かります。
Arduino入門編、番外編、お役立ち情報などなどサイトマップで記事一覧をぜひご確認ください。
Arduino入門編、Arduino入門編2で使用しているUNOはAmazonにて購入可能です。
Arduino入門編では互換品を使用。
Arduinoはオープンソース。
複製して販売するのもライセンス的に問題なし。
そのため互換品の品質も悪くなく、それでいて値段は安いです。
正規品本体の値段程度で豊富な部品が多数ついています。
学習用、遊び用、お試し用には安価な互換品がおすすめです。
ELEGOO UNO キット レベルアップ チュートリアル付 uno mega2560 r3 nanoと互換 Arduino用
上記のものでも十分に多数の部品が入っていますが、最初からもっと多数の部品が入っているこちらもお勧めです。
Arduino入門編2では「Arduino UNO R4 Minima」「Arduino UNO R4 WIFI」にて遊ぶため今のところは正規品を使用。(まだ互換品が・・・ほぼない)
Amazonでお得に買う方法
Amazonでお得に購入するならAmazon Mastercard、Amazonギフト券がおすすめです。
時期により異なりますが、様々なキャンペーンを実施しています。
\Amazonギフト券/
Amazonギフトカード キャンペーン
\Amazon Mastercard お申込み/
Amazon Mastercard 申し込み
いずれの場合もプライム会員である方がお得!!
\Amazon Prime 30日間の無料会員を試す/
無料会員登録
コメント
digitalWriteとdelay関数の組み合わせと、analogWriteではpulseInが働くタイミングが変わってくるんですね。delay関数について理解が足りておりませんでした。
この手の情報はネットで探してもあまり見つからなかったので困っておりましたが、おかげさまで理解できました。ありがとうございました。
コメントありがとうございます。
お役に立てたのであれば、うれしいです。
また、何かありましたらコメントよろしくお願いいたします。
初めまして、現在、超音波を使用して距離センサーを自作しております。
Arduinoを使ってパルスを発生させることについて質問がございましてコメントさせていただきました。
前に、pulseInのコードの動作を確認するために、digitalWriteとdelayでパルスを作成し、これを別のピンに入力、pulseInでパルス幅を計測しようとしておりました。しかし、シリアルモニターにはゼロしか出力されませんでした。
お聞きしたいのは、ゼロしか出力されない理由です。もし、この原因についてご存知でしたら、ご教授いただけないでしょうか?
void loop内のコードは下記の通りです。
digitalWrite(13, HIGH); //13ピンが出力
delayMicroseconds(50);
digitalWrite(13, LOW);
durationTime = pulseIn(12, HIGH); //12ピンが入力
Serial.println(durationTime);
原因がわからず、ネットで調べていたところこちらの記事にたどり着きました。記事に記載されている通り、digitalWriteではなく、analogWriteを使用して、パルスを発生させたところ、pulseInでパルス幅を計測することができました。digitalWriteで作ったパルスと、analogWriteで作ったパルスとでは何かが異なるのでしょうか?
以上、よろしくお願い申し上げます。
コメントありがとうございます。
delayMicroseconds関数はプログラムを指定した時間だけ一時停止する関数となっています。
delay関数を使用している間はArduinoは何もすることができません。
※Arduinoは逐次処理です。
記載のスケッチでは
13番ピンをHにする → 50us秒停止 → 13番ピンをLにする → パルス幅測定
となり、パルス幅測定時は13番ピンはLでありpulseIn関数が遷移を認識できず測定することはできません。
digitalWriteとdelay関数の組み合わせでは、LからH、HからLへの切り替わりをpulseIn関数が認識できないということです。