2019年7月27日土曜日

Arduinoでus(マイクロ秒)間隔のパルスを作る方法


背景

loopでdelayMicroseconds関数を利用してパルスを作っていたところ、同時に別のタスクもさせたくなったので、loopの外部でパルスを作る方法を探してみました。
いくつか実現方法が分かったので、備忘録を兼ねて方法を共有します。

使ったもの

  • ArduinoIDEかPlatformIOをインストールしたPC
  • ProMicro
    Arduino Leonardoの互換機です。

Arduinoで作るもの

GPIO5から200usの間隔(400us周期、2500Hz)でHighとLowを繰り返す信号を作ります。


波形の確認にはAnalogDiscovery2を利用しました。


方法1: loopでdelayMicrosecondsを利用

loopの処理を専有してしまいますが、delayMicrosecondsを利用することで200us周期のパルスを作れます。

#include <Arduino.h>

#define OUTPUT_PIN 5

void setup() {
  pinMode(OUTPUT_PIN, OUTPUT);
}

unsigned long waitMicroSec = 200;

void loop() {
  digitalWrite(OUTPUT_PIN, HIGH);
  delayMicroseconds(waitMicroSec);
  digitalWrite(OUTPUT_PIN, LOW);
  delayMicroseconds(waitMicroSec);
}

AnalogDiscoveryで確認すると、約210usの間隔で信号が変わることを確認できました。
digitalWriteやloopの繰り返し処理により、delayMicrosecondsの他に約10usの遅延が発生してしまうようです。


方法2: Toneを利用

Toneとは周波数を指定して音を出すための関数です。
これに周波数を渡すことで、欲しい周期のパルスを作れます。
今回は200us周期が欲しいので、(1/0.0002)/2 = 2500HzをToneで作ります。

#include <Arduino.h>

#define OUTPUT_PIN 5

void setup() {
  tone(OUTPUT_PIN, 2500); // (1(1sec) / 0.0002(200us)) / 2 = 2500Hz
}

void loop() {
  delay(1000);
}

AnalogDiscoveryで確認すると、約205usの間隔で信号が変わることを確認できました。
Toneは間隔が長くなる形で誤差が発生するようです。



方法3: FlexiTimer2を利用

FlexiTimer2とはTimerの割り込みを設定できるライブラリです。

外部のライブラリなので、開発環境へのインストールが必要です。

Arduinoの場合の設定方法

zipファイルをダウンロード・展開してArduinoのライブラリディレクトリに配置してください。
(勝手が分からない場合は「Arduino ライブラリ zip 配置」とかで検索すると、やり方が出てくると思います。)

zipファイルはgithubのリリースページのzipをクリックするとダウンロードできます。


PlatformIOの場合の設定方法

platformio.iniに「lib_deps = FlexiTimer2」を記述してください。
platformio.ini
lib_deps = FlexiTimer2

プログラムと実行結果

200us毎の割り込みで信号線のHighとLowを繰り返すことで、200us周期のパルスを作れます。

#include <Arduino.h>
#include <FlexiTimer2.h>

#define OUTPUT_PIN 5

void flash() {
  static boolean pinState = true;
  pinState = !pinState;
  digitalWrite(OUTPUT_PIN, pinState);
}

void setup() {
  pinMode(OUTPUT_PIN, OUTPUT);
  FlexiTimer2::set(2, 1.0/10000, flash);
  FlexiTimer2::start();
}

void loop() {
  delay(1000);
}

AnalogDiscoveryで確認すると、約190us周期で信号が出ていることを確認できました。
タイマー割り込みなので数usの誤差で信号を出せても良い気がしますが、約-10usの誤差がありました。
「FlexiTimer2::set(2, 1.0/10000, flash)」の割り算の誤差によるものと自分は推測します。


まとめ

実装方法によって約5%があるようですが、いくつかの方法で200us間隔でHighとLowを切り替える信号を作れました。

ToneやTimer割り込みを使えばloopの処理を専有すること無く欲しい長さのパルスを作れるので、パルス波を作りつつ他の処理を行うプログラムが書けます。
このような書き方をするために調べていたので、狙い通りの方法が見つかって嬉しいです。

後日、パルスを読み取る方法も調べて実装してみました。
良かったらこちらも見てみてください。
Arduinoでパルスを読み取る方法

参考

タイマー割り込みでLEDを点滅させます

変更履歴

2019.08.03
Arduinoでパルスを読み取る方法」をまとめで紹介しました。
2019.11.29
platformioの設定ファイルを「platformio.ino」と間違えていたので、「platformio.ini」 に修正しました。

0 件のコメント :