前回、ホールセンサの仕組みや簡単な使い方について学びました。今回はそのホールセンサを使って、自転車などで使える簡易速度計を作ってみたいと思います。
今回の電子工作レシピ
完成までの時間目安:60分
必要なパーツ
- Arduino本体(Arduino UNO R3)https://www.switch-science.com/catalog/789/
- ロームセンサ評価キット http://www.rohm.co.jp/web/japan/sensor-shield-support
- 3桁7セグメントLED(LB-303MK) http://www.marutsu.co.jp/pc/i/15317/
- 8ビットシフトレジスタ(SN74HC595N) http://akizukidenshi.com/catalog/g/gI-08605/
- 抵抗器(220Ω) ×3
目次
- 簡易速度計の仕様を考える
- 7セグメントLEDのおさらい~シフトレジスタの使い方
- 簡易速度計のプログラム
- まとめ
1.簡易速度計の仕様を考える
まずはじめに速度計の仕様を考えてみます。自転車に設置することを例として考えてみると、前輪もしくは後輪どちらかのタイヤのフレームにホールセンサを取り付け、タイヤ側には磁石を取り付けます。こうすることで、タイヤが回った際に磁石がホールセンサと近づいて1回転が計測される、という仕組みにします。このとき、磁石とホールセンサの距離は実際にArduinoのシリアルモニタなどの表示結果を見ながら調整するようにしてください。続いて、Arduinoとセンサ評価キット本体は7セグLEDに表記される速度を確認しながら走行できるようにするため、自転車のハンドル付近に設置できるようにします。
ざっとやりたいことの想定としてはこのようなところでしょうか。

図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の表示回路
今回利用するシフトレジスタはSN74HC595Nという8ビットシフトレジスタです。8ビットというのは単純に8本出力が可能になると考えてください。

写真1 8ビットシフトレジスタ(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のつなぎ方
実際の回路は下記となります。7セグLEDの配線はいつも多くなって少しわかりにくいのですが、Arduinoで利用しているピン数が少なくなっているのがわかると思います。

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

写真2 7セグLEDとシフトレジスタ(写真では少し配線を変えています)
下記のプログラムでは、シフトレジスタの8ビットのデータを1から128まで全て送信してみるテストプログラムです。実際に動かすと、順番に7セグLEDの対応する部分が光るのが確認できます。
プログラム – シフトレジスタのテストプログラム
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | //シフトレジスタ用 #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に表示するような仕組みになっています。
プログラム – 簡易速度計のプログラム
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | #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円均一で購入してきた強力マグネットを自転車の後輪に取り付け(タイヤのフレームが金属なのでそのままくっつきました)、マグネットとセンサが近接するように、固定します。マグネットとセンサの距離の調整が少し必要なので養生テープでセンサを固定しています。
センサの固定が完了したら実際にタイヤを回してセンサが反応するか試します。回転を早めれば表示される数値が変わるのが確認できました!
ホールセンサによる簡易速度計まとめ
今回、ホールセンサを使って簡易速度計を作成しました。センサ評価キットのセンサを使う場合でも、そうでない場合でも、デバイスを作りこんでいくとArduinoのピン数が少ないと思うケースが多々出てきます。そのようなときは、シフトレジスタを使うなど工夫をすることで、より拡張性の高いデバイスを作成することができます。次回はセンサ評価キットの残りのセンサについて引き続き取り上げてみたいと思います!