AT91SAM7S256

2013.05.24_초음파센서_

성엽이 2013. 5. 24. 09:17


▶ 초음파센서를 통한 거리측정

소리는 1초 -> 340m 갑니다.

계산을 해보면 1cm는 ->  0.00002941176470588240 sec

분주비 8 로 오차가 가장적었음. 48/8 = 6Mhz 을 사용.

1cm -> 29.411764us 한번간거리.

          58.823528us 갔다온거리.

------------------------  

MCK_클락배수나눔.xlsx

ARM_AT91SAM7S (2).zip

----------------------------


 #include "ULTRA_AIC.h"


static volatile unsigned int ui_Tic;  // 58us 1cm.
static volatile unsigned int ui_dist;  // 
static volatile unsigned int ui_state;  // 현재 초음파 거리를 측정중인지 아닌지.
                                            // 측정중이면 1, 측정중이 아니면 0
unsigned char *ULTRA_RUN()
{
  static unsigned char uc_dist[] = "---cm";
    
  TRG_PULSE_Toggle();
  
  ui_Tic = 0;    // 미리 0cm 로 초기화.
  ui_dist = 0;    // 계속동작중인 ui_Tic 에다가 값을 넣어서. 실제거리를 제려고. 
    
  

  while0 == ((AT91C_BASE_PIOA->PIO_PDSR) & ( 1<<Echo_PIN )) );    // 상승엣지의 상태를 발견함.
                // LOW level 0 , HIGH level 1
// 타이머 클럭 활성화(TC_CCR, CLKEN)
  AT91C_BASE_TC0->TC_CCR  = AT91C_TC_CLKEN;    // 클럭이 켜짐. Timer/Count 를 켜줌.
// 1. 끝 : 타이머 클럭 비활성화 ------------------

// 타이머 시작(TC_CCR, SWTRG)
  AT91C_BASE_TC0->TC_CCR  = AT91C_TC_SWTRG;  

// 인터럽트를 켜줌.
  AT91C_BASE_PIOA->PIO_IER = 1<<Echo_PIN;      // PIO의 15번 핀을 켜줌. 셋팅을 끝내고 열어줌!
  AT91C_BASE_AIC->AIC_IECR = 1<<AT91C_ID_PIOA;    // 장치번호를 켜줘야함!

  ui_state = 1;      // 측정중 숫자넣어놓기.

  while1 == ui_state );    // 전역변수에 0 이 드러가면 나옴.

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

  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()
{
  ECHO_INIT();
  TRG_init();
  U_Timer_Init();

}
void ECHO_INIT()
{
  AT91C_BASE_PMC->PMC_PCER = 1<<AT91C_ID_PIOA;    // P203, PMC_PCER 를 통해서 PIOA 활성화.
  AT91C_BASE_PIOA->PIO_ODR = 1<<Echo_PIN;  // P252, PIO_ODR 를 통해서 15번 핀 출력 비활성화.
  AT91C_BASE_PIOA->PIO_PER = 1<<Echo_PIN;    // P250, PIO_PER 를 통해서 핀자체를 활성화.
  AT91C_BASE_PIOA->PIO_IDR = 1<<Echo_PIN;    // P250, PIO_IDR 를 통해서 15번 핀의 Interrupt 를 비활성화. 
  AT91C_BASE_AIC->AIC_IDCR = 1<<AT91C_ID_PIOA;  // P175, AIC_IDCR 를 통해 AIC 비활성화. 

// 타이머 카운터 0 인터럽트 핸들러 등록(AIC_SVR[TC0], AIC_Handler)
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_PIOA] = (volatile unsigned int )ULTRA_Handler;
  

// 타이머 카운터 0 인터럽트 모드 설정(AIC_SMR[TC0], AIC_SRCTYPE_INT_HIGH_LEVEL, PRIOR_LOWEST)
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_PIOA] = ((AT91C_AIC_PRIOR_LOWEST) | (AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE));  
                                                                                                                // Source type 은 외부인터럽트-Negative 로 맞춰줌.

  AT91C_BASE_AIC->AIC_ICCR = 1<<AT91C_ID_PIOA;   // P181, PIOA 장치에 값을 초기화. 엣지 디텍터
  AT91C_BASE_PIOA->PIO_IFER= 1<<Echo_PIN;    // P253, Glitch Input Filter Enable Register
                                          // PIN에 스위치를 통한 처음과 끝부분의 잡음 제거.
  AT91C_BASE_AIC->AIC_ISCR = 1<<AT91C_ID_PIOA;      // Glitch Input Filter 를 설정하고 다시 켜줌. 엣지 디텍터.
  //AT91C_BASE_PIOA->PIO_IER = 1<<Echo_PIN;    // PIO의 15번 핀을 켜줌. 셋팅을 끝내고 열어줌!
  //AT91C_BASE_AIC->AIC_IECR = 1<<AT91C_ID_PIOA;      // 장치번호를 켜줘야함!
    
  return;
}

void ULTRA_Handler()
{  // Timer/count 와는 다르게 인터럽트는 32개가 다 반응하므로 PIO로 외부인터럽트신호를 확인해줘야한다.
  AT91C_BASE_PIOA->PIO_ISR;  // 미리 만들어 둔다.

  ui_dist = ui_Tic;    // 하강인터럽트 걸리는 순간까지도 ui_Tic 은 계속 돌고있다.
            // 그래서 ui_dist 에다가 인터럽트 걸리는 순간에 실제거리를 저장해놓는다.  
  ui_state = 0;      // 0 으로 만들어둔다. 다음 타이머를 받기위해.

  AT91C_BASE_AIC->AIC_EOICR = 0;
  return;
}

void U_Timer_Init()
{
// 타이머 카운터 0 사용을 위한 PMC 활성화
     AT91C_BASE_PMC->PMC_PCER = 1<<AT91C_ID_TC0;
// 1.시작 : 타이머 클럭 비활성화 ------------------
// 타이머 클럭 비활성화(TC_CCR 설정)
  AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;    // 클럭이 꺼짐

// 2. 시작 : 타이머 인터럽트 비활성화 -------------
// 타이머 인터럽트 비활성화(TC_IDR 설정)
// 인터럽트 상태 정보 초기화(TC_SR 읽기)
  AT91C_BASE_TC0->TC_IDR = (AT91C_TC_COVFS) | (AT91C_TC_LOVRS) | (AT91C_TC_CPAS) | (AT91C_TC_CPBS) 
      | (AT91C_TC_CPCS) | (AT91C_TC_LDRAS) | (AT91C_TC_LDRBS) | (AT91C_TC_ETRGS);
  AT91C_BASE_TC0->TC_SR;  

// 분주비 128, 비교 방식 레지스터 설정(TC_CMR, DIV5_CLOCK, CPCTRG)
// MCKR divided by 8 => 58us(TC_RC 설정:353)
  AT91C_BASE_TC0->TC_CMR = (AT91C_TC_CLKS_TIMER_DIV2_CLOCK) | (AT91C_TC_CPCTRG);
  AT91C_BASE_TC0->TC_RC = 353;

// 타이머 카운터 0 인터럽트 비활성화(AIC_IDCR, TC0)
  AT91C_BASE_AIC->AIC_IDCR = 1<<AT91C_ID_TC0;


// 3. 시작 : 타이머 카운터 0 인터럽트 비활성화 ------


// 타이머 카운터 0 인터럽트 핸들러 등록(AIC_SVR[TC0], Timer_Handler)
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (volatile unsigned int )U_Timer_Handler;  


// 타이머 카운터 0 인터럽트 모드 설정(AIC_SMR[TC0], AIC_SRCTYPE_INT_HIGH_LEVEL, PRIOR_LOWEST)
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = ((AT91C_AIC_PRIOR_LOWEST) | (AT91C_AIC_SRCTYPE_POSITIVE_EDGE));

// 타이머 카운터 0 인터럽트 클리어(AIC_ICCR, TC0)
  AT91C_BASE_AIC->AIC_ICCR = 1<<AT91C_ID_TC0;


// TC_RC 값 비교 타이머 인터럽트 활성화(TC_IER, CPCS)
  AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
// 2. 끝 : 타이머 인터럽트 비활성화 ---------------


// 타이머 카운터 0 인터럽트 활성화(AIC_IECR, TC0)
  AT91C_BASE_AIC->AIC_IECR = 1<<AT91C_ID_TC0;


// 3. 끝 : 타이머 카운터 0 인터럽트 비활성화 -------

/*// 타이머 클럭 활성화(TC_CCR, CLKEN)
  AT91C_BASE_TC0->TC_CCR  = AT91C_TC_CLKEN;    // 클럭이 켜짐.
// 1. 끝 : 타이머 클럭 비활성화 ------------------

// 타이머 시작(TC_CCR, SWTRG)
  AT91C_BASE_TC0->TC_CCR  = AT91C_TC_SWTRG;*/

}

void U_Timer_Handler()
{
  AT91C_BASE_TC0->TC_SR;    // TC0_SR 에 가서 CPCS비트에 1이 들어가있는 상태면 인터럽트가 비활성화됨.
          // 그래서 1이 들어가있으면 안됨. TC0_SR 에 접근(읽으면) 0 으로 만듬
  ++ui_Tic;      // 여기선 데이터 단위 cm 이라고 보면됨.
  return;
}

void TRG_init()
{
  AT91C_BASE_PIOA->PIO_OER = 1<<TRG_PIN;
  AT91C_BASE_PIOA->PIO_PER = 1<<TRG_PIN;
  AT91C_BASE_PIOA->PIO_CODR = 1<<TRG_PIN;
  //AT91C_BASE_PIOA->PIO_PPUDR=1<<TRG_PIN;  //트러거핀 풀업저항을 오픈시켜 사용금지
  return;
}

void TRG_PULSE_Toggle()
{
  volatile unsigned int ui_Cnt;

  AT91C_BASE_PIOA->PIO_SODR = 1<<TRG_PIN;
  for(ui_Cnt=0;ui_Cnt < 100;++ui_Cnt);  // 48 cycle 이상 지연. 0.00001s 4000 cycle 이상 지연.
  AT91C_BASE_PIOA->PIO_CODR = 1<<TRG_PIN;

  return;
}