본문 바로가기

Enginius/Firmware

PIC32 - Input Capture


 Input Capture는 원래 다른 input간의 시간을 측정하는데 쓰인다.  예를 들면 주파수와 펄스 측정에 쓰인다.  하지만 그냥 edge에서 인터럽트를 발생하는 외부 인터럽트와 같이 쓸 수도있다.
 PIC32의 외부 인터럽트의 경우 외부 인터럽트는 edge-sensitive이기 때문에 모든 edge에서 인터럽트를 발생시킬 수 없다. NEC 방식을 사용하는 리모컨이나 incremental 인코더의 경우에는 모든 edge에서 인터럽트가 발생해야하기 때문에 Input Capture를 사용하면 쉽게 구현할 수 있다. 
 
 
Input Capture Control Registers

ICxCON(x는 숫자)
 bit31-16
    
Reserved
 bit15
     ON: Input Capture Module Enable bit
     1: Input Capture 를 사용한다.
     0: Input Capture 를 사용하지 않는다. 
bit14
     FRZ: Freeze in Debug Mode bit
     1: 디버그 모드에서 멈춘다.  
     0: 디버그 모드에서 멈추지 않는다.
 bit13
     SIDL: Stop in Idle Mode bit
     1: Idle 모드에서 멈춘다.
     0: Idle 모드에서 멈추지 않는다.
bit12-10
     Unimplemented
 bit9
     ICFEDGE: First Capture Edge Select bit (ICM<2:0> = 110 일때만)
     1: Rising Edge를 먼저 Capture
     0: Falling Edge를 먼저 Capture
bit8
     ICC32: 32-bit Capture Select bit
     1: 32-bit 타이머를 사용한다.
     0: 16-bit 타이머를 사용한다.
 bit7
     ICTMR: Timer Select bit (ICxC32 (ICxCON<8>이 1일땐 영향을 주지 않는다. )
     1: 타이머 2를 사용 
     0: 타이머 3을 사용
bit6-5
     ICI: Interrupt Control bits
     11: 4번째 이벤트에서 인터럽트
     10: 3번째 이벤트에서 인터럽트
     01: 2번째 이벤트에서 인터럽트
     00: 1번째 이벤트에서 인터럽트

 bit4
     ICOV: Input Capture Overflow Status bit(읽기 전용)
     1: 오버플로우가 생겼다.  
     0: 오버플로우가 생기지 않았다.
bit3
     ICBNE: Input Capture Buffer Not Empty Status bit(읽기 전용)
     1: 버퍼가 비지 않았다 - 최고 하나 이상의 capture value를 읽을 수 있다.  
     0: 버퍼가 비었다.  
 bit2-0
     ICM: Input Capture Mode Select bit
     111: 인터럽트만 한다. (Sleep이나 Idle 모드에서만 지원)
     110: Simple Capture Mode - 모든 엣지에서, 특정 엣지에서 먼저 그리고나선 모든 엣지에서
     101: 매 16번째 rising 엣지에서 이벤트
     100: 매 4번째 rising 엣지에서 이벤트
     011: 모든 rising edge에서 이벤트
     010: 모든 falling edge에서 이벤트
     001: Edge Detect mode -  모든 엣지
     000: Captue 하지 않는다. 



 아래의 소스는 두 개의 모터의 인코더 A상 B상을 각각 icap1,2,3,4에 물렸다. 
 PORT D의 8,9,10,11번 포트에 각각 연결시키고,
 인코더 값을 변화시키는 소스이다. incremental encoder를 사용하고, 정역 모두 잘 동작한다.
 



< pic32_icap.c >


#define RISING_EDGE		1
#define FALLING_EDGE		2
#define A_PULSE			1
#define B_PULSE			2
long long int right_motor_encoder = 0;
long long int left_motor_encoder = 0;
Uc Rencoder_change = A_PULSE, Lencoder_change = A_PULSE;;

void Init_icap()
{
	//Input capture 인터럽트 초기화


	//OpenTimer3(T3_ON | T3_PS_1_256, 0xffff);	//65535 * 256 = 16776960
	OpenTimer3(T3_ON | T3_IDLE_CON | T3_PS_1_1, 25000);	


	// Enable Input Capture Module 1 - RD8
	// - Capture Every edge
	// - Enable capture interrupts
	// - Use Timer 3 source
	// - Capture rising edge first
	OpenCapture1( IC_EVERY_EDGE | IC_INT_1CAPTURE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON );
	mIC1IntEnable(1);
	mIC1SetIntPriority(3);

	OpenCapture2( IC_EVERY_EDGE | IC_INT_1CAPTURE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON );
	mIC2IntEnable(1);
	mIC2SetIntPriority(3);

	OpenCapture3( IC_EVERY_EDGE | IC_INT_1CAPTURE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON );
	mIC3IntEnable(1);
	mIC3SetIntPriority(3);

	OpenCapture4( IC_EVERY_EDGE | IC_INT_1CAPTURE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON );
	mIC4IntEnable(1);
	mIC4SetIntPriority(3);

//	OpenCapture5( IC_EVERY_EDGE | IC_INT_1CAPTURE | IC_TIMER3_SRC | IC_FEDGE_RISE | IC_ON );
//	mIC5IntEnable(1);
//	mIC5SetIntPriority(3);
	
	mIC1ClearIntFlag();
	mIC2ClearIntFlag();
	mIC3ClearIntFlag();
	mIC4ClearIntFlag();	
//	mIC5ClearIntFlag();	
}

void __ISR(_INPUT_CAPTURE_1_VECTOR,ipl3) _ic1(void) 
{
	mIC1ClearIntFlag();
//	icap1cnt++;
	icap1 = PORTD & 0x100 ? RISING_EDGE : FALLING_EDGE;
	

	if(Rencoder_change == B_PULSE)
	{
		if(icap1 == RISING_EDGE)
		{
			if(icap2 == RISING_EDGE)
			{
				right_motor_encoder--;
			}
			else
			{
				right_motor_encoder++;
			}
		}
		else
		{
			if(icap2 == RISING_EDGE)
			{
				right_motor_encoder++;
			}
			else
			{
				right_motor_encoder--;
			}		
		}
	}

	Rencoder_change = A_PULSE;
}

//Input Capture 인터럽트 2
void __ISR(_INPUT_CAPTURE_2_VECTOR,ipl3) _ic2(void) 
{
	mIC2ClearIntFlag();
//	icap2cnt++;
	icap2 = PORTD & 0x200 ? RISING_EDGE : FALLING_EDGE;
	
	if(Rencoder_change == A_PULSE)
	{
		if(icap2 == RISING_EDGE)
		{
			if(icap1 == RISING_EDGE)
			{
				right_motor_encoder++;
			}
			else
			{
				right_motor_encoder--;
			}		
		}
		else
		{
			if(icap1 == RISING_EDGE)
			{
				right_motor_encoder--;
			}
			else
			{
				right_motor_encoder++;
			}		
		}	
	}
	
	Rencoder_change = B_PULSE;
}

//Input Capture 인터럽트 3
void __ISR(_INPUT_CAPTURE_3_VECTOR,ipl3) _ic3(void) 
{
	mIC3ClearIntFlag();
//	icap3cnt++;
	icap3 = PORTD & 0x400 ? RISING_EDGE : FALLING_EDGE;


	if(Lencoder_change == B_PULSE)
	{
		if(icap3 == RISING_EDGE)
		{
			if(icap4 == RISING_EDGE)
			{
				left_motor_encoder--;
			}
			else
			{
				left_motor_encoder++;
			}
		}
		else
		{
			if(icap4 == RISING_EDGE)
			{
				left_motor_encoder++;
			}
			else
			{
				left_motor_encoder--;
			}		
		}
	}

	Lencoder_change = A_PULSE;
}

//Input Capture 인터럽트 4
void __ISR(_INPUT_CAPTURE_4_VECTOR,ipl3) _ic4(void) 
{
	mIC4ClearIntFlag();
//	icap4cnt++;
	icap4 = PORTD & 0x800 ? RISING_EDGE : FALLING_EDGE;

	if(Lencoder_change == A_PULSE)
	{
		if(icap4 == RISING_EDGE)
		{
			if(icap3 == RISING_EDGE)
			{
				left_motor_encoder++;
			}
			else
			{
				left_motor_encoder--;
			}		
		}
		else
		{
			if(icap3 == RISING_EDGE)
			{
				left_motor_encoder--;
			}
			else
			{
				left_motor_encoder++;
			}		
		}	
	}
	
	Lencoder_change = B_PULSE;	
}

'Enginius > Firmware' 카테고리의 다른 글

PIC32 - SPI  (0) 2010.04.13
PIC32 - PWM  (0) 2010.02.19
PID 제어  (1) 2010.02.18
PIC32 - I2C  (0) 2010.02.17
PIC32 - GPIO  (0) 2010.02.17