はじめての電子工作超入門

第45回 ホールセンサで自転車などで使える簡易速度計を作ってみる 〜Arduino+センサの開発が劇的に楽になる!ローム・センサ評価キットを試してみた

vol45-1

前回、ホールセンサの仕組みや簡単な使い方について学びました。今回はそのホールセンサを使って、自転車などで使える簡易速度計を作ってみたいと思います。

今回の電子工作レシピ

完成までの時間目安:60分
必要なパーツ

※ロームセンサ評価キットは下記サイトから購入できます!
チップワンストップ
ザイコストア

目次

  1. 簡易速度計の仕様を考える
  2. 7セグメントLEDのおさらい~シフトレジスタの使い方
  3. 簡易速度計のプログラム
  4. まとめ

1.簡易速度計の仕様を考える

まずはじめに速度計の仕様を考えてみます。自転車に設置することを例として考えてみると、前輪もしくは後輪どちらかのタイヤのフレームにホールセンサを取り付け、タイヤ側には磁石を取り付けます。こうすることで、タイヤが回った際に磁石がホールセンサと近づいて1回転が計測される、という仕組みにします。このとき、磁石とホールセンサの距離は実際にArduinoのシリアルモニタなどの表示結果を見ながら調整するようにしてください。続いて、Arduinoとセンサ評価キット本体は7セグLEDに表記される速度を確認しながら走行できるようにするため、自転車のハンドル付近に設置できるようにします。

ざっとやりたいことの想定としてはこのようなところでしょうか。

図1 速度計の仕様

図1 速度計の仕様

 

2.7セグメントLEDのおさらい~シフトレジスタの使い方

今回速度表示をするために、7セグLEDを利用します。7セグLEDの使い方については第8回 「Arduinoで作る簡易百葉箱(その2)。電光掲示板(7セグメントLED)を使って数値を表示」で取り扱っていますが、今回もっと手軽に利用できる方法として、シフトレジスタを使って7セグLEDの表示をします。

シフトレジスタってなに?

シフトレジスタを簡単に説明すると、Arduinoのピン数を増やすことができるICチップです。たとえば第8回の7セグLEDを表示する回路では7セグLEDのそれぞれのLEDを光らせるためにArduino側も1本ずつピンを利用していることがわかりますね。この場合だと、残りのデジタルピンは0,1,9,10,12と少なくなってしまい他に拡張したい場合はかなり窮屈な思いをしながら開発をしなければいけません。そのようなケースでシフトレジスタの出番となります。

図2 第8回より7セグLEDの表示回路

図2 第8回より7セグLEDの表示回路

 

今回利用するシフトレジスタはSN74HC595Nという8ビットシフトレジスタです。8ビットというのは単純に8本出力が可能になると考えてください。

 

写真2 8ビットシフトレジスタ(SN74HC595N)

写真1 8ビットシフトレジスタ(SN74HC595N)

 

シフトレジスタの仕組み

データシートを見ながら使い方を確認します。

SN74HC595N – データシート

図3 SN74HC595Nの端子説明

図3 SN74HC595Nの端子説明

Arduinoで利用する場合、赤色がついたSER、RCLK、SRCLKの端子に対してArduinoから特定の信号を送ると、QA~QHから信号に応じた出力が発信される、という仕組みになっています。詳細なデータの流れとしては、QA~QHに出力したい信号をArduinoからSER端子に対して8ビット中の1ビット目(MSB/LSBで変わる)にデータを入力(HIGH or LOW)、SRCLK端子にHIGH信号を送って8ビット中2ビット目に移動~これを8ビット全てに繰り返しデータの入力が完了した段階で、RCLKをHIGHにするとQA~QHからデータが出力される、という仕組みになっています。

この流れを全てArduinoのプログラムで実装して制御するにはかなり面倒な話なので、ArduinoにはshiftOut()という関数が用意されています。この関数を利用することで手軽にシフトレジスタを使うことができるようになっています。

shiftOut(dataPin, clockPin, bitOrder, value)

  • dataPin – SER信号ピン
  • clockPin – SRLK信号ピン
  • bitOrder –  「MSBFIRST」(最上位ビットから送信)または「LSBFIRST」(最下位ビットから送信)のどちらか指定
  • value – 送信したいデータ

 

シフトレジスタを利用して、Arduinoから7セグLEDのそれぞれのLEDを表示させる「01000111」などデータを送り任意の数字を7セグLEDに表示させましょう。具体的には図4のように、シフトレジスタのQA~QHの出力端子が、7セグLEDのa~g,D.Pに対応するように接続すると、とてもわかりやすいです。valueが「01000111」というデータの場合、シフトレジスタから7セグLEDに対しては「0-QH / 1-QG / 0-QF /0-QE,0-QD,1-QC,1-QB,1-QA」というデータが実際に送られ、7セグLEDがそれに基づいて表示される、となります。

 

図4 シフトレジスタと7セグLEDのつなぎ方

図4 シフトレジスタと7セグLEDのつなぎ方

実際の回路は下記となります。7セグLEDの配線はいつも多くなって少しわかりにくいのですが、Arduinoで利用しているピン数が少なくなっているのがわかると思います。

 

図5 シフトレジスタと7セグLEDの回路

図5 シフトレジスタと7セグLEDの回路

 

写真2 7セグLEDとシフトレジスタ

写真2 7セグLEDとシフトレジスタ(写真では少し配線を変えています)

 

下記のプログラムでは、シフトレジスタの8ビットのデータを1から128まで全て送信してみるテストプログラムです。実際に動かすと、順番に7セグLEDの対応する部分が光るのが確認できます。

プログラム – シフトレジスタのテストプログラム

//シフトレジスタ用
#define SCK_PIN 13
#define RCK_PIN 10
#define SI_PIN  11
#define DP1 2
#define DP2 3
#define DP3 4

void setup(){
     pinMode(SCK_PIN, OUTPUT);
     pinMode(RCK_PIN, OUTPUT);
     pinMode(SI_PIN,  OUTPUT);
     pinMode(DP1,  OUTPUT);
     pinMode(DP2,  OUTPUT);
     pinMode(DP3,  OUTPUT);
}

void loop() {  
  digitalWrite(DP1, HIGH);  //1桁目は表示させない
  digitalWrite(DP2, HIGH);  //2桁目は表示させない
  digitalWrite(DP3, LOW);  //3桁目を表示させる

  //シフトレジスタの8ビット信号を順に送る(1,0の2パターンのデータが8桁 =>; 2の8乗 = 128)
  for(int i = 0; i < 128; i++){
    SEGMENT_OUT(i);
  }
}

void SEGMENT_OUT(int num){
    digitalWrite(RCK_PIN, LOW);
    shiftOut(SI_PIN, SCK_PIN, MSBFIRST, num);
    digitalWrite(RCK_PIN, HIGH);
    delay(20);
}

3.ホールセンサによる簡易速度計のプログラム

シフトレジスタの使い方および7セグLEDのおさらいが完了したところで、実際に速度計のプログラムを設計していきます。具体的なプログラムの流れとしては、一定間隔(今回は1秒間)で取得した回転数をもとに、時速を算出するようなプログラムとなります。たとえば1回転あたり、0.5m進むタイヤの場合、1秒間で2回計測された場合0.5m×2回 = 1m進んだことになりますね。それを1時間あたりで計算したときの時速を算出します。

プログラムのポイントとしては、7セグLEDに関してはこれまでも扱ったように、短い時間で1~3桁目を切り替えて表示することで、3桁表示を実現していることと、millis()関数が処理されたタイミングの時間を取得して、一定時間毎に速度を計算して7セグLEDに表示するような仕組みになっています。

 

プログラム – 簡易速度計のプログラム

#include <BD7411.h>

long _beforetime = 0;

//センサ用
int _hallout_pin = 0; // use D0 pin
int _cnt = 0;
bool _flg = false;
unsigned long _starttime = 0;
BD7411 bd7411;

//シフトレジスタ用
#define SCK_PIN 13
#define RCK_PIN 10
#define SI_PIN  11

//桁制御用
#define DP1 2
#define DP2 3
#define DP3 4

//
float _meter  = 1;  //1回転あたりの距離数(m)
float _speedVal  = 0;


//7セグLEDの数字配列
const int digits[10] = {
  0b00111111, // 0
  0b00000110, // 1
  0b01011011, // 2
  0b01001111, // 3
  0b01100110, // 4
  0b01101101, // 5
  0b01111101, // 6
  0b00100111, // 7
  0b01111111, // 8
  0b01101111, // 9
};

void setup(){
  Serial.begin(9600);
  while (!Serial);
  bd7411.init(_hallout_pin);

  pinMode(SCK_PIN, OUTPUT); 
  pinMode(RCK_PIN, OUTPUT);
  pinMode(SI_PIN,  OUTPUT);
  pinMode(DP1,  OUTPUT);
  pinMode(DP2,  OUTPUT);
  pinMode(DP3,  OUTPUT);
  
  _beforetime = millis();
}

void loop() {
  int hallout;

  hallout = bd7411.readoutpin();
  if (hallout == 0 && _flg == false) {
    if(_starttime == 0){
      _starttime = millis();
    }
    Serial.print("BD7411G Magnet field Detect! - ");
    _flg  = true;
    _cnt++;
    Serial.print(hallout);    
    Serial.print("-");    
    Serial.println(_cnt);
  }
  else{
    _flg  = false;
  }


  //前回の点滅からの経過時間(1秒)を超えると速度を更新
  if (millis() - _beforetime > 1000) {
    _beforetime = millis();
    //速度を計算して7セグLEDに表示
    float sp  = _meter * _cnt * 60*60 / 1000;  //速度 = 距離(_meter*_cnt) ÷ 時間(60秒×60分) / 1000(メーター単位にするため)
    _speedVal  = sp * 10;
    Serial.print("SPEED:");    
    Serial.println(_speedVal);
    _cnt  = 0;
  }
  SEGMENT_OUT((int)_speedVal);
  delay(1);
}

void SEGMENT_OUT(int num){
  for(int i = 0; i < 3; i++){
    int disp_num  = 0;
    int dots      = 0;
    //1桁目の処理
    if(i==0){
      disp_num = NumParse(num,1);
      digitalWrite(DP1, LOW);
      digitalWrite(DP2, HIGH);
      digitalWrite(DP3, HIGH);
    }
    //2桁目の処理
    else if(i==1){
      dots  =  0b10000000;
      disp_num  = NumParse(num,2);
      digitalWrite(DP2, LOW);
      digitalWrite(DP1, HIGH);
      digitalWrite(DP3, HIGH);
    }
    //3桁目の処理
    else if(i==2){
      disp_num  = NumParse(num,3);
      digitalWrite(DP3, LOW);    
      digitalWrite(DP1, HIGH);    
      digitalWrite(DP2, HIGH);    
    }

    digitalWrite(RCK_PIN, LOW);
    shiftOut(SI_PIN, SCK_PIN, MSBFIRST, digits[disp_num]+dots);
    digitalWrite(RCK_PIN, HIGH);
    delay(3);
  }
}


//3桁をそれぞれの桁で分解する関数
int NumParse(int Number,int s){
  int val[3];
  val[0] = (Number % 10); Number /= 10; // 1桁目を取り出す
  val[1] = (Number % 10); Number /= 10; // 2桁目を取り出す
  val[2] = (Number % 10); Number /= 10; // 3桁目を取り出す
  return val[s-1];
}

 

マグネットを近づけたり離したりすると、それに応じて速度が更新されているのがわかりますね。

 

自転車につけてみる

準備ができたので、実際に自転車につけてみます。今回、100円均一で購入してきた強力マグネットを自転車の後輪に取り付け(タイヤのフレームが金属なのでそのままくっつきました)、マグネットとセンサが近接するように、固定します。マグネットとセンサの距離の調整が少し必要なので養生テープでセンサを固定しています。

2016-06-16 15.342
 
センサの固定が完了したら実際にタイヤを回してセンサが反応するか試します。回転を早めれば表示される数値が変わるのが確認できました!
 

 
 

ホールセンサによる簡易速度計まとめ

今回、ホールセンサを使って簡易速度計を作成しました。センサ評価キットのセンサを使う場合でも、そうでない場合でも、デバイスを作りこんでいくとArduinoのピン数が少ないと思うケースが多々出てきます。そのようなときは、シフトレジスタを使うなど工夫をすることで、より拡張性の高いデバイスを作成することができます。次回はセンサ評価キットの残りのセンサについて引き続き取り上げてみたいと思います!

電子工作マニュアルVol.5
赤川シホロ

電子工作や新しいデバイスをこよなく愛するエンジニア。日常生活のちょっとしたことを電子工作で作って試して、おもしろく過ごしたいと日々考えています。