ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 타이머 카운터
    Arduino/Atmel Studio 2021. 1. 7. 11:26

    타이머는 8비트 타이머와 16비트 타이머가 있다.

    8비트 타이머에 대해 알아보자.

     

    16Mhz = 16000000hz <- Atmega328p의 클락이다.
    동작을 맞춰주기 위해서 클락이 필요하다. 

    16Mhz / 1024 = 15625 <- 1초당 발생 펄스 수이다.  <- 초당 발생되는 클럭이라고 정의할 수 있다 
    1024는 분주율이다.
    분주비는 8, 64, 256, 1024를 선택할 수 있다. 그중에 1024를 많이 쓴다. 


    분주율을 사용하는 이유는 1초 / 16Mhz를 하면 
    하나의 펄스가 만들어지는데 걸리는 시간이 나노 세컨드 단위로 나온다.
    즉, 값이 너무 작아서 분주율을 적용한 것이다.

    그리고 8비트가 timer 발생 비트의 수라고 한다면, 8비트로 표현할 수 있는 가지 수는 2^8 = 256이다.

    16Mhz / 1024 / 256 = 약 61 <- 1초에 펄스를 61번 발생한다는 의미. 
    256을 61번 돌아야 15625hz가 된다. 
    61은 그 단위가 hz이다. ( 펄스가 초당 61번 발생. ) 

    2로 나누는 이유는 1초가 아닌 0.5초를 표현하기 위함.

    이에 대한 근사치로 61은 64로 둬서 이를 2로 나누면 32가 된다.


    그리고 1 / 61을 해서 하나의 펄스를 만드는데 걸리는 시간이다. ( 주기 )
    1 / 61 = 0.016초이다. 

     

    소스 내용

    더보기
    /*	
    	타이머 카운터를 이용한 LED의 ON/OFF
    */
    
    #define F_CPU 16000000UL	//	16MHz
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    int count = 0;	//	오버플로우 개수 카운터
    int state = 0;	//	LED 상태
    
    /*	Interrupt Service Routine	*/
    ISR(TIMER0_OVF_vect)	//	인터럽트는 오버플로우가 발생했을 때, 호출된다.
    {
    	/*	0.5초마다 LED의 ON/OFF를 제어 */
    	count += 1;
    	
    	//	8bit timer에 1024 분주율을 적용하면, 약 61hz가 된다.
    	//	대략 0.5초는 32hz가 발생
    	if ( count == 32 )	//	0.5초가 지나면
    	{
    		count = 0;
    		state = !state;
    		
    		if ( state )	PORTB = 0xff;
    		else            PORTB = 0x00;
    	}
    }
    
    int main(void)
    {
    	//	1. 디지털 12번핀을 출력으로 사용하고 타이머 카운터를 설정
    	//		D12번핀과 LED와 220옴 저항을 연결.
    	DDRB = 0x10;
    	PORTB = 0x00;
    	
    	//	2. TCCR설정(분주비 1024), TIMSK(인터럽트 허용)
    	//		TCCR0B |= ( 1 << CS02 ) | ( 1 << CS00 );
    	//		TOIE0는 레지스터(0-base 기준)의 1번째 비트를 의미
    	TCCR0B |= ( 1 << CS02 );
    	TCCR0B |= ( 1 << CS00 );
    	TIMSK0 |= ( 1 << TOIE0 );	//	해당 비트를 1로 설정해서 인터럽트 허용
    	sei();						//	전역 인터럽트 허용 
    	
    	while (1)
    	{
    		
    	}
    }

     

     

    16비트 타이머를 사용해서 0.5초마다 LED를 On/Off해보자.

    16비트에서는 8192가 16비트로 표현할 수 있는 가지 수이다.
    8비트 카운터를 사용하냐 16비트 카운터를 사용하냐에 따라 OCR값이 달라진다.
    16비트를 사용할 때는 최대 가지수 2^16 = 65536
    15625hz / 65536 = 0.249hz

    소스 내용

    더보기
    /*	
    	값이 같아질 때, 인터럽트가 발생한다.
    	인터럽트의 발생에 따라 5V가 인가되거나 0V가 인가된다.
    	아두이노의 9번핀에 LED를 연결한다.
    */
    
    #define F_CPU 16000000UL	//	16MHz
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    /*	Interrupt Service Routine	*/
    ISR(TIMER1_COMPA_vect)
    {
    	TCNT1 = 0;
    }
    
    int main(void)
    {
    	//	타이머1을 이용하여 비교하는 내용
    	//	1. 타이머1의 컨트롤 레지스터를 분주율 1024로 설정(101로 설정)
    	TCCR1B |=  ( 1 << CS10 );
    	TCCR1B |=  ( 1 << CS12 );
    	
    	//	2. 카운터랑 설정값을 비교하는 설정
    	OCR1A = 0x2000;	//	0x2000 = 0010 0000 0000 0000 = 1 * 2^13 = 8192
    					//	0x2000는 십진수로 8192이며, 이는 0.5초를 의미한다.
    						
    	TCCR1A |= ( 1 << COM1A0 );
    	
    	//	3. 출력핀을 설정
    	DDRB |= ( 1 << PORTB1 );	//	OCA1핀을 의미(아두이노의 D9번핀)
    	
    	//	4. 타이머 마스크 설정
    	TIMSK1 |= ( 1 << OCIE1A );	//	비교하여 인터럽트 발생
    	sei();						//	전역 인터럽트 허용
    	
    	while (1)
    	{
    		
    	}
    }

     

     

     

    서보 모터를 제어하는 내용을 알아보자.

    소스 내용

    더보기
    /*	
    	서보모터를 아두이노의 9번핀에 연결한다.
    */
    
    #define F_CPU 16000000UL	//	16MHz
    #include <avr/io.h>
    #include <util/delay.h>
    
    #define		PULSE_MIN		1000	//	최소 펄스 지점
    #define		PULSE_MAX		5000	//	최대 펄스 지점
    
    void InitTimer(void)
    {
    	TCCR1A |= ( 1 << WGM11 );
    	TCCR1B |= ( 1 << WGM12 ) | ( 1 << WGM13 );
    	TCCR1B |= ( 1 << CS11 );	//	분주율 8, 2Mhz
    	ICR1 = 40000;				//	20ms 주기
    	TCCR1A |= ( 1 << COM1A1 );	//	비 반전 모드
    	DDRB |= ( 1 << PB1 );		//	디지털 9번핀
    }
    
    int main(void)
    {
    	InitTimer();
    	int i, j;
    	
    	while (1)
    	{
    		//	서보 모터를 조금씩 움직이는 내용
    		for ( i = PULSE_MIN; i <= PULSE_MAX; i += 20 )
    		{
    			OCR1A = i;
    			_delay_ms(50);
    		}
    		for ( j = PULSE_MAX; j >= PULSE_MIN; j -= 20 )
    		{
    			OCR1A = j;
    			_delay_ms(50);
    		}
    	}
    }

     

    댓글

Designed by Tistory.