つれづれなる備忘録

日々の発見をあるがままに綴る

TinkercadによるArduinoシミュレーション23 ~ タイマーICの利用2

1. Arduinoを用いたタイマーICの制御

 今回は前回の555タイマーをArduinoで制御する方法を紹介する。前回紹介したワンショットタイマーにおける起動と時間計測、パルス発振回路の時間計測について取り上げる。 atatat.hatenablog.com

2. ワンショットタイマーの時間計測

 Arduinoを用いてワンショットタイマーを起動し、起動時間(HIGHの持続時間)を計測した結果を表示する。電源(5V)とGNDはArduinoに接続し、また押しボタンによりるトリガー入力の代わりにArduinoの7ピンに接続したのが下図になる。(他は前回と同じ)なお抵抗は9090Ωでコンデンサは100uFに設定しており、タイマーが1秒間起動する。タイマーの出力はLEDと2ピンに接続する。タイマーの出力を外部割込みにして、LOW-HIGHへの割り込みが発生した時間とHIGH-LOWへの割り込みが発生した時間の差分をとることでパルス持続時間を測定する。

ワンショットタイマーの接続
ワンショットタイマーの接続

 スケッチは以下のようにした。setup関数内で7ピンをHIGHにしておき、pulse_in()内でLOW-HIGHを7ピンに出力することでタイマーの開始トリガーを与える。外部割込みの設定はattachInterrupt(0,catch_pulse,CHANGE);とすることで割り込みのタイミングはタイマーが開始するLOW-HIGHへの変化とタイマーが終了するHIGH-LOWへの変化となる。また割り込み時に呼び出すcatch_pulse()ではt0=millis()-t0(t0=0)によりプログラムが実行してから経過した時間を取得しつつ、pulseをインクリメントすることで割り込み数をカウントする。2度目に割り込みが発生したときはt0=mills()-t0において1度目の割り込み時間がt0となっているため、2度目の割り込み時間と1度目の割り込み時間の差分が得られ、それがタイマーの起動時間となる。この方法においては割り込みが2回発生することが前提のためシリアルモニタにはt0と同時pulseを表示している。外部割込みを有効にするinterrupts();から無効にするnoInterrupts();の間の時間はタイマーの起動時間より長くする必要(2倍程度)があり、今回は2秒(2000ms)とした。

int t0=0;
int pulse=0;
void setup()
{
  pinMode(7, OUTPUT);
  digitalWrite(7,HIGH);
  pinMode(2, INPUT_PULLUP);  
  Serial.begin(9600);  
  attachInterrupt(0, catch_pulse, CHANGE);
}

void loop()
{
  t0 = 0;
  pulse=0;
  pulse_in();
  interrupts();
  delay(2000); // パルス持続時間より長くとる(2倍程度)
  noInterrupts();
  Serial.print("Duration: ");
  Serial.println(t0);
  Serial.print("Pulse: ");
  Serial.println(pulse);
}
void catch_pulse(){
  t0=millis()-t0;  
  pulse++;
}
void pulse_in(){ //LOW-HIGHのパルス入力
  digitalWrite(7, LOW);
  delayMicroseconds(10);
  digitalWrite(7, HIGH);
}

Tinkercadでシミュレーションを開始すると開始直後1ループ目では割り込み回数は1回(pluse=1)だが、2ループ目から割り込みが2回発生(pulse=2)し、タイマー起動時間は998msという結果が得られる。

3. パルス発振回路の時間計測

 次にパルス発振回路の時間計測について紹介する。構成は前回と同じで、出力を2ピンに接続するところだけが異なる。抵抗R1=20kΩ,R2=60kΩC=10uFでパルス周波数は1Hz(計算上は0.995HZ)でHIGHの持続時間tHIGH=0.589(ms),LOWの持続時間tLOW=416(ms)となっている。

パルス発振回路の接続
パルス発振回路の接続
パルス発振回路の周期(周波数)を計測するスケッチを以下に示す。ワンショットタイマーとほぼ同じだが、外部割込みのタイミングをHIGH-LOWに変化したときのみを検出するためFALLINGを指定している。あとpulseが2のときのみシリアルモニタに表示するようにしている。

int t0=0;
int pulse=0;
void setup()
{
  pinMode(7, OUTPUT);
  digitalWrite(7,HIGH);
  pinMode(2, INPUT_PULLUP); 
  Serial.begin(9600);  
  attachInterrupt(0, catch_pulse, FALLING);
}

void loop()
{
  t0 = 0;
  pulse=0;
  interrupts();
  delay(2000);
  noInterrupts();
  if(pulse==2){
    Serial.print("Duration: ");
    Serial.println(t0);
    Serial.print("Pulse: ");
    Serial.println(pulse);
  }
}
void catch_pulse(){
  t0=millis()-t0;  
  pulse++;
}

Tinkercadのシミュレーションを実行すると1005-1006(ms)で周波数に直すと0.995Hzとなり計算上の値と一致する。またパルスの持続時間については上のスケッチでattachInterrupt(0,catch_pulse,CHANGE);,delay(1200);に変更して実行すると420(ms),586(ms)という結果が得られた。これはtLOW,tHIGHの計算値とほぼ一致しているが割り込みのタイミングがLOW-HIGHまたはHIGH-LOWの変化のため、パルスHIGHの持続時間かLOW持続時間か区別がつかない。

4. パルス検出関数の利用

 上の例では外部割込み機能を用いてパルスの持続時間を計測したが、組み込みのパルス検出関数pulseIn();を利用する方法もある。ただし、パルス時間が長すぎるとうまく検出できず、Tinkercadでシミュレーションした結果ではパルス周期を1/10程度にする必要があった。そのため上のパルス発振回路でコンデンサの値を10uFから1uFに変更し、tHIGH=0.0589(ms),LOWの持続時間tLOW=0.0416(ms)、f=9.95Hzとした。パルス検出関数pulseIn(pin,value,timeout);の使用方法はpin:ピン番号を指定,value:HIGH(LOW-HIGH)またはLOW(HIGH-LOW)の検出,timeout:タイムアウト時間を指定、デフォルト1秒となっている。検出されたパルス長さはマイクロ秒単位で返ってくる。2ピンをパルス(HIGH)の検出用の端子、3ピンをパルス(LOW)の検出用の端子として接続する。(図は省略)スケッチは以下のようになる。

unsigned long  th=0;
unsigned long  tl=0;
void setup()
{
  pinMode(2, INPUT_PULLUP);  
  pinMode(3, INPUT_PULLUP);
  Serial.begin(9600);    
}

void loop()
{
  delay(500);
  th=pulseIn(2,HIGH);//パルス(HIGH)検出
  tl=pulseIn(3,LOW);//パルス(LOW)検出
  Serial.print("Duration th: ");
  Serial.println(th);
  Serial.print("Duration tl: ");
  Serial.println(tl);
  Serial.print("Pulse Period: ");
  Serial.println(tl+th);
}

 Tinkercadのシミュレーションを実行するとtHIGH=61820(us)=0.0618(ms),tLOW=44322(us)=0.0443(ms), 周期は106142(us)でf=9.42(Hz)となる。おおよそとしては合っているとは思うが、計算値や外部割込みと比較して若干値が異なっている原因分析が必要。

5. まとめ

 今回はArduinoと組み合わせて555タイマーの制御やパルス持続時間の時間計測の方法を、主に外部割込み機能を中心に紹介した。