좌충우돌? 초음파센서(HC-SR04)를 이용한 물탱크 수위 측정기 만들기를 적어 본다.
사람은 도구를 사용해서 동물과 다르다 했던가..
필요에 의해 찾고 그래서 공부하고 그래서.. 힘들게 결과가 나왔다.
처음 초음파센서를 이용한 물탱크 수위 측정기의 필요성을 가졌을 때, 광란의 구글링..을 하여 다음의 사이트를 찾았다.
http://www.arduinogr.com/2013/01/water-tank-level-display.html
https://www.open-electronics.org/water-tank-level-display-with-arduino/
많은 도움이 돼었냐고? 누가 묻는다면,
당연히 내가 만들고자 했던 초음파센서를 이용한 물탱크 수위 측정기의 개념을 정리 해준 곳이라 말하고 싶다.
소스도 받을 수 있지만.. 코드를 수정 할 것이 제법 된다. 뼈대(계념)만 가져오고 나머진 버리고 새로 코딩을 하는 것이 정신건강에 이롭다고 말 해 본다.
다운받아 아두이노에 업로드 해보면 그 이유를 금방 안다. 오류를 뿜어되는 아두이노 IDE를 보면서 이게 뭐지?! @.@
별것 아닌데 꼭꼭 숨겨 두고 혼자 아는 척 할 이유가 없어… (주인장의 탁월한 오픈 마인드 ㅡ.ㅡv)
2일 동안 나름 고생해서 만든 초음파센서를 이용한 물탱크 수위 측정기를 공개 해 볼까 한다. 더 나은 코딩이 있다면 누구나 맘껏 수정 해 주길 부탁한다. 그럼 시작해 볼까나..
1. 개요
– 원통형 물탱크와 사각형 물탱크를 선택적으로 측정할 수 있어야 한다.
– 물의 높이 측정과 동시에 리터 단위로 물의 양을 측정할 수 있어야 한다.
– 모니터링 가능한 시각적인 요소가 있어야 한다. (LCD, LED Bar…)
– 저수위와 고수위의 경보 기능이 있어야 한다.
– 경보는 선택적으로 켜고 끌 수 있어야 한다.
2. 준비물
– 아두이노
– I2C Characters LCD (16*2)
– 초음파센서 : HC-SR04
– 텍스위치
– 저항 10kΩ
– 피에조 스피커
– 빵판과 약간의 점퍼와이어
3. 구성
Fritzing으로 만든 빵판 회로도.

4. 코드
#include
#include // I2C LCD
#include // I2C LCD
#define TRIG 7 // 트리거 핀
#define ECHO 8 // 에코 핀
#define BUZZER_PIN 6 // 부저 핀
#define SIZE_BAR (16 * 5) // LCD 수위 표시 막대
/*
#define CYLINDER_CAPACITY_BASE (R_RADIUS * R_RADIUS * PI) // 원형 수조 용량 계산식
#define PI 3.1415926535898 // 원형 수조 – 파이 값
#define R_RADIUS 50 // 원형 수조 – 반지름 (cm)
#define R_HEIGHT 146.0 // 원형 수조 – 높이 (cm)
*/
#define SQUARE_CAPACITY_BASE (L_LENGTH * H_HEIGHT * W_WIDTH)/1000000 // 사각형 수조 용량 계산식
#define L_LENGTH 50.0 // 사각형 수조 – 깊이 (cm)
#define H_HEIGHT 100.0 // 사각형 수조 – 높이 (cm)
#define W_WIDTH 50.0 // 사각형 수조 – 가로 (cm)
#define DISTANCE_PLUS 10 // 초음파 센서의 측정 단위 (mm)
#define THRESHOLD_ALARM_1 10 // 최저수위값 알람 높이 (cm)
#define THRESHOLD_ALARM_2 100 // 최고수위값 알람 높이 (cm)
//LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // LCD 인터페이스 핀 번호를 지정
LiquidCrystal_I2C lcd(0x27,16,2); // LCD 메모리주소(0x27) 및 표시 가능한 열(16)과 행(2)을 설정
volatile int mute = 0; // 부저 초기값 : 0 => 부저ON, 1 => 부저OFF
int LABEL = 1;
// 그래픽문자 정의 : ˚C
byte newChar0[8] = {
B01000,
B10100,
B01000,
B00011,
B00100,
B00100,
B00011,
B00000
};
// 그래픽문자 정의 : 스피커 아이콘
byte newChar1[8] = {
B00001,
B00011,
B11101,
B10001,
B10001,
B11101,
B00011,
B00001
};
// 그래픽문자 정의 : 스피커 ON 아이콘
byte newChar2[8] = {
B00010,
B01001,
B00101,
B10101,
B10101,
B00101,
B01001,
B00010
};
// 그래픽문자 정의 : 블럭
byte newChar3[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
void setup() {
attachInterrupt(0, ALARM_ICON, RISING); // 인트럽트 설정 : 0 => D2, 1 => D3
lcd.init(); // LCD 초기화
lcd.backlight(); // LCD 백라이트 설정
lcd.begin(16, 2); // LCD 열, 행 정의
lcd.createChar(0,newChar0);
lcd.createChar(1,newChar1);
lcd.createChar(2,newChar2);
lcd.createChar(3,newChar3);
pinMode(BUZZER_PIN, OUTPUT);
Serial.begin(9600);
}
// 10Kohm NTC 온도센서 설정 시작
double Thermister(int RawADC) {
double Temp;
Temp = log(((10240000/RawADC) – 10000));
Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
Temp = Temp – 279.90; // <—- NTC 온도 보정시 수치를 수정
return Temp;
// 10Kohm NTC 온도센서 설정 끝
}
void loop() {
if (LABEL <=1){
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(“Ultrasonic”);
lcd.setCursor(0, 1);
lcd.print(“Waterlevel Meter”);
delay(3000);
}
LABEL =2;
long hWaterCm;
int liters;
hWaterCm = read_height();
if (check_alarm(hWaterCm) != 0) /* read again water height */
hWaterCm = read_height();
lcd.clear();
print_histogram(hWaterCm);
lcd.setCursor(0, 1);
String empty_t=”Empty”;
String full_t=”Full”;
if (hWaterCm >=100){ // 저수조 높이 (cm)
lcd.print(full_t);
lcd.setCursor(5, 1);
// litres = floor(CYLINDER_CAPACITY_BASE * hWatherCm * 10); //원통형 수조
liters = floor(SQUARE_CAPACITY_BASE * hWaterCm * 10); //사각형 수조
lcd.print(liters);
lcd.print(“L “);
Serial.print(“Amount of Water : “);
Serial.print(liters);
Serial.println(“L”);
}
if (hWaterCm <=0){
lcd.print(empty_t);
lcd.setCursor(6, 1);
Serial.print(“Water level : “);
Serial.println(empty_t);
lcd.print(“0”);
lcd.setCursor(7, 1);
lcd.print(“L”);
Serial.print(“Amount of Water : 0”);
Serial.println(“L”);
}
else {
lcd.print(hWaterCm);
lcd.print(“cm “);
Serial.print(“Water level : “);
Serial.print(hWaterCm);
Serial.println(“cm”);
// litres = floor(CYLINDER_CAPACITY_BASE * hWatherCm * 10); //원통형 수조
liters = floor(SQUARE_CAPACITY_BASE * hWaterCm * 10); //사각형 수조
lcd.print(liters);
lcd.print(“L”);
Serial.print(“Amount of Water : “);
Serial.print(liters);
Serial.println(“L”);
lcd.setCursor(14, 1);
lcd.write(byte(1)); // 스피커 아이콘
lcd.setCursor(15, 1);
if (!mute)
lcd.write(byte(2)); // 스피커 ON 아이콘
else
lcd.print(“x”);
switch (check_alarm(hWaterCm)) {
case 1: //full – alarm
buzz(200);
delay(100);
buzz(200);
delay(100);
buzz(200);
delay(100);
buzz(200);
delay(100);
buzz(200);
delay(100);
buzz(200);
delay(100);
buzz(200);
delay(100);
buzz(200);
break;
case 2: //empty – alarm
buzz(200);
delay(500);
buzz(200);
delay(500);
break;
case 0: // no alarm
delay(500);
}
}
/* 디스플레이용 수위 히스토그램 막대 설정 */
void print_histogram(int hWaterCm) {
int i;
int bloks;
float histogram;
histogram = (SIZE_BAR * hWaterCm) / H_HEIGHT;
histogram = histogram + 0.5;
bloks = (int)histogram / 5;
for (i = 0; i < bloks; i++) lcd.write(byte(3)); // 그래픽문자 정의 : 블럭 if ((int)(histogram) % 1 > 0)
lcd.write((int)(histogram) % 1);
}
long read_height() {
/*
초음파 센서의 핑 설정 및 거리와 센티미터의 변수 설정,
*/
long hWaterCm; pinMode(TRIG, OUTPUT);
digitalWrite(TRIG, LOW);
delayMicroseconds(20);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW); pinMode(ECHO, INPUT);
float distance = pulseIn(ECHO, HIGH);
distance=distance / 29.387 / 2;
Serial.print(“Sensor Real Distance : “);
Serial.print(distance);
Serial.println(“cm”);
Serial.println(“——————————“);
delay(20); hWaterCm = H_HEIGHT – distance + DISTANCE_PLUS;
if (hWaterCm < 0)
return 0; if (hWaterCm > H_HEIGHT)
return H_HEIGHT; return hWaterCm;
} void buzz(int msec) {
if (!mute)
digitalWrite(BUZZER_PIN, HIGH);
delay(msec);
digitalWrite(BUZZER_PIN, LOW);
} int check_alarm(int hWaterCm) {
if (hWaterCm >= THRESHOLD_ALARM_2) {
return 1;}
if (hWaterCm <= THRESHOLD_ALARM_1) {
return 2;}
else {
return 0;}
} void ALARM_ICON() {
if (mute == 1)
mute = 0;
else
mute = 1;
}
참 길기도 하다.. 라고 말하지만, 내가 사용 하기에는 앞으로 추가 해야 할 부분들이 더 있다. 하지만 이 정도면 모니터링 하기에는 문제 없어 보인다.
5. 결과물.. 사진






앞으로 이녀석에게 저수위 일때 물탱크의 자동 급수를 위해 모터 릴레이와 물탱크 내부 온도 모니터를 위해 온도 센서를 추가해 볼까 한다.
“ARDUINO – 초음파센서(HC-SR04)를 이용한 물탱크 수위 측정기 만들기”의 1개의 생각