以前購入して放置していた超音波距離センサーモジュール HC-SR04を使って
実用として使える(?)簡易距離測定器を製作しました。

上の写真がHC-SR04です。使い方は簡単でスイッチサイエンスさん商品紹介ページに
原理とサンプルソースが掲載されています。
製作
まずはArduino UNOでプロトタイプを作成し動作確認後にATmega328に
置き換えました。測定結果は4桁7セグLEDで表示させます。
Arduino IDEでATmega328のプログラミングを行う環境は、
kosakalabさんのHPの「Arduino IDEでATtiny他の開発(AVRISP編)」の記事を
参考にしました。ただし書込みはUSBaspを使ってます。

回路的にはこんな感じです。

4桁7セグLEDとMAX7219のピン割り付け

これを基板に実装してモジュール化しました。
4桁7セグとCPUは別々にモジュールして別のものに利用出来るように工夫してみました。
4桁7セグはMAX7219を使って3本の信号線と電源2本で接続します。

CPUモジュールは、こんな感じでピン端子、ISP端子、電源端子を付けただけです。
内部クロック8MHzで利用します。

プログラムの書き込みはこんな感じでUSBaspをつなげてやります。

これらをつなげて動作確認後、

強引にケースに詰め込んで完成しました。

う~ん、ダサい。もっとかっこよいデジタルアイテムをイメージしたのですが...
ケースのスイッチ類は電源ボタンと測定ボタン(プッシュボタン)です。
測定ボタンを長押しすることで、リアルタイム計測とワンショット計測の切り替えが
出来ます。ワンショット計測時は測定ボタンを押す都度計測します。
そこそこの精度は出ます。測定範囲は2cm~400cm位です。
取りあえず、ケースは作り直します。
プログラムはこんな感じです。
#include "LedControl.h"
#define trigPin 8
#define echoPin 9
#define swPin 5
#define DISP_ERROR -3 // 測定エラー
#define DISP_MODE_LOOP -2 // リアルタイム計測モード表示
#define DISP_MODE_ONE -1 // ワンショット計測モード表示
boolean flgRealTime = false; // リアルタイム測定モードフラグ
// 初期状態はワンショット計測モード
// LED7セグ表示用
LedControl lc=LedControl(2,4,3,1); // DIN,CLK,LOAD
void setup() {
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(swPin, INPUT_PULLUP);
lc.shutdown(0,false);
lc.setIntensity(0,10);
lc.setScanLimit(0,3);
lc.clearDisplay(0);
dispLed(DISP_MODE_ONE);
}
// LED7セグに数値表示
void dispLed(float val) {
char str[10];
byte clm =0;
byte digit = 0;
boolean flgdp = false;
byte i=0;
char v;
if (val == DISP_MODE_LOOP) {
lc.setChar(0,0,'L',false);
lc.setChar(0,1,'0',false);
lc.setChar(0,2,'0',false);
lc.setChar(0,3,'P',false);
return;
}
if (val == DISP_MODE_ONE) {
lc.setChar(0,0,'-',false);
lc.setChar(0,1,'-',false);
lc.setChar(0,2,'-',false);
lc.setChar(0,3,'-',false);
return;
}
if (val == DISP_ERROR) {
lc.setChar(0,0,' ',false);
lc.setChar(0,1,' ',false);
lc.setChar(0,2,' ',false);
lc.setChar(0,3,'E',true);
return;
}
val = val+0.05;
int v1 = val;
int v2 = val*10 - v1*10;
sprintf(str,"%3d.%1d",v1,v2);
while(true) {
if (str[i] == '\0') {
break;
}
v = str[i];
if (str[i+1] == '.') {
flgdp = true;
i++;
} else {
flgdp = false;
}
lc.setChar(0,clm,v,flgdp);
i++;
clm++;
}
}
// 距離の計測
void getDistance() {
float duration,distance;
digitalWrite(trigPin, HIGH);
delayMicroseconds(2);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = (duration/2) / 29.1;
if (distance >= 500 || distance <= 0){
dispLed(DISP_ERROR);
}
else {
dispLed(distance);
}
}
void loop() {
boolean sw;
if (flgRealTime) {
// リアルタイム計測表示
getDistance();
delay(500);
}
// スイッチボタンの操作
if (digitalRead(swPin) == LOW ) {
sw = true;
// 3秒間押しっぱなしチェック
for (int i= 0; i < 30;i++) {
if (digitalRead(swPin) == HIGH) {
sw = false;
break;
}
delay(100);
}
if (sw) {
// 3秒間押したままならモードを変更する
flgRealTime = (flgRealTime == true) ? false:true;
if (flgRealTime) {
// リアルタイム計測モードに移行
dispLed(DISP_MODE_LOOP);
} else {
// ワンショット計測モードに移行
dispLed(DISP_MODE_ONE);
}
while(digitalRead(swPin) == LOW);
} else {
if (flgRealTime == false) {
// ワンショット計測
getDistance();
}
}
}
delay(100);
}
最近のコメント