AVR2560

2013.06.10_초음파센서_활용

성엽이 2013. 6. 11. 17:52

▶ Ultra.c

#include "Ultra.h"

static volatile unsigned int ui_Tic;  // 58us 1cm.
static volatile unsigned int ui_dist;  // Echo Pulse 가 Low 되는순간의 값을 저장. 거리를 게산가능.
static volatile unsigned int ui_state;  // 현재 초음파 거리를 측정중인지 아닌지.
                                            // 측정중이면 1, 측정중이 아니면 0
unsigned char *ULTRA_RUN(void)
{
  static unsigned char uc_dist[] = "---cm";

  ui_Tic = 0;    // 미리 0cm 로 초기화.
  ui_dist = 0;    // 계속동작중인 ui_Tic 에다가 값을 넣어서. 실제거리를 제려고.   

  TRG_PULSE_Toggle();   // TRG Toggle

  DDRE = 0x00;    // PIN에 입력받음.

  while0 == ((PINE) & (1<<Echo_Pin)) );    // Echo_Pin 의 상승엣지를 발견함.  LOW level 0 , HIGH level 1                


  TIMSK0 = (0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0);  // 타이머/카운터0 인터럽트 허용. OverFlow 방식.

  sei();    // 모든 인터럽트 켜주기. TC 시작
  
  ui_state = 1;      
                                             // 측정중 숫자넣어놓기. Echo 주파수의 하강엣지 감지 > vector_5 > state = 0 으로 되면서 
  while1 == ui_state );    // 전역변수에 0 이 드러가면 나옴.

  U_Timer_Init();    // 타이머 꺼줌.
  Echo_INT_Init();    // Echo 꺼줌.

  cli();    // 모든 인터럽트 꺼주기. 초기화.

  uc_dist[0]= '0' + ((ui_dist%1000)/100);    // ui_dist의 실제거리를 넣어둠.
  uc_dist[1]= '0' + ((ui_dist%100)/10);
  uc_dist[2]= '0' + ((ui_dist%10));
  
  return uc_dist;
}

void ULTRA_INIT(void)
{
  Echo_INT_Init();
  TRG_init();
  U_Timer_Init();
}

void Echo_INT_Init(void)  // Low 레벨에서 걸리도록.
{
  EICRB = (EICRB) | (1<<ISC41) | (0<<ISC40);    // 하강엣지감지.
  EIMSK = (1<<Echo_Pin);  // Echo_Pin 쓰겠다.
  
  return;
}

void __vector_5(void)  // Ultra 핸들러.
{
  ui_dist = ui_Tic;
  ui_state = 0;
  return;
}

void U_Timer_Init(void)
{
  TCCR0A = ((0<<WGM00) | (0<<WGM01) | (0<<COM0A0) | (0<<COM0A1) |(0<<COM0B0) |(0<<COM0B1)) ;  // 노말모드
  TCCR0B = ((0<<CS02) | (1<<CS01) | (0<<CS00) | (0<<WGM02));  // 상승엣지 에서 동작 설정. 8 분주비

  TCNT0 = Tic_Start;  // 오버플로수 시작값 설정.
  //TIMSK0 = (1<<OCIE0A);  // 타이머/카운터0 인터럽트 허용.

  

  cli();

}

void __vector_23(void)  // 타이머핸들러.
{
  ++ui_Tic;        // Tic 을 계속 올려줌.
  TCNT0 = Tic_Start;    // 다시 불러줌.
  return;
}

void TRG_init(void)
{
  DDRA = 0xFF;
  PORTA = 0<<TRG_PIN;  // TRG 핀 초기화.
  return;
}

void TRG_PULSE_Toggle(void)
{
  volatile unsigned int ui_Cnt;
  DDRA = 0xFF;

  PORTA = 1<<TRG_PIN;  // TRG 핀 출력
  
  for(ui_Cnt=0;ui_Cnt < 1000;++ui_Cnt);  // 48 cycle 이상 지연. 0.00001s 4000 cycle 이상 지연.

  PORTA = 0<<TRG_PIN;  // TRG 핀 입력

  return;
}


▶ Ultra.h

#ifndef  _ULTRA_H_
#define  _ULTRA_H_


#define PINA    (*((volatile unsigned char *)0x20))
#define DDRA    (*((volatile unsigned char *)0x21))
#define PORTA  (*((volatile unsigned char *)0x22))

#define PINE    (*((volatile unsigned char *)0x2C))
#define DDRE    (*((volatile unsigned char *)0x2D))
#define PORTE  (*((volatile unsigned char *)0x2E))

#define  TRG_PIN    1  // 트리거 핀.

/**** 외부인터럽트 제어 레지스터 EICRA ***/
#define  EICRA  ((*(volatile unsigned char *)0x69))
#define  ISC31  7
#define  ISC30  6
#define  ISC21  5
#define  ISC20  4
#define  ISC11  3
#define  ISC10  2
#define  ISC01  1
#define  ISC00  0

/**** 외부인터럽트 제어 레지스터 EICRB ***/
#define  EICRB  ((*(volatile unsigned char *)0x6A))
#define  ISC71  7
#define  ISC70  6
#define  ISC61  5
#define  ISC60  4
#define  ISC51  3
#define  ISC50  2
#define  ISC41  1
#define  ISC40  0

/**** 외부인터럽트 마스크 레지스터 EIMSK **/
#define  EIMSK  ((*(volatile unsigned char *)0x3D))
#define  INT7  7
#define  INT6  6
#define  INT5  5
#define  Echo_Pin  4  // 6번핀을 사용할 것이다.
#define  INT3  3
#define  INT2  2
#define  INT1  1
#define  INT0  0

#define  EIFR    ((*(volatile unsigned char *)0x3C))
#define  INTF7  7
#define  INTF6  6
#define  INTF5  5
#define  Echo_Flag  4
#define  INTF3  3
#define  INTF2  2
#define  INTF1  1
#define  INTF0  0

#define  TCCR0    (*((volatile unsigned int *)0x44))  // 타이머/카운터 제어레지.
#define  TCCR0A    (*((volatile unsigned char *)0x44))  // 타이머/카운터 제어레지.
#define  TCCR0B    (*((volatile unsigned char *)0x45))
#define  TCNT0    (*((volatile unsigned char *)0x46))  // 카운터값을 저장하는 레지.
                                                            // 카운터 세어주는 레지.
/***** 인터럽트 기능 설정 레지스터 ******/
#define  TIMSK0    (*((volatile unsigned char *)0x6E))

/*****  타미어/카운터 0 제어 레지 A 설정 ***/
#define  WGM00    0
#define  WGM01    1
#define  COM0B0    4
#define  COM0B1    5
#define  COM0A0    6
#define  COM0A1    7

/*****  타미어/카운터 0 제어 레지 B 설정 ***/
#define  CS00    0
#define  CS01    1
#define  CS02    2
#define  WGM02    3    
#define  FOC0B    6
#define  FOC0A    7

/***** 상태 레지스터 SREG *****/
#define  SREG    (*((volatile unsigned char *)0x5F))
#define  Global_Interrupt_Enable  7  
#define  T            6
#define  H            5
#define  S            4
#define  V            3
#define  N            2
#define  Z            1
#define  C            0

/***** 분주비 설정 라인 ****/
#define  MCK      16000000
#define  PRESCALE    8
#define  Tic_Start    255-((1/(340L*100))*2)/(1/(MCK/PRESCALE))  // 오버플로우 시작값을 설정해줌.
                       //255-117
                                       
/***** 인터럽트 기능 허용 ***/
#define  OCIE0B    2
#define  OCIE0A    1
#define  TOIE0    0

unsigned char *ULTRA_RUN(void);
void U_Timer_Init(void);
void ULTRA_INIT(void);
void Echo_INT_Init(void);
void TRG_init(void);
void TRG_PULSE_Toggle(void);

void __vector_5(void) __attribute__ ((signal, used, externally_visible));   // INT4 외부인터럽트 벡터

void __vector_23(void) __attribute__ ((signal, used, externally_visible));  // TC OVF 벡터

#define sei(void)   __asm__ __volatile__ ("sei" ::)  // InLine asm , 소스코드 안에 직접 집어넣는 어셈블러
  // C소스안에 어셈블리어를 쓸수없는데, 어셈블리어를 넣을때 InLine 으로 넣을수 있다.
  // C가 아니기 때문에 전처리, 컴파일에서 걸리지 않는다. gcc 문법임.
  // 방법 (1) SREG = ((SREG) | (1<<Global_Interrupt_Enable)); 직접 넣는 명령어.
  // (2) 어셈블리 명령어 sei(); 어셈블리 명령어.
#define cli(void)   __asm__ __volatile__ ("cli" ::)  // InLine asm , 소스코드 안에 직접 집어넣는 어셈블러  
#define sleep(void)  __asm__ __volatile__ ( "sleep" "\n\t" :: )
  // 전력소모를 줄이기위한 어셈블리 대기상태 명령.


#endif // _ULTRA_H_