Embedded System/ATmega128

HC-SR04(초음파 센서)의 이해

전두선 2017. 8. 13. 16:44

HC-SR04(초음파 센서)의 이해                                Datasheet :    HCSR04.pdf





초음파란? 주파수가 20kHz를 넘는 사람이 듣지 못하는 음파를 초음파라고 한다.


HC-SR04 란? 초음파 센서 모듈로 초음파 송신부(Trig), 초음파 수신부(Echo), 제어회로로 

구성되어 있는데, 가격적으로 저렴하고 사용자가 간편하게 초음파를 제어해 거리를 측정 할 수 있도록 만들어졌다.









이 초음파 센서는 전방 2cm ~ 400cm의 15도까지 정확하게 측정이 가능하다. 하지만 측정이 가능

하게 하려면 사용자는 이 제품의 데이터 시트가 원하는 조건을 들어주어야 한다.

그 조건이란 타이밍 다이어그램을 말하는데 이 HC-HSR04말고도 다른 제품을 사용할때, 

타이밍 다이어그램이 존재한다면 그것을 이해하는것은 매우 중요하다.



HC-SR04 Timing Diagram




[타이밍 다이어그램 해석]

1. 모듈의 트리거 인풋에 10 us의 하이펄스를 준다.

2.  40KHz의 8개 초음파 버스트 발생. [1번 과정을 거쳐야만 발생]

3. 에코는 초음파 발신 직후 HIGH 레벨이 되고, 반항을 감지하면 LOW 레벨이 된다.

-> 에코 펄스는 즉, 초음파가 장애물을 만나 다시 에코로 돌아올때까지의 왕복 시간을 나타낸다,

4. 거리 에코 High Pulse 시간(왕복시간) 소리의 속도(340m/s) / 2 

-> 왕복이므로 2로 나누어 주어야한다. 





위는 HC-SR04 데이터 시트의일부 내용이다. 측정 주기를 60ms 이상 주어서 측정을 하라는 말이다. 위에 보면 자세하지 않은 타이밍 다이어그램도 그렇고, 바로 위에 이 측정 주기를 60ms 이상으로 주어라....

뭐 사용하는데 지장은 없겠지만, 저는 완벽하게 이해하기 위해서 이 HC-SR04와 비슷한 제품인

SRF-04를 찾을 수 있었다. 


보기전에 SRF-04 제품은 2cm ~ 300cm 측정이 가능하기에 이 부분이 다르다, 

즉 걸러낼것은 걸러내고 HC-SR04 제품을 생각하면서 참고를 목적으로 봐야한다. 


SRF04 Timing Diagram



   

HC-SR04 제품보다 이 SRF04제품은 타이밍 다이어그램에 더 자세한 설명들이 적혀있다.


1. 우선 에코펄스. 에코 펄스가 100us ~ 18ms 의 범위라고 나오는데, 위에서 말했듯이 이것은 

측정 가능한 범위를 나타낸다. 2cm ~ 300cm를 나타내는데, 

직접 에코펄스*소리의 속도/2를 계산해보면 알수있다. HC-SR04 제품은 최대 측정 거리가 400cm 이므로 에코 펄스가 더 클 수 있다는 점을 알아야한다. 

또한 객체탐지가 안됬을시, 즉  8개의 초음파 버스트가 모두 장애물 감지를 못했을때. 최대 36ms까지 펄스가 커진다는 점도 알아야한다.


2. 다음은 에코펄스가 끝나고 다음 트리거를 주기전까지 10ms의 딜레이가 필요한데, 그 이유는 

8개의 초음파 펄스가 모두 사라질 때까지 대기해야 하기 때문이다. 8개중 1개가 제일 가까운 장애물을 감지하고 들어왔는데, 나머지 7개의 버스트가 들어오지 않았기 때문에 딜레이가 필요하다는 거다.


-> 결과적으로 보면 10us의 트리거 입력 주기(측정주기)를 이 제품은 약 50ms 주기로 측정해야 하고, 왜 HC-SR04 제품이 60ms의 주기로 측정하라는 건지 어느정도 이해갔을것이다. 




지금까지의 과정을 이해했다면, 초음파 센서로 거리가 어떻게 측정되는지 감이 왔을것이다. 

거리 = 속도 x 시간 이므로, 거리 = 소리의 속도(0.034 cm/us) x 에코 펄스시간이 된다.


위 사진은 역으로 에코펄스의 시간을 구해보았다. 만약 장애물이 10cm라 가정했을때, 

에코 펄스는 588.235us가 된다는것을 알 수 있다.


소리의 속도는 340m/s = 0.034 cm/s

즉, 1cm가는데 걸리는 시간은 29us인데, 왕복이므로 58us가 된다. 

10cm 이므로 580us.




외부인터럽트와 16bit 타이머를 이용한 초음파 센서 제어 







해상도(CM, MM 등)



1cm 왕복시간은 58us이고, 1mm 왕복시간은 5.88us 이다.


거리 = 속도 x 시간 / 2 = 소리의 속도 x ((F-R TCNT) x 분주비/F CPU) / 2


빨간색으로 표시한 부분이 에코펄스 구간이다. 


센티미터

이 제품의 최소 거리인 2cm의 에코펄스는 116us가 된다. 

3cm는? +58us 

4cm는? +58us


밀리미터

동일하게 최소 거리인 20mm의 에코펄스는 116us가 되고, 

21mm는? +5.88us 

22mm는? +5.88us


결과적으로 분주비와 F CPU 선택해상도에 영향을 준다는것을 알 수 있다.












** 참고한 소스코드(https://cafe.naver.com/circuitsmanual/149885) **

1
2
3
4
5
6
7
8
9
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#define  F_CPU 16000000UL // 16 MHz
#include <avr/io.h>
#include <util/delay.h> 
#include <avr/interrupt.h>
//
volatile unsigned int  buf[8],dist[8],start=0,end=0;
volatile unsigned char cnt=0,flag[8]={0,};
//
ISR(INT0_vect){ if(EICRA==0x03)start=TCNT1; elseend=TCNT1; buf[0]=end-start; EIMSK=0; flag[0]=1; } EICRA^=0x01; }
ISR(INT1_vect){ if(EICRA==0x0C)start=TCNT1; elseend=TCNT1; buf[1]=end-start; EIMSK=0; flag[1]=1; } EICRA^=0x04; }
ISR(INT2_vect){ if(EICRA==0x30)start=TCNT1; elseend=TCNT1; buf[2]=end-start; EIMSK=0; flag[2]=1; } EICRA^=0x10; }
ISR(INT3_vect){ if(EICRA==0xC0)start=TCNT1; elseend=TCNT1; buf[3]=end-start; EIMSK=0; flag[3]=1; } EICRA^=0x40; }
ISR(INT4_vect){ if(EICRB==0x03)start=TCNT1; elseend=TCNT1; buf[4]=end-start; EIMSK=0; flag[4]=1; } EICRB^=0x01; }
ISR(INT5_vect){ if(EICRB==0x0C)start=TCNT1; elseend=TCNT1; buf[5]=end-start; EIMSK=0; flag[5]=1; } EICRB^=0x04; }
ISR(INT6_vect){ if(EICRB==0x30)start=TCNT1; elseend=TCNT1; buf[6]=end-start; EIMSK=0; flag[6]=1; } EICRB^=0x10; }
ISR(INT7_vect){ if(EICRB==0xC0)start=TCNT1; elseend=TCNT1; buf[7]=end-start; EIMSK=0; flag[7]=1; } EICRB^=0x40; }
//
ISR(TIMER1_COMPA_vect){
    switch(cnt){
      case 0: PORTA|=0x01; _delay_us(10); PORTA&=~0x01; EICRA=0x03; EICRB=0x00; EIFR=0xFF; EIMSK=0x01break;
      case 1: PORTA|=0x02; _delay_us(10); PORTA&=~0x02; EICRA=0x0C; EICRB=0x00; EIFR=0xFF; EIMSK=0x02break;
      case 2: PORTA|=0x04; _delay_us(10); PORTA&=~0x04; EICRA=0x30; EICRB=0x00; EIFR=0xFF; EIMSK=0x04break;
      case 3: PORTA|=0x08; _delay_us(10); PORTA&=~0x08; EICRA=0xC0; EICRB=0x00; EIFR=0xFF; EIMSK=0x08break;
      case 4: PORTA|=0x19; _delay_us(10); PORTA&=~0x10; EICRA=0x00; EICRB=0x03; EIFR=0xFF; EIMSK=0x10break;
      case 5: PORTA|=0x20; _delay_us(10); PORTA&=~0x20; EICRA=0x00; EICRB=0x0C; EIFR=0xFF; EIMSK=0x20break;
      case 6: PORTA|=0x40; _delay_us(10); PORTA&=~0x40; EICRA=0x00; EICRB=0x30; EIFR=0xFF; EIMSK=0x40break;
      case 7: PORTA|=0x80; _delay_us(10); PORTA&=~0x80; EICRA=0x00; EICRB=0xC0; EIFR=0xFF; EIMSK=0x80break;
    }
    if(++cnt>7)cnt=0;
}
//
int main(void){
    DDRA=0xFF// 트리거
    DDRB=0xff;
    TCCR1B=0x0C; OCR1A=3124; TIMSK=0x10//16000000/256/(1+ 3124)=20Hz=50ms
    SREG=0x80;
    while(1){
        if(flag[0]){ flag[0]=0; dist[0]=(int)((float)buf[0]/14.5); }
        if(flag[1]){ flag[1]=0; dist[1]=(int)((float)buf[1]/14.5); }
        if(flag[2]){ flag[2]=0; dist[2]=(int)((float)buf[2]/14.5); }
        if(flag[3]){ flag[3]=0; dist[3]=(int)((float)buf[3]/14.5); }
        if(flag[4]){ flag[4]=0; dist[4]=(int)((float)buf[4]/14.5); }
        if(flag[5]){ flag[5]=0; dist[5]=(int)((float)buf[5]/14.5); }
        if(flag[6]){ flag[6]=0; dist[6]=(int)((float)buf[6]/14.5); }
        if(flag[7]){ flag[7]=0; dist[7]=(int)((float)buf[7]/14.5); }
    }
}
 
cs




공부할때 정말 많은 도움이 된 전자공작 사이트 주소입니다.   http://cafe.naver.com/circuitsmanual