13
2016-Feb
[AVR] HC_SR04 초음파센서 사용
작성자: Blonix
IP ADRESS: *.148.87.98 조회 수: 1668
바로 요놈이다.
일단 VCC, GND는 전원이고, 중요한건 TRIG (트리거) 핀과 ECHO (에코) 핀이다.
아두이노에 사용하는 방법은 인터넷 찾아보면 널렸고.. AVR에 사용하려면 이놈의 작동방식을 자세히 알 필요가 있다.
일단 데이터 시트부터 보자.
주목할건 가장 아래의 그림이다.
작동 순서는 다음과 같다.
1. avr에서 소프트웨어적으로 트리거 핀에 10us 의 펄스신호를 준다.
2. HC_SR04는 그 시작신호를 받고 8개의 40kH짜리 음파 펄스를 만들어서 스피커로 뚜다다당 쏜다.
3. 그 즉시(?) 에코 핀으로 HIGH 입력신호를 보내기 시작한다. (즉시 맞나? 상식적으로 즉시 맞겠지?)
4. 반사되어 돌아온 초음파가 수신 스피커로 들어오면 에코 핀에서 보내던 HIGH 신호를 멈춘다.
5. 보낸 음파가 돌아오지 않았을 경우 38ms 가 지나서 HIGH 신호를 끊는다.
그러니까 우리가 AVR에서 해야하는 것은 에코 핀에서 돌아오는 HIGH 신호가 얼마나 지속되었는지를 알아내야 하는 거다.
에코핀에 들어온 HIGH 신호 (일반적인 실온에서) 59 마이크로초(us)당 1cm 라고 계산하면 된다.
왜 58us 인지 궁금하면 실온에서의 음속인 340m/s 를 변환해보면 알게 된다. 갔다가 돌아오는거니까 *2 까먹지 말고.
코드는 다음과 같다. 내 코드는 C++ 타입이라 좀 알아보기 힘들듯 하여 스크랩으로 대체한다.
근데 포그이터 게시판에서 들여쓰기 맛탱이가 좀 이상해서 링크가 살아있다면 링크가서 보는걸 추천
출처 :: http://blog.daum.net/seongju4645/58
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
volatile unsigned int pulse_count = 0;
volatile unsigned char togle = 0;
void pulse(void) //10usec High 펄스 출력
{
_delay_ms(100);
PORTD |= 0x01; //input pulse -> PB0
_delay_us(10);
PORTD &= ~0x01;
}
ISR(TIMER0_OVF_vect)
{
pulse_count++; //58sec 마다 증가
}
ISR(INT0_vect)
{
if(togle == 0) //카운터 시작하고 외부인터럽트(INT0)를 다음에는 falling Edge에서 걸리도록 함.
{
pulse_count = 0; //측정된 이전 거리값 초기화
// TIMER COUNTER RESISTER
TIMSK0 = 1<<TOIE0; //Timer/Counter0 Overflow Interrupt Enable
//TCNT0 -> 256이 되면 오버플로우가 발생되게 됩니다.
TCCR0B = 1<<CS01; //분주비 8 => 8MHz->1MHz
TCNT0 = 256 - 58; /*TCNT0 한 클럭 당 시간(s = 1/f) 1/1MHz=1us 필요한 시간 58us =>58us/1us=58
TCNT0에 숫자를 지정해주는 것은 시작하는 지점을 지정해주는 것입니다.
256 -58 = 198부터 TCNT0가 시작되어서 카운터를 하는데 결국 58번 카운터된 후 오버플로우가 발생되게 되어서
58us를 센 후 오버플로우가 발생하는 것입니다.*/
EICRA = 1<<CS01; //외부인터럽트 INT0 falling edge에서 인터럽트 발생
togle = 1;
}
else //카운터를 정지시키고 외부 인터럽트(IN0)를 다음에는 Rising Edge에서 걸리도록 함.
{
TIMSK0 = 0x00; //All Timer Disable
togle = 0;
EICRA = (1<<CS01)|(1<<CS00); //외부인터럽트 INT0가 rising edge에서 인터럽트 발생
}
}
void main()
{
DDRD = 0x01; //Dport 0 input pulse 송신 (출력), Dport 2 output pulse 수신 (입력)
PORTD |= 0x02; //PORTD b1 pullup enable
DDRB = 0x01; //LED pin -> PB)
_delay_ms(5);
EIMSK = 1<<INT0; //외부인터럽트 INT0 Enable
EICRA = (1<<CS01)|(1<<CS00); //rising edge
sei();
while(1)
{
pulse(); //10usec High Pulse Output
if(pulse_count<8) PORTB = 1; //8cm보다 작으면 led가 켜집니다.
else PORTB = 0; //그외 조건에서는 꺼집니다.
}
}