# 프로그램 설명
1. pulseIn(int pinNum, Value) 함수는 Value에서 제시한 신호의 유지 시간을 측정하여 반환하는 함수이다. 이 함수와 같이 HIGH 펄스가 유지된 시간을 구하는 자체 함수 MyPulseIn()을 구현한다. 이 함수는 인터럽트가 발생 시에 호출된다.
2. 초음파 센서와 장애물 사이의 거리를 MyPulseIn() 함수를 사용하여 구한 후 시리얼 모니터에 출력하는 프로그램이므로 setup() 부분에 시리얼 전송 속도를 설정한다. 트리거 단자는 출력 모드, 에코 단자는 입력 모드로 설정한다. 이때 에코 단자는 인터럽트를 사용하기 위하여 인터럽트 단자인 2번 단자에 연결한다. 장애물 사이의 거리(cm)를 구하기 위해 사용될 섭씨온도와 소리의 이동 속도(cm/us)를 지정하고 거리의 범위를 설정한다.
3. attachInterrupt() 함수를 사용하여 에코 단자 번호(2번)를 인터럽트 번호(0번)로 변환한 후 이 단자의 신호가 CHANGE(HIGH->LOW 또는 LOW->HIGH)가 되어 인터럽트가 발생하면 MyPulseIn() 함수를 수행하도록 지정한다.
모드가 CHANGE인 이유는 에코 단자가 LOW에서 HIGH가 될 때까지(RISING) 기다린 후 HIGH가 되자마자 시간을 측정하여 다시 HIGH에서 LOW가 될 때까지의(FALLING) 시간을 측정한 후 그 차를 구하여 왕복 시간을 구하므로 RISING과 FALLING 상태 모두 인터럽트가 발생시킨다.
4. 인터럽트가 발생하여 호출된 함수 MyPulseIn() 에서는 에코 단자가 LOW에서 HIGH로 바뀌는 RISING 모드일 때 인터럽트가 발생되어 이전 상태가 LOW이고 에코 단자가 HIGH 이면 현재 시간을 s에 저장한다. (현재 시간을 구하는 함수는 micros() 함수로 이 함수는 us 단위로 구한다.) HIGH가 계속 유지된 후 HIGH에서 LOW로 바뀌는 FALLING 모드일 때 인터럽트가 발생되어 에코 단자가 LOW이고 이전 상태가 HIGH이면 현재 시간을 e에 저장한다. 처음 HIGH로 올라가는 시간인 s와 HIGH로 유지되다가 LOW가 되는 시간인 e의 차이를 이용하면 HIGH 펄스 시간을 구할 수 있다. 이를 구하여 변수 t에 저장한다.
5. void loop() 부분에서 digitalWrite() 함수를 이용하여 Trig 단자의 신호를 LOW로 만들어 오동작을 방지한 후 10us 지연시킨다. 이 후 신호를 HIGH로 만들어 HIGH 펄스를 만든 후 10us 지연시킨 후 신호를 LOW로 만들어 8개의 40KHz 펄스로 구성된 초음파를 방출한다. 초음파가 장애물에 반사되어 돌아오면 HIGH가 Echo 단자에 들어온다. Echo 단자로 들어온 HIGH 펄스가 유지된 시간(us)을 인터럽트를 발생시켜 MyPulseIn() 함수를 사용하여 구하여 변수 duration(왕복 시간)에 저장하고 이를 사용하여 초음파 센서와 장애물 사이의 거리(cm)를 구하여 변수 distance에 저장한다.
6. 장애물 사이의 거리가 범위 안에 해당하면 거리를 시리얼 모니터에 출력하고 범위가 벗어나면 이를 알려주는 메세지를 출력한다.
7. 초음파 센서의 Vcc 단자(보라색)를 아두이노 5V, Trig 단자(파란색)를 GPIO 8번, Echo 단자(초록색)를 GPIO 7번, GND(노란색 를 GND에 연결한다.
# 소스
#define ECHO_PIN 2 // Echo 단자
#define TRIG_PIN 8 // Trig 단자
#define TEMPERATURE 27 // 섭씨 온도
int maximumRange = 25; // 최대 범위
int minimumRange = 5; // 최소 범위
long duration, distance; // 왕복시간, 센서와 장애물 사이의 거리
double sSpeed_cm_us; // 소리의 이동 속도
volatile unsigned long s, e, t; // 왕복시간 구하는 데 필요한 변수
volatile int previous = LOW; // 이전 상태 저장하는 변수
void setup() {
Serial.begin (9600);
pinMode(TRIG_PIN, OUTPUT); // Trig 단자 OUTPUT모드로 설정
pinMode(ECHO_PIN, INPUT); // Echo 단자 INPUT모드로 설정
sSpeed_cm_us = (331.5 + 0.6*TEMPERATURE) * pow(10, 2) / pow(10, 6); // 소리의 이동 속도 [cm/us]
// 인터럽트 발생 시 처리할 함수 설정
attachInterrupt(digitalPinToInterrupt(ECHO_PIN),MyPulseIn,CHANGE);
}
void loop() {
digitalWrite(TRIG_PIN, LOW); // Trig 신호를 LOW로 만들어 오동작 방지
delayMicroseconds(10); // 10us 지연
digitalWrite(TRIG_PIN, HIGH); // 10us High Pulse 생성
delayMicroseconds(10); // 10us 지연
digitalWrite(TRIG_PIN, LOW); // 센서 모듈이 40KHz의 펄스 8개 출력
duration = t; // 초음파가 발사된 후 반사되어 돌아오는 왕복시간(us)
distance = duration/2 * sSpeed_cm_us; // 초음파 센서와 장애물 사이의 거리 구함
// 최소 범위 ~ 최대 범위 사이이면 장애물 사이의 거리 출력
if (distance <= maximumRange and distance >= minimumRange)
Serial.println(distance);
// 범위를 벗어나면 이를 알려주는 메세지 출력
else
Serial.println("범위를 벗어났습니다.") ;
}
void MyPulseIn(){ // pulseIn() 함수와 동일한 동작하는 자체 함수
// 이전 상태가 LOW이고 Echo 단자가 HIGH가 되면(RISING)
if(digitalRead(ECHO_PIN)==HIGH and previous == LOW) {
s = micros(); // 현재 시간을 s에 저장
previous = HIGH; // 이전 상태를 HIGH로 바꿈
}
// 이전 상태가 HIGH이고 Echo 단자가 LOW가 되면(FALLING)
if(digitalRead(ECHO_PIN)==LOW and previous == HIGH){
e = micros(); // 현재 시간을 e에 저장
previous = LOW; // 이전 상태를 LOW로 바꿈
}
t = e-s; // HIGH 펄스 시간를 t에 저장
}
# 실행화면 (시리얼 모니터)
- 5 ~ 25cm 사이에 장애물이 위치하면 시리얼 모니터에 거리 출력
- 약 16cm와 8cm에 위치한 장애물의 거리를 측정
- 5 ~ 25cm 사이에 속하지 않으면 거리를 벗어났다는 메세지 출력
'전공 공부 > 아두이노프로그래밍' 카테고리의 다른 글
20KHz의 클럭 소스를 이용하여 인터럽트를 발생. 이를 기반으로 tone() 함수를 설계하고 한 옥타브의 음정을 연주 (0) | 2021.01.22 |
---|---|
MsTimer2 이용하여 지정한 주파수의 음정을 생성하는 myTone(pin, frequency)과 myNoTone() 함수를 제작 (0) | 2021.01.22 |
analogWrite() 함수 이용하여 390Hz의 periodic interrupt를 발생시키는 프로그램 (0) | 2021.01.22 |
장애물까지의 거리를 mm단위로 반환하는 함수 (4) | 2021.01.18 |
스피커를 이용한 연주 (0) | 2021.01.18 |